@whanext/core 0.10.0 → 0.12.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 +25 -0
- package/README.md +62 -44
- package/dist/index.d.ts +42 -19
- package/dist/index.js +128 -76
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## 0.12.0 - Message content classification
|
|
5
|
+
|
|
6
|
+
### Adicionado
|
|
7
|
+
|
|
8
|
+
- `Message.contentKind` para classificar o payload recebido sem expor tipos do Baileys.
|
|
9
|
+
- Novo tipo público `MessageContentKind`.
|
|
10
|
+
- Classificação nativa para texto, imagem, vídeo, áudio, documento, sticker, localização, contato, enquete e catálogo/produto.
|
|
11
|
+
- `unknown` como fallback para formatos ainda não normalizados pela biblioteca.
|
|
12
|
+
|
|
13
|
+
### Compatibilidade
|
|
14
|
+
|
|
15
|
+
- `contentKind` é opcional no contrato público para manter compatibilidade com providers customizados e objetos `Message` criados por aplicações existentes.
|
|
16
|
+
- O `BaileysProvider` oficial sempre preenche `contentKind` nas mensagens recebidas.
|
|
17
|
+
- `message.media.kind` continua sendo a API indicada para mídia baixável; `contentKind` complementa essa API com tipos não-mídia.
|
|
18
|
+
|
|
19
|
+
## 0.11.0 - Command discovery
|
|
20
|
+
|
|
21
|
+
- `CommandRouter.load()` carrega diretórios de comandos diretamente pelo router.
|
|
22
|
+
- `loadCommands()` agora aceita `URL` além de caminhos em string.
|
|
23
|
+
- Autoload reconhece `.ts`, `.mts` e `.cts` por padrão, além de JavaScript.
|
|
24
|
+
- `CommandContext` agora expõe `ctx.commands` (catálogo somente-leitura) e `ctx.prefix`.
|
|
25
|
+
- Menus e comandos de ajuda podem consultar o catálogo sem factory ou referência global ao app.
|
|
26
|
+
- Mantém compatibilidade com `defineCommand`, `defineCommands`, `defineSubcommand` e `defineCommandGroup`.
|
|
27
|
+
|
|
3
28
|
Todas as mudanças relevantes do projeto serão registradas neste arquivo.
|
|
4
29
|
|
|
5
30
|
## 0.10.0
|
package/README.md
CHANGED
|
@@ -220,6 +220,22 @@ if (app.isReady) {
|
|
|
220
220
|
|
|
221
221
|
Toda mensagem possui `message.sender: User`. Menções ficam em `message.mentionedUsers`, e o remetente de um reply em `message.quoted?.sender`.
|
|
222
222
|
|
|
223
|
+
O provider Baileys também classifica o payload em `message.contentKind`, sem exigir acesso aos tipos internos do Baileys ou download da mídia:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
app.on('message', async (message) => {
|
|
227
|
+
if (message.contentKind === 'location') {
|
|
228
|
+
console.log('Localização recebida');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (message.contentKind === 'poll') {
|
|
232
|
+
console.log('Enquete recebida');
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Os valores disponíveis são `text`, `image`, `video`, `audio`, `document`, `sticker`, `location`, `contact`, `poll`, `catalog` e `unknown`. Para mídia baixável, continue usando `message.media.kind`.
|
|
238
|
+
|
|
223
239
|
```ts
|
|
224
240
|
app.on('message', async (message) => {
|
|
225
241
|
console.log(message.sender.id);
|
|
@@ -566,81 +582,83 @@ Restrições disponíveis:
|
|
|
566
582
|
|
|
567
583
|
`ArgsParser` possui `string`, `number`, `boolean`, `enum`, `user`, `duration`, `peek`, `skip` e `rest`. `args.user()` retorna `User`, nunca uma string crua.
|
|
568
584
|
|
|
569
|
-
###
|
|
585
|
+
### Descoberta automática de comandos
|
|
570
586
|
|
|
571
|
-
|
|
587
|
+
A forma recomendada agora é deixar cada arquivo de comando autossuficiente e pedir ao próprio router para descobrir a árvore inteira. Não é necessário manter `index.ts` por pasta nem um arquivo central de imports:
|
|
572
588
|
|
|
573
589
|
```ts
|
|
574
|
-
|
|
590
|
+
const app = await create({ prefix: '&' });
|
|
575
591
|
|
|
576
|
-
await
|
|
592
|
+
await app.commands.load(new URL('./commands/', import.meta.url));
|
|
577
593
|
```
|
|
578
594
|
|
|
579
|
-
|
|
595
|
+
O mesmo código funciona em desenvolvimento TypeScript (com um runtime/loader como `tsx`) e depois do build: o loader reconhece `.ts`, `.mts`, `.cts`, `.js`, `.mjs` e `.cjs` por padrão. O diretório é percorrido recursivamente.
|
|
580
596
|
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
597
|
+
```text
|
|
598
|
+
src/commands/
|
|
599
|
+
├── admin/
|
|
600
|
+
│ ├── ban.ts
|
|
601
|
+
│ ├── mute.ts
|
|
602
|
+
│ └── warn.ts
|
|
603
|
+
├── group/
|
|
604
|
+
│ ├── access.ts
|
|
605
|
+
│ └── pin.ts
|
|
606
|
+
└── general/
|
|
607
|
+
├── menu.ts
|
|
608
|
+
└── profile.ts
|
|
590
609
|
```
|
|
591
610
|
|
|
592
|
-
|
|
611
|
+
Um arquivo pode exportar um comando:
|
|
593
612
|
|
|
594
613
|
```ts
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
description: 'Silencia um membro.',
|
|
601
|
-
async execute(message, args) {
|
|
602
|
-
// ...
|
|
603
|
-
},
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
const unmute = defineCommand({
|
|
607
|
-
name: 'unmute',
|
|
608
|
-
description: 'Remove o silêncio de um membro.',
|
|
609
|
-
async execute(message, args) {
|
|
610
|
-
// ...
|
|
614
|
+
export default defineCommand({
|
|
615
|
+
name: 'ping',
|
|
616
|
+
description: 'Responde pong.',
|
|
617
|
+
async execute(ctx) {
|
|
618
|
+
await ctx.reply('pong');
|
|
611
619
|
},
|
|
612
620
|
});
|
|
613
|
-
|
|
614
|
-
export default defineCommands(mute, unmute);
|
|
615
621
|
```
|
|
616
622
|
|
|
617
|
-
|
|
623
|
+
Ou vários comandos relacionados no mesmo módulo:
|
|
618
624
|
|
|
619
625
|
```ts
|
|
620
626
|
export const mute = defineCommand({ /* ... */ });
|
|
621
627
|
export const unmute = defineCommand({ /* ... */ });
|
|
622
628
|
```
|
|
623
629
|
|
|
624
|
-
|
|
630
|
+
Também é possível exportar uma coleção com `defineCommands(...)`. Exports auxiliares são ignorados quando o módulo contém pelo menos um comando válido, e o mesmo objeto não é registrado duas vezes.
|
|
625
631
|
|
|
626
|
-
|
|
632
|
+
Para menus dinâmicos, `CommandContext` expõe uma visão somente-leitura do catálogo e o prefixo atual:
|
|
627
633
|
|
|
628
634
|
```ts
|
|
629
|
-
|
|
635
|
+
export default defineCommand({
|
|
636
|
+
name: 'menu',
|
|
637
|
+
description: 'Mostra os comandos.',
|
|
638
|
+
async execute(ctx) {
|
|
639
|
+
const commands = ctx.commands.catalog({ category: 'administração' });
|
|
640
|
+
const lines = commands.map((command) =>
|
|
641
|
+
`${ctx.prefix}${command.path.join(' ')} — ${command.definition.description}`,
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
await ctx.reply(lines.join('\n'));
|
|
645
|
+
},
|
|
646
|
+
});
|
|
630
647
|
```
|
|
631
648
|
|
|
632
|
-
`
|
|
649
|
+
`ctx.commands` fornece `catalog()`, `categories()`, `find()`, `has()`, `size` e `prefix`; ele não expõe detalhes internos do provider.
|
|
633
650
|
|
|
634
|
-
|
|
651
|
+
Se for necessário controlar extensões ou recursão:
|
|
635
652
|
|
|
636
653
|
```ts
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
console.log(result.commands); // { name, filePath }[]
|
|
654
|
+
await app.commands.load(new URL('./commands/', import.meta.url), {
|
|
655
|
+
recursive: true,
|
|
656
|
+
extensions: ['.ts'],
|
|
657
|
+
});
|
|
642
658
|
```
|
|
643
659
|
|
|
660
|
+
`loadCommands(registrar, directory, options)` continua disponível como API de baixo nível para registradores customizados. O retorno contém arquivos carregados/ignorados e os comandos descobertos.
|
|
661
|
+
|
|
644
662
|
## Cache externo
|
|
645
663
|
|
|
646
664
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,14 @@ interface MessageKey {
|
|
|
65
65
|
participantId?: string;
|
|
66
66
|
}
|
|
67
67
|
type MediaKind = 'image' | 'video' | 'audio' | 'document' | 'sticker';
|
|
68
|
+
/**
|
|
69
|
+
* High-level classification of the received WhatsApp message payload.
|
|
70
|
+
*
|
|
71
|
+
* `media.kind` remains the source of truth for downloadable media.
|
|
72
|
+
* `contentKind` additionally exposes non-media payloads such as locations,
|
|
73
|
+
* contacts, polls and catalog/product messages without leaking Baileys types.
|
|
74
|
+
*/
|
|
75
|
+
type MessageContentKind = 'text' | 'image' | 'video' | 'audio' | 'document' | 'sticker' | 'location' | 'contact' | 'poll' | 'catalog' | 'unknown';
|
|
68
76
|
interface MessageMedia {
|
|
69
77
|
kind: MediaKind;
|
|
70
78
|
mimetype?: string;
|
|
@@ -99,6 +107,7 @@ interface Message {
|
|
|
99
107
|
isReply: boolean;
|
|
100
108
|
isViewOnce: boolean;
|
|
101
109
|
hasMedia: boolean;
|
|
110
|
+
contentKind?: MessageContentKind;
|
|
102
111
|
media?: MessageMedia;
|
|
103
112
|
quoted?: QuotedMessage;
|
|
104
113
|
}
|
|
@@ -438,6 +447,17 @@ declare class MessageService {
|
|
|
438
447
|
text(chatId: string, text: string, mentions?: MentionTarget[]): Promise<SentMessage>;
|
|
439
448
|
}
|
|
440
449
|
|
|
450
|
+
interface CommandCatalogView {
|
|
451
|
+
readonly prefix: string;
|
|
452
|
+
readonly size: number;
|
|
453
|
+
catalog(options?: {
|
|
454
|
+
category?: string;
|
|
455
|
+
includeHidden?: boolean;
|
|
456
|
+
}): readonly RegisteredCommand[];
|
|
457
|
+
categories(): readonly string[];
|
|
458
|
+
has(path: string): boolean;
|
|
459
|
+
find(path: string): RegisteredCommand | undefined;
|
|
460
|
+
}
|
|
441
461
|
interface CommandRuntimeServices {
|
|
442
462
|
messages: MessageService;
|
|
443
463
|
media: MediaService;
|
|
@@ -466,6 +486,8 @@ interface CommandContext<Schema extends CommandOptionSchema = CommandOptionSchem
|
|
|
466
486
|
readonly chat: CommandChatContext;
|
|
467
487
|
readonly group: CommandGroupContext | undefined;
|
|
468
488
|
readonly command: RegisteredCommand;
|
|
489
|
+
readonly commands: CommandCatalogView;
|
|
490
|
+
readonly prefix: string;
|
|
469
491
|
readonly options: ParsedCommandOptions<Schema>;
|
|
470
492
|
readonly args: ArgsParser;
|
|
471
493
|
readonly locale: string | undefined;
|
|
@@ -584,6 +606,24 @@ declare function defineCommandGroup<const Group extends CommandGroupDefinition>(
|
|
|
584
606
|
declare function defineCommands<const Commands extends readonly CommandDefinition[]>(...commands: Commands): Commands;
|
|
585
607
|
declare function isCommandGroup(definition: CommandDefinition): definition is CommandGroupDefinition;
|
|
586
608
|
|
|
609
|
+
interface CommandRegistrar {
|
|
610
|
+
command(definition: CommandDefinition): unknown;
|
|
611
|
+
}
|
|
612
|
+
interface LoadCommandsOptions {
|
|
613
|
+
extensions?: readonly string[];
|
|
614
|
+
recursive?: boolean;
|
|
615
|
+
}
|
|
616
|
+
interface LoadCommandsResult {
|
|
617
|
+
loaded: readonly string[];
|
|
618
|
+
skipped: readonly string[];
|
|
619
|
+
commands: readonly LoadedCommand[];
|
|
620
|
+
}
|
|
621
|
+
interface LoadedCommand {
|
|
622
|
+
name: string;
|
|
623
|
+
filePath: string;
|
|
624
|
+
}
|
|
625
|
+
declare function loadCommands(registrar: CommandRegistrar, dirPath: string | URL, options?: LoadCommandsOptions): Promise<LoadCommandsResult>;
|
|
626
|
+
|
|
587
627
|
interface RouterOptions {
|
|
588
628
|
prefix?: string;
|
|
589
629
|
onError?: (error: WhaNextError, message: Message) => void | Promise<void>;
|
|
@@ -606,6 +646,7 @@ declare class CommandRouter {
|
|
|
606
646
|
get prefix(): string;
|
|
607
647
|
get size(): number;
|
|
608
648
|
command(definition: CommandDefinition): this;
|
|
649
|
+
load(dirPath: string | URL, options?: LoadCommandsOptions): Promise<LoadCommandsResult>;
|
|
609
650
|
use(middleware: CommandMiddleware): this;
|
|
610
651
|
onError(handler: CommandErrorHandler): () => void;
|
|
611
652
|
catalog(options?: CommandCatalogOptions): readonly RegisteredCommand[];
|
|
@@ -749,24 +790,6 @@ declare class MemoryCache implements CacheStore {
|
|
|
749
790
|
stats(): Readonly<MemoryCacheStats>;
|
|
750
791
|
}
|
|
751
792
|
|
|
752
|
-
interface CommandRegistrar {
|
|
753
|
-
command(definition: CommandDefinition): unknown;
|
|
754
|
-
}
|
|
755
|
-
interface LoadCommandsOptions {
|
|
756
|
-
extensions?: readonly string[];
|
|
757
|
-
recursive?: boolean;
|
|
758
|
-
}
|
|
759
|
-
interface LoadCommandsResult {
|
|
760
|
-
loaded: readonly string[];
|
|
761
|
-
skipped: readonly string[];
|
|
762
|
-
commands: readonly LoadedCommand[];
|
|
763
|
-
}
|
|
764
|
-
interface LoadedCommand {
|
|
765
|
-
name: string;
|
|
766
|
-
filePath: string;
|
|
767
|
-
}
|
|
768
|
-
declare function loadCommands(registrar: CommandRegistrar, dirPath: string, options?: LoadCommandsOptions): Promise<LoadCommandsResult>;
|
|
769
|
-
|
|
770
793
|
declare class SqliteMuteStore implements MuteStore {
|
|
771
794
|
#private;
|
|
772
795
|
constructor(path?: string);
|
|
@@ -777,4 +800,4 @@ declare class SqliteMuteStore implements MuteStore {
|
|
|
777
800
|
close(): void;
|
|
778
801
|
}
|
|
779
802
|
|
|
780
|
-
export { 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 CommandCatalogOptions, 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 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 MessageKey, type MessageMedia, 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 RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, type WhatsAppProvider, create, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
|
|
803
|
+
export { 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 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 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 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 RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, type WhatsAppProvider, create, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
|
package/dist/index.js
CHANGED
|
@@ -395,6 +395,8 @@ var CommandContextImplementation = class {
|
|
|
395
395
|
chat;
|
|
396
396
|
group;
|
|
397
397
|
command;
|
|
398
|
+
commands;
|
|
399
|
+
prefix;
|
|
398
400
|
options;
|
|
399
401
|
args;
|
|
400
402
|
locale;
|
|
@@ -413,6 +415,8 @@ var CommandContextImplementation = class {
|
|
|
413
415
|
this.user = options.message.sender;
|
|
414
416
|
this.chat = { id: options.message.chatId, isGroup: options.message.isGroup };
|
|
415
417
|
this.command = options.command;
|
|
418
|
+
this.commands = options.commands;
|
|
419
|
+
this.prefix = options.commands.prefix;
|
|
416
420
|
this.options = options.options;
|
|
417
421
|
this.args = options.args;
|
|
418
422
|
this.locale = options.locale;
|
|
@@ -510,6 +514,85 @@ function normalizeContent(content) {
|
|
|
510
514
|
return typeof content === "string" ? { text: content } : content;
|
|
511
515
|
}
|
|
512
516
|
|
|
517
|
+
// src/commands/load-commands.ts
|
|
518
|
+
import { readdir } from "fs/promises";
|
|
519
|
+
import path from "path";
|
|
520
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
521
|
+
var DEFAULT_EXTENSIONS = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"];
|
|
522
|
+
async function loadCommands(registrar, dirPath, options = {}) {
|
|
523
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
524
|
+
const recursive = options.recursive ?? true;
|
|
525
|
+
const resolvedDirPath = dirPath instanceof URL ? fileURLToPath(dirPath) : dirPath;
|
|
526
|
+
const entries = await readEntries(resolvedDirPath, recursive);
|
|
527
|
+
const loaded = [];
|
|
528
|
+
const skipped = [];
|
|
529
|
+
const commands = [];
|
|
530
|
+
for (const filePath of entries) {
|
|
531
|
+
if (isDeclarationFile(filePath) || !extensions.includes(path.extname(filePath))) {
|
|
532
|
+
skipped.push(filePath);
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
const definitions = await importCommands(filePath);
|
|
536
|
+
for (const definition of definitions) {
|
|
537
|
+
registrar.command(definition);
|
|
538
|
+
commands.push({ name: definition.name, filePath });
|
|
539
|
+
}
|
|
540
|
+
loaded.push(filePath);
|
|
541
|
+
}
|
|
542
|
+
return { loaded, skipped, commands };
|
|
543
|
+
}
|
|
544
|
+
async function readEntries(dirPath, recursive) {
|
|
545
|
+
let dirents;
|
|
546
|
+
try {
|
|
547
|
+
dirents = await readdir(dirPath, { recursive, withFileTypes: true });
|
|
548
|
+
} catch (error) {
|
|
549
|
+
throw new WhaNextError("COMMAND_LOAD_FAILED", `Could not read the commands directory "${dirPath}".`, {
|
|
550
|
+
cause: error,
|
|
551
|
+
context: { dirPath }
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
return dirents.filter((dirent) => dirent.isFile()).map((dirent) => path.join(dirent.parentPath, dirent.name)).sort((left, right) => left.localeCompare(right));
|
|
555
|
+
}
|
|
556
|
+
async function importCommands(filePath) {
|
|
557
|
+
let module;
|
|
558
|
+
try {
|
|
559
|
+
module = await import(pathToFileURL(filePath).href);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
throw new WhaNextError("COMMAND_LOAD_FAILED", `Could not import the command file "${filePath}".`, {
|
|
562
|
+
cause: error,
|
|
563
|
+
context: { filePath }
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
const definitions = [];
|
|
567
|
+
const seen = /* @__PURE__ */ new Set();
|
|
568
|
+
const exports = [
|
|
569
|
+
module.default,
|
|
570
|
+
...Object.entries(module).filter(([name]) => name !== "default").map(([, value]) => value)
|
|
571
|
+
];
|
|
572
|
+
for (const value of exports) {
|
|
573
|
+
const candidates = Array.isArray(value) ? value : [value];
|
|
574
|
+
for (const candidate of candidates) {
|
|
575
|
+
if (isCommandDefinition(candidate) && !seen.has(candidate)) {
|
|
576
|
+
seen.add(candidate);
|
|
577
|
+
definitions.push(candidate);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (definitions.length === 0) {
|
|
582
|
+
throw new WhaNextError("COMMAND_LOAD_FAILED", `The file "${filePath}" does not export any valid commands.`, {
|
|
583
|
+
context: { filePath }
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
return definitions;
|
|
587
|
+
}
|
|
588
|
+
function isCommandDefinition(value) {
|
|
589
|
+
const candidate = value;
|
|
590
|
+
return typeof value === "object" && value !== null && typeof candidate.name === "string" && (typeof candidate.execute === "function" || Array.isArray(candidate.subcommands));
|
|
591
|
+
}
|
|
592
|
+
function isDeclarationFile(filePath) {
|
|
593
|
+
return /\.d\.(?:ts|mts|cts)$/.test(filePath);
|
|
594
|
+
}
|
|
595
|
+
|
|
513
596
|
// src/commands/options.ts
|
|
514
597
|
var option = {
|
|
515
598
|
string(definition) {
|
|
@@ -705,6 +788,9 @@ var CommandRouter = class {
|
|
|
705
788
|
this.#definitions.add(definition);
|
|
706
789
|
return this;
|
|
707
790
|
}
|
|
791
|
+
load(dirPath, options = {}) {
|
|
792
|
+
return loadCommands(this, dirPath, options);
|
|
793
|
+
}
|
|
708
794
|
use(middleware) {
|
|
709
795
|
this.#globalMiddleware.push(middleware);
|
|
710
796
|
return this;
|
|
@@ -778,6 +864,7 @@ _Nenhum comando dispon\xEDvel._`;
|
|
|
778
864
|
options: new ParsedCommandOptions({}),
|
|
779
865
|
args: new ArgsParser(tokens),
|
|
780
866
|
services: this.#services,
|
|
867
|
+
commands: this,
|
|
781
868
|
signal: new AbortController().signal,
|
|
782
869
|
...root.locale ? { locale: root.locale } : {}
|
|
783
870
|
});
|
|
@@ -820,6 +907,7 @@ _Nenhum comando dispon\xEDvel._`;
|
|
|
820
907
|
options: parsedOptions,
|
|
821
908
|
args: legacyArgs,
|
|
822
909
|
services: this.#services,
|
|
910
|
+
commands: this,
|
|
823
911
|
signal,
|
|
824
912
|
...resolved.locale ? { locale: resolved.locale } : {}
|
|
825
913
|
});
|
|
@@ -840,6 +928,7 @@ _Nenhum comando dispon\xEDvel._`;
|
|
|
840
928
|
options: new ParsedCommandOptions({}),
|
|
841
929
|
args: legacyArgs,
|
|
842
930
|
services: this.#services,
|
|
931
|
+
commands: this,
|
|
843
932
|
signal: new AbortController().signal,
|
|
844
933
|
...resolved.locale ? { locale: resolved.locale } : {}
|
|
845
934
|
});
|
|
@@ -2212,6 +2301,7 @@ function normalizeBaileysMessage(input) {
|
|
|
2212
2301
|
});
|
|
2213
2302
|
const mentionedUsers = (context?.mentionedJid ?? []).map((identity) => User.fromIdentities([identity]));
|
|
2214
2303
|
const media = getMedia(type, node, Boolean(input.key.isViewOnce));
|
|
2304
|
+
const contentKind = getContentKind(type);
|
|
2215
2305
|
const text = getText(content);
|
|
2216
2306
|
const caption = getCaption(content);
|
|
2217
2307
|
const quoted = getQuoted(context, chatId);
|
|
@@ -2229,7 +2319,8 @@ function normalizeBaileysMessage(input) {
|
|
|
2229
2319
|
isGroup: chatId.endsWith("@g.us"),
|
|
2230
2320
|
isReply: quoted !== void 0,
|
|
2231
2321
|
isViewOnce: media?.viewOnce ?? false,
|
|
2232
|
-
hasMedia: media !== void 0
|
|
2322
|
+
hasMedia: media !== void 0,
|
|
2323
|
+
contentKind
|
|
2233
2324
|
};
|
|
2234
2325
|
if (senderJid !== void 0) message.senderJid = senderJid;
|
|
2235
2326
|
if (senderLid !== void 0) {
|
|
@@ -2242,6 +2333,42 @@ function normalizeBaileysMessage(input) {
|
|
|
2242
2333
|
if (quoted !== void 0) message.quoted = quoted;
|
|
2243
2334
|
return message;
|
|
2244
2335
|
}
|
|
2336
|
+
function getContentKind(type) {
|
|
2337
|
+
switch (String(type ?? "")) {
|
|
2338
|
+
case "conversation":
|
|
2339
|
+
case "extendedTextMessage":
|
|
2340
|
+
case "buttonsResponseMessage":
|
|
2341
|
+
case "listResponseMessage":
|
|
2342
|
+
case "templateButtonReplyMessage":
|
|
2343
|
+
return "text";
|
|
2344
|
+
case "imageMessage":
|
|
2345
|
+
return "image";
|
|
2346
|
+
case "videoMessage":
|
|
2347
|
+
return "video";
|
|
2348
|
+
case "audioMessage":
|
|
2349
|
+
return "audio";
|
|
2350
|
+
case "documentMessage":
|
|
2351
|
+
case "documentWithCaptionMessage":
|
|
2352
|
+
return "document";
|
|
2353
|
+
case "stickerMessage":
|
|
2354
|
+
return "sticker";
|
|
2355
|
+
case "locationMessage":
|
|
2356
|
+
case "liveLocationMessage":
|
|
2357
|
+
return "location";
|
|
2358
|
+
case "contactMessage":
|
|
2359
|
+
case "contactsArrayMessage":
|
|
2360
|
+
return "contact";
|
|
2361
|
+
case "pollCreationMessage":
|
|
2362
|
+
case "pollCreationMessageV2":
|
|
2363
|
+
case "pollCreationMessageV3":
|
|
2364
|
+
return "poll";
|
|
2365
|
+
case "productMessage":
|
|
2366
|
+
case "orderMessage":
|
|
2367
|
+
return "catalog";
|
|
2368
|
+
default:
|
|
2369
|
+
return "unknown";
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2245
2372
|
function normalizeKey(key) {
|
|
2246
2373
|
const normalized = {
|
|
2247
2374
|
id: key.id ?? "",
|
|
@@ -2890,81 +3017,6 @@ var guards = {
|
|
|
2890
3017
|
return guard;
|
|
2891
3018
|
}
|
|
2892
3019
|
};
|
|
2893
|
-
|
|
2894
|
-
// src/commands/load-commands.ts
|
|
2895
|
-
import { readdir } from "fs/promises";
|
|
2896
|
-
import path from "path";
|
|
2897
|
-
import { pathToFileURL } from "url";
|
|
2898
|
-
var DEFAULT_EXTENSIONS = [".js", ".mjs", ".cjs"];
|
|
2899
|
-
async function loadCommands(registrar, dirPath, options = {}) {
|
|
2900
|
-
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
2901
|
-
const recursive = options.recursive ?? true;
|
|
2902
|
-
const entries = await readEntries(dirPath, recursive);
|
|
2903
|
-
const loaded = [];
|
|
2904
|
-
const skipped = [];
|
|
2905
|
-
const commands = [];
|
|
2906
|
-
for (const filePath of entries) {
|
|
2907
|
-
if (!extensions.includes(path.extname(filePath))) {
|
|
2908
|
-
skipped.push(filePath);
|
|
2909
|
-
continue;
|
|
2910
|
-
}
|
|
2911
|
-
const definitions = await importCommands(filePath);
|
|
2912
|
-
for (const definition of definitions) {
|
|
2913
|
-
registrar.command(definition);
|
|
2914
|
-
commands.push({ name: definition.name, filePath });
|
|
2915
|
-
}
|
|
2916
|
-
loaded.push(filePath);
|
|
2917
|
-
}
|
|
2918
|
-
return { loaded, skipped, commands };
|
|
2919
|
-
}
|
|
2920
|
-
async function readEntries(dirPath, recursive) {
|
|
2921
|
-
let dirents;
|
|
2922
|
-
try {
|
|
2923
|
-
dirents = await readdir(dirPath, { recursive, withFileTypes: true });
|
|
2924
|
-
} catch (error) {
|
|
2925
|
-
throw new WhaNextError("COMMAND_LOAD_FAILED", `Could not read the commands directory "${dirPath}".`, {
|
|
2926
|
-
cause: error,
|
|
2927
|
-
context: { dirPath }
|
|
2928
|
-
});
|
|
2929
|
-
}
|
|
2930
|
-
return dirents.filter((dirent) => dirent.isFile()).map((dirent) => path.join(dirent.parentPath, dirent.name)).sort((left, right) => left.localeCompare(right));
|
|
2931
|
-
}
|
|
2932
|
-
async function importCommands(filePath) {
|
|
2933
|
-
let module;
|
|
2934
|
-
try {
|
|
2935
|
-
module = await import(pathToFileURL(filePath).href);
|
|
2936
|
-
} catch (error) {
|
|
2937
|
-
throw new WhaNextError("COMMAND_LOAD_FAILED", `Could not import the command file "${filePath}".`, {
|
|
2938
|
-
cause: error,
|
|
2939
|
-
context: { filePath }
|
|
2940
|
-
});
|
|
2941
|
-
}
|
|
2942
|
-
const definitions = [];
|
|
2943
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2944
|
-
const exports = [
|
|
2945
|
-
module.default,
|
|
2946
|
-
...Object.entries(module).filter(([name]) => name !== "default").map(([, value]) => value)
|
|
2947
|
-
];
|
|
2948
|
-
for (const value of exports) {
|
|
2949
|
-
const candidates = Array.isArray(value) ? value : [value];
|
|
2950
|
-
for (const candidate of candidates) {
|
|
2951
|
-
if (isCommandDefinition(candidate) && !seen.has(candidate)) {
|
|
2952
|
-
seen.add(candidate);
|
|
2953
|
-
definitions.push(candidate);
|
|
2954
|
-
}
|
|
2955
|
-
}
|
|
2956
|
-
}
|
|
2957
|
-
if (definitions.length === 0) {
|
|
2958
|
-
throw new WhaNextError("COMMAND_LOAD_FAILED", `The file "${filePath}" does not export any valid commands.`, {
|
|
2959
|
-
context: { filePath }
|
|
2960
|
-
});
|
|
2961
|
-
}
|
|
2962
|
-
return definitions;
|
|
2963
|
-
}
|
|
2964
|
-
function isCommandDefinition(value) {
|
|
2965
|
-
const candidate = value;
|
|
2966
|
-
return typeof value === "object" && value !== null && typeof candidate.name === "string" && (typeof candidate.execute === "function" || Array.isArray(candidate.subcommands));
|
|
2967
|
-
}
|
|
2968
3020
|
export {
|
|
2969
3021
|
ArgsParser,
|
|
2970
3022
|
Browser,
|