@whanext/core 0.14.3 → 0.16.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/CHANGELOG.md +36 -0
- package/README.md +53 -1
- package/dist/index.d.ts +30 -2
- package/dist/index.js +139 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## 0.16.0
|
|
5
|
+
|
|
6
|
+
### Adicionado
|
|
7
|
+
|
|
8
|
+
- Novo evento público `messageDeleted` em `app.on()` e `multi.on()`.
|
|
9
|
+
- Novo tipo `MessageDeleted`, com chave da mensagem, payload original quando disponível, autor da revogação e horário da exclusão.
|
|
10
|
+
- O provider Baileys passa a observar `messages.update` e reconhecer revogações sem expor tipos do Baileys à aplicação.
|
|
11
|
+
- Mensagens revogadas permanecem no cache recente, permitindo `app.message.repost()` e `app.media.download()` enquanto a entrada estiver disponível.
|
|
12
|
+
|
|
13
|
+
### Compatibilidade
|
|
14
|
+
|
|
15
|
+
- A mudança é aditiva para consumidores da API pública.
|
|
16
|
+
- Providers customizados passam a incluir `messageDeleted` em `ProviderEvents`.
|
|
17
|
+
- Quando a mensagem original já saiu do cache, o evento continua sendo emitido sem o campo `message`.
|
|
18
|
+
|
|
19
|
+
## 0.15.0
|
|
20
|
+
|
|
21
|
+
### Adicionado
|
|
22
|
+
|
|
23
|
+
- Suporte de alto nível a mensagens com botões interativos Native Flow.
|
|
24
|
+
- Botão `copy` para copiar códigos/textos usando `cta_copy`.
|
|
25
|
+
- Botão `link` para abrir URLs usando `cta_url`.
|
|
26
|
+
- Novo `ButtonsContent` no `MessageContent`, com `title`, `text`, `footer`, `mentions` e uma lista tipada de botões.
|
|
27
|
+
- Novo atalho `app.message.buttons(chatId, content)`; `ctx.reply({...})` e `app.message.reply(...)` também aceitam o novo conteúdo automaticamente.
|
|
28
|
+
- Exportação pública dos tipos `ButtonsContent`, `MessageButton`, `CopyCodeButton` e `LinkButton`.
|
|
29
|
+
|
|
30
|
+
### Provider Baileys
|
|
31
|
+
|
|
32
|
+
- Mensagens interativas são geradas como `InteractiveMessage`/`NativeFlowMessage` e enviadas por `relayMessage`, sem expor protobufs ao consumidor.
|
|
33
|
+
- Replies e menções são preservados no envio de botões.
|
|
34
|
+
- O relay inclui os nós de compatibilidade necessários para Native Flow em chats privados e grupos.
|
|
35
|
+
|
|
36
|
+
### Compatibilidade
|
|
37
|
+
|
|
38
|
+
- Nenhum contrato existente foi removido. Texto, mídia, reações, edição, delete e repost continuam usando as APIs anteriores.
|
|
39
|
+
|
|
4
40
|
## 0.14.3
|
|
5
41
|
|
|
6
42
|
- Corrige uma rejeição órfã durante o login quando a solicitação de código de pareamento falha ao mesmo tempo em que o socket é fechado.
|
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ await app.login({
|
|
|
37
37
|
- Prefixo global e comandos declarativos com argumentos tipados.
|
|
38
38
|
- Comandos exclusivos da conta conectada com `guards.owner()` ou `onlyOwner`.
|
|
39
39
|
- Usuários normalizados entre JID, LID e PN.
|
|
40
|
-
- Mensagens, replies, edição, exclusão, menções, mídias e download normalizado.
|
|
40
|
+
- Mensagens, replies, edição, exclusão, revogações, menções, mídias e download normalizado.
|
|
41
41
|
- Operações de grupos e membros com resultados idempotentes.
|
|
42
42
|
- Cache de metadados transparente e substituível.
|
|
43
43
|
- Mute permanente ou temporário com SQLite ou banco próprio.
|
|
@@ -159,6 +159,20 @@ if (principal?.isReady) {
|
|
|
159
159
|
|
|
160
160
|
`multi.commands.command()`, `use()`, `onError()` e `load()` aplicam a mesma configuração de comandos a todas as contas. Dentro de um comando, `ctx.account.id` informa qual conta recebeu e executou aquela interação. Eventos também podem ser observados em conjunto com `multi.on()`.
|
|
161
161
|
|
|
162
|
+
## Mensagens apagadas
|
|
163
|
+
|
|
164
|
+
Revogações recebidas pelo WhatsApp são expostas pelo evento `messageDeleted`. Quando a mensagem original ainda estiver no cache recente, o payload inclui `message`, que pode ser republicada ou usada para baixar a mídia pelas APIs existentes.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
app.on('messageDeleted', async ({ message, deletedByMe }) => {
|
|
168
|
+
if (!message || deletedByMe) return;
|
|
169
|
+
|
|
170
|
+
await app.message.repost(message, app.account.selfChatId);
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
O evento também informa `deletedById` quando o WhatsApp fornece a identidade responsável pela revogação.
|
|
175
|
+
|
|
162
176
|
## Logging
|
|
163
177
|
|
|
164
178
|
O nível padrão é `info`. Estão disponíveis `debug`, `info`, `warn`, `error` e `silent`.
|
|
@@ -340,6 +354,44 @@ await app.message.react(sent, '👏🏻');
|
|
|
340
354
|
await app.message.unreact(sent);
|
|
341
355
|
```
|
|
342
356
|
|
|
357
|
+
### Botões interativos
|
|
358
|
+
|
|
359
|
+
Por enquanto, a API pública suporta botões de **copiar código** e **abrir link**:
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
await app.message.buttons(chatId, {
|
|
363
|
+
title: 'Acesso',
|
|
364
|
+
text: 'Escolha uma ação:',
|
|
365
|
+
footer: 'WhaNext',
|
|
366
|
+
buttons: [
|
|
367
|
+
{
|
|
368
|
+
type: 'copy',
|
|
369
|
+
label: 'Copiar código',
|
|
370
|
+
code: 'ABC-123',
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
type: 'link',
|
|
374
|
+
label: 'Abrir painel',
|
|
375
|
+
url: 'https://example.com',
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Também funciona diretamente em replies de comandos, sem importar tipos do Baileys:
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
await ctx.reply({
|
|
385
|
+
text: 'Use uma das opções abaixo.',
|
|
386
|
+
buttons: [
|
|
387
|
+
{ type: 'copy', label: 'Copiar', code: 'ABC-123' },
|
|
388
|
+
{ type: 'link', label: 'Abrir site', url: 'https://example.com' },
|
|
389
|
+
],
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
`title`, `footer` e `mentions` são opcionais. Os botões podem ser combinados na mesma mensagem.
|
|
394
|
+
|
|
343
395
|
`delete()` aceita `Message`, `SentMessage` ou `MessageKey`.
|
|
344
396
|
|
|
345
397
|
`react()` aceita os mesmos tipos e adiciona uma reação à mensagem. `unreact()` remove a reação da conta conectada.
|
package/dist/index.d.ts
CHANGED
|
@@ -90,6 +90,13 @@ interface QuotedMessage {
|
|
|
90
90
|
contentKind?: MessageContentKind;
|
|
91
91
|
media?: MessageMedia;
|
|
92
92
|
}
|
|
93
|
+
interface MessageDeleted {
|
|
94
|
+
key: MessageKey;
|
|
95
|
+
message?: Message;
|
|
96
|
+
deletedByMe: boolean;
|
|
97
|
+
deletedById?: string;
|
|
98
|
+
deletedAt: Date;
|
|
99
|
+
}
|
|
93
100
|
interface Message {
|
|
94
101
|
id: string;
|
|
95
102
|
jid: string;
|
|
@@ -139,6 +146,24 @@ interface TextContent {
|
|
|
139
146
|
text: string;
|
|
140
147
|
mentions?: MentionTarget[];
|
|
141
148
|
}
|
|
149
|
+
interface LinkButton {
|
|
150
|
+
type: 'link';
|
|
151
|
+
label: string;
|
|
152
|
+
url: string;
|
|
153
|
+
}
|
|
154
|
+
interface CopyCodeButton {
|
|
155
|
+
type: 'copy';
|
|
156
|
+
label: string;
|
|
157
|
+
code: string;
|
|
158
|
+
}
|
|
159
|
+
type MessageButton = LinkButton | CopyCodeButton;
|
|
160
|
+
interface ButtonsContent {
|
|
161
|
+
text: string;
|
|
162
|
+
buttons: MessageButton[];
|
|
163
|
+
title?: string;
|
|
164
|
+
footer?: string;
|
|
165
|
+
mentions?: MentionTarget[];
|
|
166
|
+
}
|
|
142
167
|
interface ImageContent {
|
|
143
168
|
image: MediaSource;
|
|
144
169
|
caption?: string;
|
|
@@ -160,7 +185,7 @@ interface AudioContent {
|
|
|
160
185
|
interface StickerContent {
|
|
161
186
|
sticker: MediaSource;
|
|
162
187
|
}
|
|
163
|
-
type MessageContent = TextContent | ImageContent | VideoContent | AudioContent | StickerContent;
|
|
188
|
+
type MessageContent = TextContent | ButtonsContent | ImageContent | VideoContent | AudioContent | StickerContent;
|
|
164
189
|
|
|
165
190
|
type GroupAccess = 'open' | 'closed';
|
|
166
191
|
type GroupRole = 'member' | 'admin' | 'owner';
|
|
@@ -229,6 +254,7 @@ interface ConnectionUpdate {
|
|
|
229
254
|
}
|
|
230
255
|
interface ProviderEvents {
|
|
231
256
|
message: Message;
|
|
257
|
+
messageDeleted: MessageDeleted;
|
|
232
258
|
connection: ConnectionUpdate;
|
|
233
259
|
groupChanged: {
|
|
234
260
|
groupId: string;
|
|
@@ -458,6 +484,7 @@ declare class MessageService {
|
|
|
458
484
|
react(message: Message | SentMessage | MessageKey, emoji: string): Promise<SentMessage>;
|
|
459
485
|
unreact(message: Message | SentMessage | MessageKey): Promise<SentMessage>;
|
|
460
486
|
text(chatId: string, text: string, mentions?: MentionTarget[]): Promise<SentMessage>;
|
|
487
|
+
buttons(chatId: string, content: ButtonsContent): Promise<SentMessage>;
|
|
461
488
|
}
|
|
462
489
|
|
|
463
490
|
interface CommandCatalogView {
|
|
@@ -727,6 +754,7 @@ declare class AccountService {
|
|
|
727
754
|
|
|
728
755
|
interface AppEvents {
|
|
729
756
|
message: Message;
|
|
757
|
+
messageDeleted: MessageDeleted;
|
|
730
758
|
connection: ConnectionUpdate;
|
|
731
759
|
error: WhaNextError;
|
|
732
760
|
mute: MuteEnforcement;
|
|
@@ -886,4 +914,4 @@ declare class SqliteMuteStore implements MuteStore {
|
|
|
886
914
|
close(): void;
|
|
887
915
|
}
|
|
888
916
|
|
|
889
|
-
export { AccountService, type AddMuteOptions, type AddMuteResult, type AppEvents, type AppHealth, type AppHealthStatus, ArgsParser, type AudioContent, type BooleanOption, Browser, type CacheOptions, type CacheStore, type CallEvent, type CallStatus, type ChangeResult, type CommandAccountContext, type CommandCatalogOptions, type CommandCatalogView, type CommandChatContext, type CommandConcurrency, type CommandContext, type CommandCooldown, type CommandDefinition, type CommandErrorHandler, type CommandGroupContext, type CommandGroupDefinition, type CommandGuard, type CommandHelpOptions, type CommandHooks, type CommandLocalization, type CommandMetadata, type CommandMiddleware, type CommandOptionDefinition, type CommandOptionSchema, type CommandOptionValue, type CommandOptionValues, type CommandRegistrar, CommandRouter, type CommandRuntimeServices, type CommandScope, type ConcurrencyStrategy, type ConnectionState, type ConnectionUpdate, type CreateMultiOptions, type CreateOptions, DeferredReply, type DownloadedMedia, type DurationOption, type EnumOption, type ExecutableCommandDefinition, type GroupAccess, type GroupAddressingMode, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, type GuardResult, type ImageContent, type InviteResult, type LoadCommandsOptions, type LoadCommandsResult, type LoadedCommand, type LogContext, type LogEntry, type LogFormat, type LogLevel, type LogWriter, Logger, type LoggerConfig, type LoggerOptions, type LoginOptions, type MediaKind, type MediaSource, type MemberActionState, MemoryCache, type MemoryCacheStats, type MentionTarget, type Message, type MessageContent, type MessageContentKind, type MessageKey, type MessageMedia, type MultiAccountOptions, type MultiAppEvent, type MultiAppHealth, MultiCommandRouter, type MultiLoadCommandsResult, type MultiLoginOptions, type MuteChangeResult, type MuteEnforcement, type MuteOptions, type MuteRecord, MuteService, type MuteStore, type NumberOption, ParsedCommandOptions, type ParticipantUpdateResult, type PresenceState, type QuotedMessage, type ReconnectOptions, type RegisteredCommand, type RemoveMuteResult, type ReplyOptions, type RepostMessageOptions, type RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, WhaNextMultiApp, type WhatsAppProvider, create, createMulti, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
|
|
917
|
+
export { AccountService, type AddMuteOptions, type AddMuteResult, type AppEvents, type AppHealth, type AppHealthStatus, ArgsParser, type AudioContent, type BooleanOption, Browser, type ButtonsContent, type CacheOptions, type CacheStore, type CallEvent, type CallStatus, type ChangeResult, type CommandAccountContext, type CommandCatalogOptions, type CommandCatalogView, type CommandChatContext, type CommandConcurrency, type CommandContext, type CommandCooldown, type CommandDefinition, type CommandErrorHandler, type CommandGroupContext, type CommandGroupDefinition, type CommandGuard, type CommandHelpOptions, type CommandHooks, type CommandLocalization, type CommandMetadata, type CommandMiddleware, type CommandOptionDefinition, type CommandOptionSchema, type CommandOptionValue, type CommandOptionValues, type CommandRegistrar, CommandRouter, type CommandRuntimeServices, type CommandScope, type ConcurrencyStrategy, type ConnectionState, type ConnectionUpdate, type CopyCodeButton, type CreateMultiOptions, type CreateOptions, DeferredReply, type DownloadedMedia, type DurationOption, type EnumOption, type ExecutableCommandDefinition, type GroupAccess, type GroupAddressingMode, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, type GuardResult, type ImageContent, type InviteResult, type LinkButton, type LoadCommandsOptions, type LoadCommandsResult, type LoadedCommand, type LogContext, type LogEntry, type LogFormat, type LogLevel, type LogWriter, Logger, type LoggerConfig, type LoggerOptions, type LoginOptions, type MediaKind, type MediaSource, type MemberActionState, MemoryCache, type MemoryCacheStats, type MentionTarget, type Message, type MessageButton, type MessageContent, type MessageContentKind, type MessageDeleted, type MessageKey, type MessageMedia, type MultiAccountOptions, type MultiAppEvent, type MultiAppHealth, MultiCommandRouter, type MultiLoadCommandsResult, type MultiLoginOptions, type MuteChangeResult, type MuteEnforcement, type MuteOptions, type MuteRecord, MuteService, type MuteStore, type NumberOption, ParsedCommandOptions, type ParticipantUpdateResult, type PresenceState, type QuotedMessage, type ReconnectOptions, type RegisteredCommand, type RemoveMuteResult, type ReplyOptions, type RepostMessageOptions, type RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, WhaNextMultiApp, type WhatsAppProvider, create, createMulti, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
|
package/dist/index.js
CHANGED
|
@@ -2036,6 +2036,9 @@ var MessageService = class {
|
|
|
2036
2036
|
}
|
|
2037
2037
|
return this.send(chatId, content);
|
|
2038
2038
|
}
|
|
2039
|
+
buttons(chatId, content) {
|
|
2040
|
+
return this.send(chatId, content);
|
|
2041
|
+
}
|
|
2039
2042
|
};
|
|
2040
2043
|
|
|
2041
2044
|
// src/app/whanext-app.ts
|
|
@@ -2194,6 +2197,15 @@ var WhaNextApp = class {
|
|
|
2194
2197
|
});
|
|
2195
2198
|
await this.#events.emit("call", call);
|
|
2196
2199
|
});
|
|
2200
|
+
this.#provider.on("messageDeleted", async (deletion) => {
|
|
2201
|
+
this.logger.debug("Message deleted", {
|
|
2202
|
+
chatId: deletion.key.chatId,
|
|
2203
|
+
messageId: deletion.key.id,
|
|
2204
|
+
deletedByMe: deletion.deletedByMe,
|
|
2205
|
+
cached: deletion.message !== void 0
|
|
2206
|
+
});
|
|
2207
|
+
await this.#events.emit("messageDeleted", deletion);
|
|
2208
|
+
});
|
|
2197
2209
|
this.#provider.on("message", async (message) => {
|
|
2198
2210
|
try {
|
|
2199
2211
|
const enforcement = await this.mute.enforce(message);
|
|
@@ -2281,6 +2293,8 @@ import {
|
|
|
2281
2293
|
Browsers,
|
|
2282
2294
|
DisconnectReason,
|
|
2283
2295
|
downloadMediaMessage,
|
|
2296
|
+
generateWAMessageFromContent,
|
|
2297
|
+
isJidGroup,
|
|
2284
2298
|
makeWASocket,
|
|
2285
2299
|
proto,
|
|
2286
2300
|
useMultiFileAuthState
|
|
@@ -2685,6 +2699,9 @@ var BaileysProvider = class {
|
|
|
2685
2699
|
}
|
|
2686
2700
|
}
|
|
2687
2701
|
async sendMessage(chatId, content, replyTo) {
|
|
2702
|
+
if ("buttons" in content) {
|
|
2703
|
+
return this.#sendButtons(chatId, content, replyTo);
|
|
2704
|
+
}
|
|
2688
2705
|
const socket = this.#requireSocket();
|
|
2689
2706
|
const options = replyTo ? {
|
|
2690
2707
|
quoted: {
|
|
@@ -2840,6 +2857,23 @@ var BaileysProvider = class {
|
|
|
2840
2857
|
if (message) void this.#events.emit("message", message);
|
|
2841
2858
|
}
|
|
2842
2859
|
});
|
|
2860
|
+
socket.ev.on("messages.update", (updates) => {
|
|
2861
|
+
for (const { key, update } of updates) {
|
|
2862
|
+
if (update.message !== null || !key.id || !key.remoteJid) continue;
|
|
2863
|
+
const stored = this.#messageStore.get(this.#messageStoreKey(key));
|
|
2864
|
+
const message = stored ? normalizeBaileysMessage(stored) : void 0;
|
|
2865
|
+
const deletionKey = update.key;
|
|
2866
|
+
const deletedByMe = deletionKey?.fromMe === true;
|
|
2867
|
+
const deletedById = deletionKey?.participant ?? deletionKey?.participantAlt ?? (deletedByMe ? this.#socket?.user?.id : deletionKey?.remoteJid ?? void 0);
|
|
2868
|
+
void this.#events.emit("messageDeleted", {
|
|
2869
|
+
key: message?.keys ?? normalizeKey(key),
|
|
2870
|
+
...message ? { message } : {},
|
|
2871
|
+
deletedByMe,
|
|
2872
|
+
...deletedById ? { deletedById } : {},
|
|
2873
|
+
deletedAt: /* @__PURE__ */ new Date()
|
|
2874
|
+
});
|
|
2875
|
+
}
|
|
2876
|
+
});
|
|
2843
2877
|
socket.ev.on("groups.update", (groups) => {
|
|
2844
2878
|
for (const group of groups) {
|
|
2845
2879
|
if (group.id) {
|
|
@@ -2928,6 +2962,111 @@ var BaileysProvider = class {
|
|
|
2928
2962
|
}
|
|
2929
2963
|
return this.#socket;
|
|
2930
2964
|
}
|
|
2965
|
+
async #sendButtons(chatId, content, replyTo) {
|
|
2966
|
+
const socket = this.#requireSocket();
|
|
2967
|
+
const userJid = socket.user?.id;
|
|
2968
|
+
if (!userJid) {
|
|
2969
|
+
throw new WhaNextError(
|
|
2970
|
+
"PROVIDER_ERROR",
|
|
2971
|
+
"WhatsApp did not expose the current account identity for the interactive message."
|
|
2972
|
+
);
|
|
2973
|
+
}
|
|
2974
|
+
const interactiveMessage = proto.Message.InteractiveMessage.create({
|
|
2975
|
+
...content.title !== void 0 ? {
|
|
2976
|
+
header: {
|
|
2977
|
+
title: content.title,
|
|
2978
|
+
hasMediaAttachment: false
|
|
2979
|
+
}
|
|
2980
|
+
} : {},
|
|
2981
|
+
body: { text: content.text },
|
|
2982
|
+
...content.footer !== void 0 ? { footer: { text: content.footer } } : {},
|
|
2983
|
+
...content.mentions && content.mentions.length > 0 ? {
|
|
2984
|
+
contextInfo: {
|
|
2985
|
+
mentionedJid: this.#mentions(content.mentions)
|
|
2986
|
+
}
|
|
2987
|
+
} : {},
|
|
2988
|
+
nativeFlowMessage: {
|
|
2989
|
+
buttons: content.buttons.map((button) => {
|
|
2990
|
+
if (button.type === "copy") {
|
|
2991
|
+
return {
|
|
2992
|
+
name: "cta_copy",
|
|
2993
|
+
buttonParamsJson: JSON.stringify({
|
|
2994
|
+
display_text: button.label,
|
|
2995
|
+
copy_code: button.code
|
|
2996
|
+
})
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
return {
|
|
3000
|
+
name: "cta_url",
|
|
3001
|
+
buttonParamsJson: JSON.stringify({
|
|
3002
|
+
display_text: button.label,
|
|
3003
|
+
url: button.url,
|
|
3004
|
+
merchant_url: button.url
|
|
3005
|
+
})
|
|
3006
|
+
};
|
|
3007
|
+
}),
|
|
3008
|
+
messageParamsJson: "{}",
|
|
3009
|
+
messageVersion: 1
|
|
3010
|
+
}
|
|
3011
|
+
});
|
|
3012
|
+
const quoted = replyTo ? {
|
|
3013
|
+
key: this.#toWaKey(replyTo),
|
|
3014
|
+
message: { conversation: "" }
|
|
3015
|
+
} : void 0;
|
|
3016
|
+
const generated = generateWAMessageFromContent(
|
|
3017
|
+
chatId,
|
|
3018
|
+
{ interactiveMessage },
|
|
3019
|
+
{
|
|
3020
|
+
userJid,
|
|
3021
|
+
...quoted ? { quoted } : {}
|
|
3022
|
+
}
|
|
3023
|
+
);
|
|
3024
|
+
const messageId = generated.key.id;
|
|
3025
|
+
if (!generated.message || !messageId) {
|
|
3026
|
+
throw new WhaNextError(
|
|
3027
|
+
"PROVIDER_ERROR",
|
|
3028
|
+
"WhatsApp could not generate the interactive message."
|
|
3029
|
+
);
|
|
3030
|
+
}
|
|
3031
|
+
await socket.relayMessage(chatId, generated.message, {
|
|
3032
|
+
messageId,
|
|
3033
|
+
additionalNodes: this.#interactiveRelayNodes(chatId)
|
|
3034
|
+
});
|
|
3035
|
+
return this.#sent(generated);
|
|
3036
|
+
}
|
|
3037
|
+
#interactiveRelayNodes(chatId) {
|
|
3038
|
+
const bizNode = {
|
|
3039
|
+
tag: "biz",
|
|
3040
|
+
attrs: {
|
|
3041
|
+
actual_actors: "2",
|
|
3042
|
+
host_storage: "2",
|
|
3043
|
+
privacy_mode_ts: (Math.floor(Date.now() / 1e3) - 77980457).toString()
|
|
3044
|
+
},
|
|
3045
|
+
content: [
|
|
3046
|
+
{
|
|
3047
|
+
tag: "interactive",
|
|
3048
|
+
attrs: { type: "native_flow", v: "1" },
|
|
3049
|
+
content: [
|
|
3050
|
+
{
|
|
3051
|
+
tag: "native_flow",
|
|
3052
|
+
attrs: { v: "9", name: "mixed" }
|
|
3053
|
+
}
|
|
3054
|
+
]
|
|
3055
|
+
},
|
|
3056
|
+
{
|
|
3057
|
+
tag: "quality_control",
|
|
3058
|
+
attrs: { source_type: "third_party" }
|
|
3059
|
+
}
|
|
3060
|
+
]
|
|
3061
|
+
};
|
|
3062
|
+
if (isJidGroup(chatId)) {
|
|
3063
|
+
return [bizNode];
|
|
3064
|
+
}
|
|
3065
|
+
return [
|
|
3066
|
+
{ tag: "bot", attrs: { biz_bot: "1" } },
|
|
3067
|
+
bizNode
|
|
3068
|
+
];
|
|
3069
|
+
}
|
|
2931
3070
|
#toContent(content) {
|
|
2932
3071
|
if ("text" in content) {
|
|
2933
3072
|
return {
|