@whanext/core 0.14.2 → 0.15.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 +27 -0
- package/README.md +38 -0
- package/dist/index.d.ts +21 -2
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## 0.15.0
|
|
5
|
+
|
|
6
|
+
### Adicionado
|
|
7
|
+
|
|
8
|
+
- Suporte de alto nível a mensagens com botões interativos Native Flow.
|
|
9
|
+
- Botão `copy` para copiar códigos/textos usando `cta_copy`.
|
|
10
|
+
- Botão `link` para abrir URLs usando `cta_url`.
|
|
11
|
+
- Novo `ButtonsContent` no `MessageContent`, com `title`, `text`, `footer`, `mentions` e uma lista tipada de botões.
|
|
12
|
+
- Novo atalho `app.message.buttons(chatId, content)`; `ctx.reply({...})` e `app.message.reply(...)` também aceitam o novo conteúdo automaticamente.
|
|
13
|
+
- Exportação pública dos tipos `ButtonsContent`, `MessageButton`, `CopyCodeButton` e `LinkButton`.
|
|
14
|
+
|
|
15
|
+
### Provider Baileys
|
|
16
|
+
|
|
17
|
+
- Mensagens interativas são geradas como `InteractiveMessage`/`NativeFlowMessage` e enviadas por `relayMessage`, sem expor protobufs ao consumidor.
|
|
18
|
+
- Replies e menções são preservados no envio de botões.
|
|
19
|
+
- O relay inclui os nós de compatibilidade necessários para Native Flow em chats privados e grupos.
|
|
20
|
+
|
|
21
|
+
### Compatibilidade
|
|
22
|
+
|
|
23
|
+
- Nenhum contrato existente foi removido. Texto, mídia, reações, edição, delete e repost continuam usando as APIs anteriores.
|
|
24
|
+
|
|
25
|
+
## 0.14.3
|
|
26
|
+
|
|
27
|
+
- 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.
|
|
28
|
+
- Mantém o erro principal de autenticação sem gerar `unhandledRejection` paralelo no processo.
|
|
29
|
+
|
|
3
30
|
## 0.14.2
|
|
4
31
|
|
|
5
32
|
### Corrigido
|
package/README.md
CHANGED
|
@@ -340,6 +340,44 @@ await app.message.react(sent, '👏🏻');
|
|
|
340
340
|
await app.message.unreact(sent);
|
|
341
341
|
```
|
|
342
342
|
|
|
343
|
+
### Botões interativos
|
|
344
|
+
|
|
345
|
+
Por enquanto, a API pública suporta botões de **copiar código** e **abrir link**:
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
await app.message.buttons(chatId, {
|
|
349
|
+
title: 'Acesso',
|
|
350
|
+
text: 'Escolha uma ação:',
|
|
351
|
+
footer: 'WhaNext',
|
|
352
|
+
buttons: [
|
|
353
|
+
{
|
|
354
|
+
type: 'copy',
|
|
355
|
+
label: 'Copiar código',
|
|
356
|
+
code: 'ABC-123',
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
type: 'link',
|
|
360
|
+
label: 'Abrir painel',
|
|
361
|
+
url: 'https://example.com',
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Também funciona diretamente em replies de comandos, sem importar tipos do Baileys:
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
await ctx.reply({
|
|
371
|
+
text: 'Use uma das opções abaixo.',
|
|
372
|
+
buttons: [
|
|
373
|
+
{ type: 'copy', label: 'Copiar', code: 'ABC-123' },
|
|
374
|
+
{ type: 'link', label: 'Abrir site', url: 'https://example.com' },
|
|
375
|
+
],
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
`title`, `footer` e `mentions` são opcionais. Os botões podem ser combinados na mesma mensagem.
|
|
380
|
+
|
|
343
381
|
`delete()` aceita `Message`, `SentMessage` ou `MessageKey`.
|
|
344
382
|
|
|
345
383
|
`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
|
@@ -139,6 +139,24 @@ interface TextContent {
|
|
|
139
139
|
text: string;
|
|
140
140
|
mentions?: MentionTarget[];
|
|
141
141
|
}
|
|
142
|
+
interface LinkButton {
|
|
143
|
+
type: 'link';
|
|
144
|
+
label: string;
|
|
145
|
+
url: string;
|
|
146
|
+
}
|
|
147
|
+
interface CopyCodeButton {
|
|
148
|
+
type: 'copy';
|
|
149
|
+
label: string;
|
|
150
|
+
code: string;
|
|
151
|
+
}
|
|
152
|
+
type MessageButton = LinkButton | CopyCodeButton;
|
|
153
|
+
interface ButtonsContent {
|
|
154
|
+
text: string;
|
|
155
|
+
buttons: MessageButton[];
|
|
156
|
+
title?: string;
|
|
157
|
+
footer?: string;
|
|
158
|
+
mentions?: MentionTarget[];
|
|
159
|
+
}
|
|
142
160
|
interface ImageContent {
|
|
143
161
|
image: MediaSource;
|
|
144
162
|
caption?: string;
|
|
@@ -160,7 +178,7 @@ interface AudioContent {
|
|
|
160
178
|
interface StickerContent {
|
|
161
179
|
sticker: MediaSource;
|
|
162
180
|
}
|
|
163
|
-
type MessageContent = TextContent | ImageContent | VideoContent | AudioContent | StickerContent;
|
|
181
|
+
type MessageContent = TextContent | ButtonsContent | ImageContent | VideoContent | AudioContent | StickerContent;
|
|
164
182
|
|
|
165
183
|
type GroupAccess = 'open' | 'closed';
|
|
166
184
|
type GroupRole = 'member' | 'admin' | 'owner';
|
|
@@ -458,6 +476,7 @@ declare class MessageService {
|
|
|
458
476
|
react(message: Message | SentMessage | MessageKey, emoji: string): Promise<SentMessage>;
|
|
459
477
|
unreact(message: Message | SentMessage | MessageKey): Promise<SentMessage>;
|
|
460
478
|
text(chatId: string, text: string, mentions?: MentionTarget[]): Promise<SentMessage>;
|
|
479
|
+
buttons(chatId: string, content: ButtonsContent): Promise<SentMessage>;
|
|
461
480
|
}
|
|
462
481
|
|
|
463
482
|
interface CommandCatalogView {
|
|
@@ -886,4 +905,4 @@ declare class SqliteMuteStore implements MuteStore {
|
|
|
886
905
|
close(): void;
|
|
887
906
|
}
|
|
888
907
|
|
|
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 };
|
|
908
|
+
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 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
|
|
@@ -2149,6 +2152,7 @@ var WhaNextApp = class {
|
|
|
2149
2152
|
);
|
|
2150
2153
|
}, options.timeoutMs ?? 3e5);
|
|
2151
2154
|
});
|
|
2155
|
+
void connected.catch(() => void 0);
|
|
2152
2156
|
try {
|
|
2153
2157
|
await this.#provider.connect();
|
|
2154
2158
|
if (this.#phone) {
|
|
@@ -2280,6 +2284,8 @@ import {
|
|
|
2280
2284
|
Browsers,
|
|
2281
2285
|
DisconnectReason,
|
|
2282
2286
|
downloadMediaMessage,
|
|
2287
|
+
generateWAMessageFromContent,
|
|
2288
|
+
isJidGroup,
|
|
2283
2289
|
makeWASocket,
|
|
2284
2290
|
proto,
|
|
2285
2291
|
useMultiFileAuthState
|
|
@@ -2684,6 +2690,9 @@ var BaileysProvider = class {
|
|
|
2684
2690
|
}
|
|
2685
2691
|
}
|
|
2686
2692
|
async sendMessage(chatId, content, replyTo) {
|
|
2693
|
+
if ("buttons" in content) {
|
|
2694
|
+
return this.#sendButtons(chatId, content, replyTo);
|
|
2695
|
+
}
|
|
2687
2696
|
const socket = this.#requireSocket();
|
|
2688
2697
|
const options = replyTo ? {
|
|
2689
2698
|
quoted: {
|
|
@@ -2927,6 +2936,111 @@ var BaileysProvider = class {
|
|
|
2927
2936
|
}
|
|
2928
2937
|
return this.#socket;
|
|
2929
2938
|
}
|
|
2939
|
+
async #sendButtons(chatId, content, replyTo) {
|
|
2940
|
+
const socket = this.#requireSocket();
|
|
2941
|
+
const userJid = socket.user?.id;
|
|
2942
|
+
if (!userJid) {
|
|
2943
|
+
throw new WhaNextError(
|
|
2944
|
+
"PROVIDER_ERROR",
|
|
2945
|
+
"WhatsApp did not expose the current account identity for the interactive message."
|
|
2946
|
+
);
|
|
2947
|
+
}
|
|
2948
|
+
const interactiveMessage = proto.Message.InteractiveMessage.create({
|
|
2949
|
+
...content.title !== void 0 ? {
|
|
2950
|
+
header: {
|
|
2951
|
+
title: content.title,
|
|
2952
|
+
hasMediaAttachment: false
|
|
2953
|
+
}
|
|
2954
|
+
} : {},
|
|
2955
|
+
body: { text: content.text },
|
|
2956
|
+
...content.footer !== void 0 ? { footer: { text: content.footer } } : {},
|
|
2957
|
+
...content.mentions && content.mentions.length > 0 ? {
|
|
2958
|
+
contextInfo: {
|
|
2959
|
+
mentionedJid: this.#mentions(content.mentions)
|
|
2960
|
+
}
|
|
2961
|
+
} : {},
|
|
2962
|
+
nativeFlowMessage: {
|
|
2963
|
+
buttons: content.buttons.map((button) => {
|
|
2964
|
+
if (button.type === "copy") {
|
|
2965
|
+
return {
|
|
2966
|
+
name: "cta_copy",
|
|
2967
|
+
buttonParamsJson: JSON.stringify({
|
|
2968
|
+
display_text: button.label,
|
|
2969
|
+
copy_code: button.code
|
|
2970
|
+
})
|
|
2971
|
+
};
|
|
2972
|
+
}
|
|
2973
|
+
return {
|
|
2974
|
+
name: "cta_url",
|
|
2975
|
+
buttonParamsJson: JSON.stringify({
|
|
2976
|
+
display_text: button.label,
|
|
2977
|
+
url: button.url,
|
|
2978
|
+
merchant_url: button.url
|
|
2979
|
+
})
|
|
2980
|
+
};
|
|
2981
|
+
}),
|
|
2982
|
+
messageParamsJson: "{}",
|
|
2983
|
+
messageVersion: 1
|
|
2984
|
+
}
|
|
2985
|
+
});
|
|
2986
|
+
const quoted = replyTo ? {
|
|
2987
|
+
key: this.#toWaKey(replyTo),
|
|
2988
|
+
message: { conversation: "" }
|
|
2989
|
+
} : void 0;
|
|
2990
|
+
const generated = generateWAMessageFromContent(
|
|
2991
|
+
chatId,
|
|
2992
|
+
{ interactiveMessage },
|
|
2993
|
+
{
|
|
2994
|
+
userJid,
|
|
2995
|
+
...quoted ? { quoted } : {}
|
|
2996
|
+
}
|
|
2997
|
+
);
|
|
2998
|
+
const messageId = generated.key.id;
|
|
2999
|
+
if (!generated.message || !messageId) {
|
|
3000
|
+
throw new WhaNextError(
|
|
3001
|
+
"PROVIDER_ERROR",
|
|
3002
|
+
"WhatsApp could not generate the interactive message."
|
|
3003
|
+
);
|
|
3004
|
+
}
|
|
3005
|
+
await socket.relayMessage(chatId, generated.message, {
|
|
3006
|
+
messageId,
|
|
3007
|
+
additionalNodes: this.#interactiveRelayNodes(chatId)
|
|
3008
|
+
});
|
|
3009
|
+
return this.#sent(generated);
|
|
3010
|
+
}
|
|
3011
|
+
#interactiveRelayNodes(chatId) {
|
|
3012
|
+
const bizNode = {
|
|
3013
|
+
tag: "biz",
|
|
3014
|
+
attrs: {
|
|
3015
|
+
actual_actors: "2",
|
|
3016
|
+
host_storage: "2",
|
|
3017
|
+
privacy_mode_ts: (Math.floor(Date.now() / 1e3) - 77980457).toString()
|
|
3018
|
+
},
|
|
3019
|
+
content: [
|
|
3020
|
+
{
|
|
3021
|
+
tag: "interactive",
|
|
3022
|
+
attrs: { type: "native_flow", v: "1" },
|
|
3023
|
+
content: [
|
|
3024
|
+
{
|
|
3025
|
+
tag: "native_flow",
|
|
3026
|
+
attrs: { v: "9", name: "mixed" }
|
|
3027
|
+
}
|
|
3028
|
+
]
|
|
3029
|
+
},
|
|
3030
|
+
{
|
|
3031
|
+
tag: "quality_control",
|
|
3032
|
+
attrs: { source_type: "third_party" }
|
|
3033
|
+
}
|
|
3034
|
+
]
|
|
3035
|
+
};
|
|
3036
|
+
if (isJidGroup(chatId)) {
|
|
3037
|
+
return [bizNode];
|
|
3038
|
+
}
|
|
3039
|
+
return [
|
|
3040
|
+
{ tag: "bot", attrs: { biz_bot: "1" } },
|
|
3041
|
+
bizNode
|
|
3042
|
+
];
|
|
3043
|
+
}
|
|
2930
3044
|
#toContent(content) {
|
|
2931
3045
|
if ("text" in content) {
|
|
2932
3046
|
return {
|