@whanext/core 0.7.0 → 0.10.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 +48 -0
- package/README.md +158 -2
- package/SECURITY.md +1 -1
- package/dist/index.d.ts +288 -67
- package/dist/index.js +875 -88
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
Todas as mudanças relevantes do projeto serão registradas neste arquivo.
|
|
4
4
|
|
|
5
|
+
## 0.10.0
|
|
6
|
+
|
|
7
|
+
### Adicionado
|
|
8
|
+
|
|
9
|
+
- `CommandContext`, uma interação enriquecida que continua compatível com o modelo `Message` legado.
|
|
10
|
+
- `ctx.reply()`, `ctx.defer()`, `ctx.edit()`, `ctx.react()`, `ctx.unreact()`, `ctx.delete()` e respostas com exclusão programada.
|
|
11
|
+
- `option.string`, `number`, `boolean`, `enum`, `user` e `duration`, com inferência de tipos, obrigatoriedade e validações.
|
|
12
|
+
- `defineCommandGroup()` e `defineSubcommand()` para comandos como `&grupo abrir` e `&grupo fechar`.
|
|
13
|
+
- Guards reutilizáveis para grupo, privado, admin, bot admin e regras customizadas.
|
|
14
|
+
- Middleware global e por comando, além de hooks `beforeExecute`, `afterExecute` e `onError`.
|
|
15
|
+
- Cooldown por usuário, chat, usuário+chat ou global, com limpeza automática de entradas expiradas.
|
|
16
|
+
- Controle de concorrência com estratégias `parallel`, `reject`, `queue` e `replace`.
|
|
17
|
+
- `app.commands`, catálogo consultável, categorias, busca e help gerado por metadados.
|
|
18
|
+
- Localizações de nome, aliases e descrição sem duplicar definições.
|
|
19
|
+
- Códigos de erro `COMMAND_COOLDOWN` e `COMMAND_BUSY`.
|
|
20
|
+
|
|
21
|
+
### Compatibilidade
|
|
22
|
+
|
|
23
|
+
- `app.router()` continua retornando o mesmo router disponível em `app.commands`.
|
|
24
|
+
- `onlyGroup`, `onlyPrivate`, `onlyAdmin` e `botMustBeAdmin` continuam suportados.
|
|
25
|
+
- Comandos legados com `execute(message, args)` continuam funcionando sem alteração.
|
|
26
|
+
- `loadCommands()` agora também reconhece grupos de comandos.
|
|
27
|
+
|
|
28
|
+
## 0.9.0
|
|
29
|
+
|
|
30
|
+
### Alterado
|
|
31
|
+
|
|
32
|
+
- Baileys atualizado de `7.0.0-rc13` para `7.0.0-rc14`.
|
|
33
|
+
- O provider agora fornece `cachedGroupMetadata` ao Baileys, evitando consultas redundantes ao WhatsApp no fan-out de mensagens em grupos.
|
|
34
|
+
- O cache interno usado pelo envio possui TTL, LRU limitado, deduplicação de buscas concorrentes e proteção contra a reinserção de resultados invalidados durante uma busca.
|
|
35
|
+
- `MemoryCache` agora promove corretamente chaves sobrescritas na ordem LRU.
|
|
36
|
+
|
|
37
|
+
### Adicionado
|
|
38
|
+
|
|
39
|
+
- `MemoryCache.stats()` para observar hits, misses, sets, evictions e expirations.
|
|
40
|
+
- `MemoryCache.prune()` para remover entradas expiradas de forma explícita.
|
|
41
|
+
|
|
42
|
+
### Compatibilidade
|
|
43
|
+
|
|
44
|
+
- Nenhuma alteração é necessária nos comandos ou na API pública existente.
|
|
45
|
+
- Sessões criadas pela v0.8 continuam compatíveis; o auth state multifile do Baileys 7 já persiste as chaves de LID, device list e TC token exigidas pela migração.
|
|
46
|
+
|
|
47
|
+
## 0.8.0
|
|
48
|
+
|
|
49
|
+
### Adicionado
|
|
50
|
+
|
|
51
|
+
- `app.media.sticker(chatId, { sticker })` para enviar stickers WebP estáticos ou animados a partir de bytes, URL ou arquivo local.
|
|
52
|
+
|
|
5
53
|
## 0.7.0
|
|
6
54
|
|
|
7
55
|
### Adicionado
|
package/README.md
CHANGED
|
@@ -290,6 +290,10 @@ await app.media.audio(chatId, {
|
|
|
290
290
|
voice: true,
|
|
291
291
|
});
|
|
292
292
|
|
|
293
|
+
await app.media.sticker(chatId, {
|
|
294
|
+
sticker: { path: './sticker.webp' },
|
|
295
|
+
});
|
|
296
|
+
|
|
293
297
|
const downloaded = await app.media.download(message);
|
|
294
298
|
|
|
295
299
|
await writeFile(`./downloads/${downloaded.fileName ?? message.id}`, downloaded.data);
|
|
@@ -297,7 +301,7 @@ await writeFile(`./downloads/${downloaded.fileName ?? message.id}`, downloaded.d
|
|
|
297
301
|
|
|
298
302
|
`download()` aceita a `Message` recebida ou a sua `MessageKey` e devolve o buffer junto dos metadados normalizados. A mídia deve ser baixada enquanto a mensagem ainda está no cache da instância; o provider tenta renovar a URL de mídia automaticamente quando necessário.
|
|
299
303
|
|
|
300
|
-
Texto, imagem e vídeo aceitam `User` diretamente em `mentions`.
|
|
304
|
+
Stickers aceitam `Uint8Array`, URL ou caminho local e devem estar em WebP, inclusive para animações. Texto, imagem e vídeo aceitam `User` diretamente em `mentions`.
|
|
301
305
|
|
|
302
306
|
## Grupos e membros
|
|
303
307
|
|
|
@@ -397,6 +401,137 @@ const app = await create({
|
|
|
397
401
|
|
|
398
402
|
## Comandos
|
|
399
403
|
|
|
404
|
+
O sistema moderno usa um contexto semelhante às interactions do Discord. `ctx` contém a mensagem normalizada, usuário, chat, grupo, services, options, sinal de cancelamento e helpers de resposta.
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
import {
|
|
408
|
+
defineCommand,
|
|
409
|
+
guards,
|
|
410
|
+
option,
|
|
411
|
+
} from '@whanext/core';
|
|
412
|
+
|
|
413
|
+
app.commands.command(
|
|
414
|
+
defineCommand({
|
|
415
|
+
name: 'ban',
|
|
416
|
+
aliases: ['banir'],
|
|
417
|
+
description: 'Remove um membro do grupo.',
|
|
418
|
+
category: 'moderação',
|
|
419
|
+
|
|
420
|
+
guards: [
|
|
421
|
+
guards.group(),
|
|
422
|
+
guards.userAdmin(),
|
|
423
|
+
guards.botAdmin(),
|
|
424
|
+
],
|
|
425
|
+
|
|
426
|
+
options: {
|
|
427
|
+
user: option.user({
|
|
428
|
+
description: 'Usuário que será removido.',
|
|
429
|
+
required: true,
|
|
430
|
+
}),
|
|
431
|
+
reason: option.string({
|
|
432
|
+
description: 'Motivo da remoção.',
|
|
433
|
+
rest: true,
|
|
434
|
+
}),
|
|
435
|
+
},
|
|
436
|
+
|
|
437
|
+
cooldown: {
|
|
438
|
+
durationMs: 5_000,
|
|
439
|
+
scope: 'user-chat',
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
concurrency: {
|
|
443
|
+
scope: 'chat',
|
|
444
|
+
max: 1,
|
|
445
|
+
strategy: 'queue',
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
async execute(ctx) {
|
|
449
|
+
const user = ctx.options.user('user');
|
|
450
|
+
const reason = ctx.options.string('reason') ?? 'Não informado';
|
|
451
|
+
const deferred = await ctx.defer('⏳ _Processando banimento..._');
|
|
452
|
+
const result = await ctx.members.remove(ctx.chatId, user);
|
|
453
|
+
|
|
454
|
+
await deferred.edit(
|
|
455
|
+
result.changed
|
|
456
|
+
? `🔨 *Usuário banido*\n\n${user.mention} foi removido.\n• *Motivo:* ${reason}`
|
|
457
|
+
: `⚠️ O usuário não está mais no grupo.`,
|
|
458
|
+
);
|
|
459
|
+
},
|
|
460
|
+
}),
|
|
461
|
+
);
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Subcomandos
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
import {
|
|
468
|
+
defineCommandGroup,
|
|
469
|
+
defineSubcommand,
|
|
470
|
+
guards,
|
|
471
|
+
} from '@whanext/core';
|
|
472
|
+
|
|
473
|
+
app.commands.command(defineCommandGroup({
|
|
474
|
+
name: 'grupo',
|
|
475
|
+
aliases: ['group'],
|
|
476
|
+
description: 'Gerencia o grupo.',
|
|
477
|
+
category: 'grupos',
|
|
478
|
+
guards: [guards.group(), guards.userAdmin(), guards.botAdmin()],
|
|
479
|
+
|
|
480
|
+
subcommands: [
|
|
481
|
+
defineSubcommand({
|
|
482
|
+
name: 'abrir',
|
|
483
|
+
aliases: ['open'],
|
|
484
|
+
description: 'Abre o grupo.',
|
|
485
|
+
async execute(ctx) {
|
|
486
|
+
await ctx.groups.open(ctx.chatId);
|
|
487
|
+
await ctx.reply('🔓 *Grupo aberto*');
|
|
488
|
+
},
|
|
489
|
+
}),
|
|
490
|
+
defineSubcommand({
|
|
491
|
+
name: 'fechar',
|
|
492
|
+
aliases: ['close'],
|
|
493
|
+
description: 'Fecha o grupo.',
|
|
494
|
+
async execute(ctx) {
|
|
495
|
+
await ctx.groups.close(ctx.chatId);
|
|
496
|
+
await ctx.reply('🔒 *Grupo fechado*');
|
|
497
|
+
},
|
|
498
|
+
}),
|
|
499
|
+
],
|
|
500
|
+
}));
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Isso aceita `&grupo abrir`, `&group open`, `&grupo fechar` e `&group close` sem duplicar lógica.
|
|
504
|
+
|
|
505
|
+
### Middleware e erros
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
app.commands.use(async (ctx, next) => {
|
|
509
|
+
const startedAt = performance.now();
|
|
510
|
+
await next();
|
|
511
|
+
app.logger.debug('Command completed', {
|
|
512
|
+
command: ctx.command.path.join(' '),
|
|
513
|
+
durationMs: performance.now() - startedAt,
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
app.commands.onError(async (ctx, error) => {
|
|
518
|
+
if (error.code === 'COMMAND_COOLDOWN') {
|
|
519
|
+
await ctx.reply('⏱️ Aguarde um pouco antes de usar novamente.');
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
await ctx.reply('⚠️ *Não foi possível concluir*');
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
`app.commands.catalog()`, `categories()`, `find()`, `has()` e `values()` expõem a coleção registrada. `app.commands.help(ctx, { category: 'moderação' })` gera a ajuda usando descrição, usage, opções e visibilidade dos comandos.
|
|
528
|
+
|
|
529
|
+
Detalhes completos estão em [Comandos modernos](./docs/commands-v0.10.md).
|
|
530
|
+
|
|
531
|
+
### API legada
|
|
532
|
+
|
|
533
|
+
Comandos existentes continuam válidos:
|
|
534
|
+
|
|
400
535
|
```ts
|
|
401
536
|
app.router().command(
|
|
402
537
|
defineCommand({
|
|
@@ -520,12 +655,33 @@ const app = await create({
|
|
|
520
655
|
|
|
521
656
|
O cache padrão vive na instância do app, usa LRU limitado e elimina entradas expiradas durante as leituras. Consultas simultâneas dos mesmos metadados são agrupadas em uma única chamada ao WhatsApp. Eventos e mutações de grupo invalidam automaticamente entradas relacionadas.
|
|
522
657
|
|
|
658
|
+
Os mesmos metadados também alimentam internamente o `cachedGroupMetadata` do Baileys. Em grupos já aquecidos, isso remove a consulta de metadados do caminho de envio; mensagens continuam aguardando somente criptografia, upload quando houver mídia e confirmação da rede.
|
|
659
|
+
|
|
660
|
+
Para observar um `MemoryCache` criado diretamente:
|
|
661
|
+
|
|
662
|
+
```ts
|
|
663
|
+
import { MemoryCache } from '@whanext/core';
|
|
664
|
+
|
|
665
|
+
const cache = new MemoryCache({ maxEntries: 5_000 });
|
|
666
|
+
|
|
667
|
+
console.log(cache.stats());
|
|
668
|
+
cache.prune();
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
`stats()` informa `size`, `maxEntries`, `hits`, `misses`, `sets`, `evictions` e `expirations`.
|
|
672
|
+
|
|
673
|
+
Para uma única instância, o cache padrão é suficiente mesmo com muitos grupos, desde que `memoryMaxEntries` seja dimensionado. Em várias instâncias/processos, use um `CacheStore` distribuído para o cache público; cada conexão mantém ainda um L1 local limitado para o caminho criptográfico do Baileys. Não compartilhe uma mesma sessão ativa entre processos.
|
|
674
|
+
|
|
523
675
|
O cache interno de mensagens mantém até 1.000 mensagens por padrão para replies, reenvios do provider e downloads de mídia. Ajuste quando necessário:
|
|
524
676
|
|
|
525
677
|
```ts
|
|
526
678
|
const app = await create({ messageCacheSize: 2_000 });
|
|
527
679
|
```
|
|
528
680
|
|
|
681
|
+
Não há delay artificial no envio. Presença é enviada diretamente e previews de alta qualidade permanecem desativados no provider; mídias ainda dependem do tempo de leitura, criptografia e upload ao WhatsApp.
|
|
682
|
+
|
|
683
|
+
Para limites, dimensionamento e decisões de produção, consulte [Desempenho e escala](./docs/performance-and-scale.md).
|
|
684
|
+
|
|
529
685
|
## Presença
|
|
530
686
|
|
|
531
687
|
```ts
|
|
@@ -567,7 +723,7 @@ Todos os erros públicos usam `WhaNextError` e códigos estáveis. O logger regi
|
|
|
567
723
|
| Domínio | Responsabilidade |
|
|
568
724
|
| --- | --- |
|
|
569
725
|
| `app.message` | Envio, reply, edição, exclusão, texto e reações |
|
|
570
|
-
| `app.media` | Envio
|
|
726
|
+
| `app.media` | Envio, download e stickers |
|
|
571
727
|
| `app.group` | Estado, convite, pin e metadados |
|
|
572
728
|
| `app.member` | Remoção, promoção e rebaixamento |
|
|
573
729
|
| `app.user` | Criação e resolução de usuários |
|
package/SECURITY.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -142,34 +142,10 @@ interface AudioContent {
|
|
|
142
142
|
mimetype?: string;
|
|
143
143
|
voice?: boolean;
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
interface CommandDefinition {
|
|
148
|
-
name: string;
|
|
149
|
-
description: string;
|
|
150
|
-
aliases?: readonly string[];
|
|
151
|
-
onlyGroup?: boolean;
|
|
152
|
-
onlyPrivate?: boolean;
|
|
153
|
-
onlyAdmin?: boolean;
|
|
154
|
-
botMustBeAdmin?: boolean;
|
|
155
|
-
execute(message: Message, args: ArgsParser): void | Promise<void>;
|
|
145
|
+
interface StickerContent {
|
|
146
|
+
sticker: MediaSource;
|
|
156
147
|
}
|
|
157
|
-
|
|
158
|
-
declare function defineCommands<const Commands extends readonly CommandDefinition[]>(...commands: Commands): Commands;
|
|
159
|
-
|
|
160
|
-
type WhaNextErrorCode = 'AUTH_INVALID_PHONE' | 'AUTH_EXPIRED' | 'CONNECTION_CLOSED' | 'CONNECTION_FAILED' | 'GROUP_NOT_FOUND' | 'MEMBER_NOT_FOUND' | 'BOT_NOT_ADMIN' | 'MESSAGE_NOT_FOUND' | 'MEDIA_NOT_AVAILABLE' | 'MUTE_DISABLED' | 'STORAGE_ERROR' | 'ARGUMENT_MISSING' | 'ARGUMENT_INVALID' | 'COMMAND_NOT_ALLOWED' | 'COMMAND_LOAD_FAILED' | 'PROVIDER_ERROR' | 'UNKNOWN_ERROR';
|
|
161
|
-
interface WhaNextErrorOptions {
|
|
162
|
-
cause?: unknown;
|
|
163
|
-
context?: Readonly<Record<string, unknown>>;
|
|
164
|
-
recoverable?: boolean;
|
|
165
|
-
}
|
|
166
|
-
declare class WhaNextError extends Error {
|
|
167
|
-
readonly code: WhaNextErrorCode;
|
|
168
|
-
readonly context: Readonly<Record<string, unknown>>;
|
|
169
|
-
readonly recoverable: boolean;
|
|
170
|
-
constructor(code: WhaNextErrorCode, message: string, options?: WhaNextErrorOptions);
|
|
171
|
-
}
|
|
172
|
-
declare function toWhaNextError(error: unknown, context?: Readonly<Record<string, unknown>>): WhaNextError;
|
|
148
|
+
type MessageContent = TextContent | ImageContent | VideoContent | AudioContent | StickerContent;
|
|
173
149
|
|
|
174
150
|
type GroupAccess = 'open' | 'closed';
|
|
175
151
|
type GroupRole = 'member' | 'admin' | 'owner';
|
|
@@ -283,47 +259,75 @@ declare class GroupService {
|
|
|
283
259
|
invalidate(groupId: string): Promise<void>;
|
|
284
260
|
}
|
|
285
261
|
|
|
286
|
-
|
|
287
|
-
prefix?: string;
|
|
288
|
-
onError?: (error: WhaNextError, message: Message) => void | Promise<void>;
|
|
289
|
-
}
|
|
290
|
-
declare class CommandRouter {
|
|
262
|
+
declare class UserService {
|
|
291
263
|
#private;
|
|
292
|
-
constructor(group: GroupService
|
|
293
|
-
|
|
294
|
-
|
|
264
|
+
constructor(group: GroupService);
|
|
265
|
+
resolve(message: Message, args: ArgsParser): Promise<User>;
|
|
266
|
+
from(identity: string): User;
|
|
295
267
|
}
|
|
296
268
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
timestamp: string;
|
|
302
|
-
level: Exclude<LogLevel, 'silent'>;
|
|
303
|
-
scope: string;
|
|
304
|
-
message: string;
|
|
305
|
-
context: LogContext;
|
|
269
|
+
interface BaseOption<TKind extends string> {
|
|
270
|
+
kind: TKind;
|
|
271
|
+
description: string;
|
|
272
|
+
required?: boolean;
|
|
306
273
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
writer?: LogWriter;
|
|
312
|
-
scope?: string;
|
|
313
|
-
redact?: readonly string[];
|
|
274
|
+
interface StringOption extends BaseOption<'string'> {
|
|
275
|
+
rest?: boolean;
|
|
276
|
+
minLength?: number;
|
|
277
|
+
maxLength?: number;
|
|
314
278
|
}
|
|
315
|
-
|
|
316
|
-
|
|
279
|
+
interface NumberOption extends BaseOption<'number'> {
|
|
280
|
+
min?: number;
|
|
281
|
+
max?: number;
|
|
282
|
+
}
|
|
283
|
+
interface BooleanOption extends BaseOption<'boolean'> {
|
|
284
|
+
}
|
|
285
|
+
interface UserOption extends BaseOption<'user'> {
|
|
286
|
+
}
|
|
287
|
+
interface DurationOption extends BaseOption<'duration'> {
|
|
288
|
+
}
|
|
289
|
+
interface EnumOption<Values extends readonly string[] = readonly string[]> extends BaseOption<'enum'> {
|
|
290
|
+
values: Values;
|
|
291
|
+
}
|
|
292
|
+
type CommandOptionDefinition = StringOption | NumberOption | BooleanOption | UserOption | DurationOption | EnumOption;
|
|
293
|
+
type CommandOptionSchema = Readonly<Record<string, CommandOptionDefinition>>;
|
|
294
|
+
type RawOptionValue<Definition extends CommandOptionDefinition> = Definition extends StringOption ? string : Definition extends NumberOption ? number : Definition extends BooleanOption ? boolean : Definition extends UserOption ? User : Definition extends DurationOption ? number | undefined : Definition extends EnumOption<infer Values> ? Values[number] : never;
|
|
295
|
+
type CommandOptionValue<Definition extends CommandOptionDefinition> = Definition['required'] extends true ? RawOptionValue<Definition> : RawOptionValue<Definition> | undefined;
|
|
296
|
+
type CommandOptionValues<Schema extends CommandOptionSchema> = {
|
|
297
|
+
readonly [Name in keyof Schema]: CommandOptionValue<Schema[Name]>;
|
|
298
|
+
};
|
|
299
|
+
declare const option: {
|
|
300
|
+
string<const Definition extends Omit<StringOption, "kind">>(definition: Definition): {
|
|
301
|
+
kind: "string";
|
|
302
|
+
} & Definition;
|
|
303
|
+
number<const Definition extends Omit<NumberOption, "kind">>(definition: Definition): {
|
|
304
|
+
kind: "number";
|
|
305
|
+
} & Definition;
|
|
306
|
+
boolean<const Definition extends Omit<BooleanOption, "kind">>(definition: Definition): {
|
|
307
|
+
kind: "boolean";
|
|
308
|
+
} & Definition;
|
|
309
|
+
user<const Definition extends Omit<UserOption, "kind">>(definition: Definition): {
|
|
310
|
+
kind: "user";
|
|
311
|
+
} & Definition;
|
|
312
|
+
duration<const Definition extends Omit<DurationOption, "kind">>(definition: Definition): {
|
|
313
|
+
kind: "duration";
|
|
314
|
+
} & Definition;
|
|
315
|
+
enum<const Values extends readonly string[], const Definition extends Omit<EnumOption<Values>, "kind" | "values">>(values: Values, definition: Definition): {
|
|
316
|
+
kind: "enum";
|
|
317
|
+
values: Values;
|
|
318
|
+
} & Definition;
|
|
319
|
+
};
|
|
320
|
+
declare class ParsedCommandOptions<Schema extends CommandOptionSchema = CommandOptionSchema> {
|
|
317
321
|
#private;
|
|
318
|
-
constructor(
|
|
319
|
-
get
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
322
|
+
constructor(values: CommandOptionValues<Schema>);
|
|
323
|
+
get<Name extends keyof Schema>(name: Name): CommandOptionValue<Schema[Name]>;
|
|
324
|
+
string<Name extends keyof Schema>(name: Name): CommandOptionValue<Schema[Name]>;
|
|
325
|
+
number<Name extends keyof Schema>(name: Name): CommandOptionValue<Schema[Name]>;
|
|
326
|
+
boolean<Name extends keyof Schema>(name: Name): CommandOptionValue<Schema[Name]>;
|
|
327
|
+
user<Name extends keyof Schema>(name: Name): CommandOptionValue<Schema[Name]>;
|
|
328
|
+
duration<Name extends keyof Schema>(name: Name): CommandOptionValue<Schema[Name]>;
|
|
329
|
+
enum<Name extends keyof Schema>(name: Name): CommandOptionValue<Schema[Name]>;
|
|
330
|
+
toJSON(): CommandOptionValues<Schema>;
|
|
327
331
|
}
|
|
328
332
|
|
|
329
333
|
interface StoredMute {
|
|
@@ -410,6 +414,7 @@ declare class MediaService {
|
|
|
410
414
|
image(chatId: string, content: ImageContent): Promise<SentMessage>;
|
|
411
415
|
video(chatId: string, content: VideoContent): Promise<SentMessage>;
|
|
412
416
|
audio(chatId: string, content: AudioContent): Promise<SentMessage>;
|
|
417
|
+
sticker(chatId: string, content: StickerContent): Promise<SentMessage>;
|
|
413
418
|
download(message: Message | MessageKey): Promise<DownloadedMedia>;
|
|
414
419
|
}
|
|
415
420
|
|
|
@@ -433,11 +438,215 @@ declare class MessageService {
|
|
|
433
438
|
text(chatId: string, text: string, mentions?: MentionTarget[]): Promise<SentMessage>;
|
|
434
439
|
}
|
|
435
440
|
|
|
436
|
-
|
|
441
|
+
interface CommandRuntimeServices {
|
|
442
|
+
messages: MessageService;
|
|
443
|
+
media: MediaService;
|
|
444
|
+
groups: GroupService;
|
|
445
|
+
members: MemberService;
|
|
446
|
+
chats: ChatService;
|
|
447
|
+
users: UserService;
|
|
448
|
+
mute: MuteService;
|
|
449
|
+
}
|
|
450
|
+
interface CommandChatContext {
|
|
451
|
+
id: string;
|
|
452
|
+
isGroup: boolean;
|
|
453
|
+
}
|
|
454
|
+
interface CommandGroupContext {
|
|
455
|
+
id: string;
|
|
456
|
+
metadata(refresh?: boolean): ReturnType<GroupService['metadata']>;
|
|
457
|
+
isUserAdmin(): Promise<boolean>;
|
|
458
|
+
isBotAdmin(): Promise<boolean>;
|
|
459
|
+
}
|
|
460
|
+
interface ReplyOptions {
|
|
461
|
+
deleteAfterMs?: number;
|
|
462
|
+
}
|
|
463
|
+
interface CommandContext<Schema extends CommandOptionSchema = CommandOptionSchema> extends Message {
|
|
464
|
+
readonly message: Message;
|
|
465
|
+
readonly user: User;
|
|
466
|
+
readonly chat: CommandChatContext;
|
|
467
|
+
readonly group: CommandGroupContext | undefined;
|
|
468
|
+
readonly command: RegisteredCommand;
|
|
469
|
+
readonly options: ParsedCommandOptions<Schema>;
|
|
470
|
+
readonly args: ArgsParser;
|
|
471
|
+
readonly locale: string | undefined;
|
|
472
|
+
readonly signal: AbortSignal;
|
|
473
|
+
readonly client: CommandRuntimeServices;
|
|
474
|
+
readonly messages: MessageService;
|
|
475
|
+
readonly mediaService: MediaService;
|
|
476
|
+
readonly groups: GroupService;
|
|
477
|
+
readonly members: MemberService;
|
|
478
|
+
readonly chats: ChatService;
|
|
479
|
+
readonly users: UserService;
|
|
480
|
+
readonly muteService: MuteService;
|
|
481
|
+
reply(content: string | MessageContent, options?: ReplyOptions): Promise<SentMessage>;
|
|
482
|
+
defer(content?: string | MessageContent): Promise<DeferredReply>;
|
|
483
|
+
edit(content: string): Promise<SentMessage>;
|
|
484
|
+
react(emoji: string): Promise<SentMessage>;
|
|
485
|
+
unreact(): Promise<SentMessage>;
|
|
486
|
+
delete(): Promise<void>;
|
|
487
|
+
deleteReply(options?: ReplyOptions): Promise<void>;
|
|
488
|
+
}
|
|
489
|
+
declare class DeferredReply {
|
|
437
490
|
#private;
|
|
438
|
-
constructor(
|
|
439
|
-
|
|
440
|
-
|
|
491
|
+
constructor(messages: MessageService, message: SentMessage, onEdit: (message: SentMessage) => void);
|
|
492
|
+
edit(content: string): Promise<SentMessage>;
|
|
493
|
+
delete(): Promise<void>;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
type WhaNextErrorCode = 'AUTH_INVALID_PHONE' | 'AUTH_EXPIRED' | 'CONNECTION_CLOSED' | 'CONNECTION_FAILED' | 'GROUP_NOT_FOUND' | 'MEMBER_NOT_FOUND' | 'BOT_NOT_ADMIN' | 'MESSAGE_NOT_FOUND' | 'MEDIA_NOT_AVAILABLE' | 'MUTE_DISABLED' | 'STORAGE_ERROR' | 'ARGUMENT_MISSING' | 'ARGUMENT_INVALID' | 'COMMAND_NOT_ALLOWED' | 'COMMAND_COOLDOWN' | 'COMMAND_BUSY' | 'COMMAND_LOAD_FAILED' | 'PROVIDER_ERROR' | 'UNKNOWN_ERROR';
|
|
497
|
+
interface WhaNextErrorOptions {
|
|
498
|
+
cause?: unknown;
|
|
499
|
+
context?: Readonly<Record<string, unknown>>;
|
|
500
|
+
recoverable?: boolean;
|
|
501
|
+
}
|
|
502
|
+
declare class WhaNextError extends Error {
|
|
503
|
+
readonly code: WhaNextErrorCode;
|
|
504
|
+
readonly context: Readonly<Record<string, unknown>>;
|
|
505
|
+
readonly recoverable: boolean;
|
|
506
|
+
constructor(code: WhaNextErrorCode, message: string, options?: WhaNextErrorOptions);
|
|
507
|
+
}
|
|
508
|
+
declare function toWhaNextError(error: unknown, context?: Readonly<Record<string, unknown>>): WhaNextError;
|
|
509
|
+
|
|
510
|
+
interface GuardResult {
|
|
511
|
+
allowed: boolean;
|
|
512
|
+
code?: WhaNextErrorCode;
|
|
513
|
+
message?: string;
|
|
514
|
+
}
|
|
515
|
+
type CommandGuard = (context: CommandContext) => boolean | void | GuardResult | Promise<boolean | void | GuardResult>;
|
|
516
|
+
declare const guards: {
|
|
517
|
+
group(): CommandGuard;
|
|
518
|
+
private(): CommandGuard;
|
|
519
|
+
userAdmin(): CommandGuard;
|
|
520
|
+
botAdmin(): CommandGuard;
|
|
521
|
+
botEnabled(check: (context: CommandContext) => boolean | Promise<boolean>): CommandGuard;
|
|
522
|
+
custom(guard: CommandGuard): CommandGuard;
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
type CommandScope = 'global' | 'user' | 'chat' | 'user-chat' | 'user-group';
|
|
526
|
+
type ConcurrencyStrategy = 'parallel' | 'reject' | 'queue' | 'replace';
|
|
527
|
+
interface CommandCooldown {
|
|
528
|
+
durationMs: number;
|
|
529
|
+
scope?: CommandScope;
|
|
530
|
+
}
|
|
531
|
+
interface CommandConcurrency {
|
|
532
|
+
max?: number;
|
|
533
|
+
scope?: CommandScope;
|
|
534
|
+
strategy?: ConcurrencyStrategy;
|
|
535
|
+
}
|
|
536
|
+
interface CommandLocalization {
|
|
537
|
+
name?: string;
|
|
538
|
+
aliases?: readonly string[];
|
|
539
|
+
description?: string;
|
|
540
|
+
}
|
|
541
|
+
type CommandMiddleware = (context: CommandContext, next: () => Promise<void>) => void | Promise<void>;
|
|
542
|
+
interface CommandHooks {
|
|
543
|
+
beforeExecute?: (context: CommandContext) => void | Promise<void>;
|
|
544
|
+
afterExecute?: (context: CommandContext) => void | Promise<void>;
|
|
545
|
+
onError?: (context: CommandContext, error: Error) => void | Promise<void>;
|
|
546
|
+
}
|
|
547
|
+
interface CommandMetadata {
|
|
548
|
+
name: string;
|
|
549
|
+
description: string;
|
|
550
|
+
aliases?: readonly string[];
|
|
551
|
+
category?: string;
|
|
552
|
+
usage?: string;
|
|
553
|
+
examples?: readonly string[];
|
|
554
|
+
hidden?: boolean;
|
|
555
|
+
localizations?: Readonly<Record<string, CommandLocalization>>;
|
|
556
|
+
guards?: readonly CommandGuard[];
|
|
557
|
+
middleware?: readonly CommandMiddleware[];
|
|
558
|
+
cooldown?: CommandCooldown;
|
|
559
|
+
concurrency?: CommandConcurrency;
|
|
560
|
+
hooks?: CommandHooks;
|
|
561
|
+
onlyGroup?: boolean;
|
|
562
|
+
onlyPrivate?: boolean;
|
|
563
|
+
onlyAdmin?: boolean;
|
|
564
|
+
botMustBeAdmin?: boolean;
|
|
565
|
+
}
|
|
566
|
+
interface ExecutableCommandDefinition<Schema extends CommandOptionSchema = CommandOptionSchema> extends CommandMetadata {
|
|
567
|
+
options?: Schema;
|
|
568
|
+
execute(context: CommandContext<Schema>, args: ArgsParser): void | Promise<void>;
|
|
569
|
+
}
|
|
570
|
+
interface CommandGroupDefinition extends CommandMetadata {
|
|
571
|
+
subcommands: readonly CommandDefinition[];
|
|
572
|
+
}
|
|
573
|
+
type CommandDefinition<Schema extends CommandOptionSchema = CommandOptionSchema> = ExecutableCommandDefinition<Schema> | CommandGroupDefinition;
|
|
574
|
+
interface RegisteredCommand {
|
|
575
|
+
definition: ExecutableCommandDefinition;
|
|
576
|
+
root: CommandDefinition;
|
|
577
|
+
path: readonly string[];
|
|
578
|
+
aliases: readonly string[];
|
|
579
|
+
category: string;
|
|
580
|
+
}
|
|
581
|
+
declare function defineCommand<const Schema extends CommandOptionSchema = CommandOptionSchema>(command: ExecutableCommandDefinition<Schema>): ExecutableCommandDefinition<Schema>;
|
|
582
|
+
declare function defineSubcommand<const Schema extends CommandOptionSchema = CommandOptionSchema>(command: ExecutableCommandDefinition<Schema>): ExecutableCommandDefinition<Schema>;
|
|
583
|
+
declare function defineCommandGroup<const Group extends CommandGroupDefinition>(group: Group): Group;
|
|
584
|
+
declare function defineCommands<const Commands extends readonly CommandDefinition[]>(...commands: Commands): Commands;
|
|
585
|
+
declare function isCommandGroup(definition: CommandDefinition): definition is CommandGroupDefinition;
|
|
586
|
+
|
|
587
|
+
interface RouterOptions {
|
|
588
|
+
prefix?: string;
|
|
589
|
+
onError?: (error: WhaNextError, message: Message) => void | Promise<void>;
|
|
590
|
+
onCommandError?: CommandErrorHandler;
|
|
591
|
+
beforeExecute?: (context: CommandContext) => void | Promise<void>;
|
|
592
|
+
afterExecute?: (context: CommandContext) => void | Promise<void>;
|
|
593
|
+
}
|
|
594
|
+
interface CommandCatalogOptions {
|
|
595
|
+
category?: string;
|
|
596
|
+
includeHidden?: boolean;
|
|
597
|
+
}
|
|
598
|
+
interface CommandHelpOptions extends CommandCatalogOptions {
|
|
599
|
+
title?: string;
|
|
600
|
+
}
|
|
601
|
+
type CommandErrorHandler = (context: CommandContext, error: WhaNextError) => void | Promise<void>;
|
|
602
|
+
declare class CommandRouter {
|
|
603
|
+
#private;
|
|
604
|
+
constructor(services: CommandRuntimeServices, options?: RouterOptions);
|
|
605
|
+
constructor(group: GroupService, options?: RouterOptions);
|
|
606
|
+
get prefix(): string;
|
|
607
|
+
get size(): number;
|
|
608
|
+
command(definition: CommandDefinition): this;
|
|
609
|
+
use(middleware: CommandMiddleware): this;
|
|
610
|
+
onError(handler: CommandErrorHandler): () => void;
|
|
611
|
+
catalog(options?: CommandCatalogOptions): readonly RegisteredCommand[];
|
|
612
|
+
categories(): readonly string[];
|
|
613
|
+
has(path: string): boolean;
|
|
614
|
+
values(): readonly RegisteredCommand[];
|
|
615
|
+
find(path: string): RegisteredCommand | undefined;
|
|
616
|
+
help(context: CommandContext, options?: CommandHelpOptions): Promise<SentMessage>;
|
|
617
|
+
dispatch(message: Message): Promise<boolean>;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
621
|
+
type LogFormat = 'pretty' | 'json';
|
|
622
|
+
type LogContext = Readonly<Record<string, unknown>>;
|
|
623
|
+
interface LogEntry {
|
|
624
|
+
timestamp: string;
|
|
625
|
+
level: Exclude<LogLevel, 'silent'>;
|
|
626
|
+
scope: string;
|
|
627
|
+
message: string;
|
|
628
|
+
context: LogContext;
|
|
629
|
+
}
|
|
630
|
+
type LogWriter = (entry: LogEntry) => unknown;
|
|
631
|
+
interface LoggerOptions {
|
|
632
|
+
level?: LogLevel;
|
|
633
|
+
format?: LogFormat;
|
|
634
|
+
writer?: LogWriter;
|
|
635
|
+
scope?: string;
|
|
636
|
+
redact?: readonly string[];
|
|
637
|
+
}
|
|
638
|
+
type LoggerConfig = LogLevel | LoggerOptions;
|
|
639
|
+
declare class Logger {
|
|
640
|
+
#private;
|
|
641
|
+
constructor(config?: LoggerConfig);
|
|
642
|
+
get level(): LogLevel;
|
|
643
|
+
setLevel(level: LogLevel): this;
|
|
644
|
+
isEnabled(level: Exclude<LogLevel, 'silent'>): boolean;
|
|
645
|
+
child(scope: string): Logger;
|
|
646
|
+
debug(message: string, context?: LogContext): void;
|
|
647
|
+
info(message: string, context?: LogContext): void;
|
|
648
|
+
warn(message: string, context?: LogContext): void;
|
|
649
|
+
error(message: string, context?: LogContext): void;
|
|
441
650
|
}
|
|
442
651
|
|
|
443
652
|
interface AppEvents {
|
|
@@ -480,6 +689,7 @@ declare class WhaNextApp {
|
|
|
480
689
|
readonly user: UserService;
|
|
481
690
|
readonly mute: MuteService;
|
|
482
691
|
readonly logger: Logger;
|
|
692
|
+
readonly commands: CommandRouter;
|
|
483
693
|
constructor(provider: WhatsAppProvider, options?: WhaNextAppOptions, logger?: Logger);
|
|
484
694
|
get state(): ConnectionUpdate['state'];
|
|
485
695
|
get isReady(): boolean;
|
|
@@ -517,6 +727,15 @@ interface CreateOptions {
|
|
|
517
727
|
}
|
|
518
728
|
declare function create(options?: CreateOptions): Promise<WhaNextApp>;
|
|
519
729
|
|
|
730
|
+
interface MemoryCacheStats {
|
|
731
|
+
size: number;
|
|
732
|
+
maxEntries: number;
|
|
733
|
+
hits: number;
|
|
734
|
+
misses: number;
|
|
735
|
+
sets: number;
|
|
736
|
+
evictions: number;
|
|
737
|
+
expirations: number;
|
|
738
|
+
}
|
|
520
739
|
declare class MemoryCache implements CacheStore {
|
|
521
740
|
#private;
|
|
522
741
|
constructor(options?: {
|
|
@@ -526,6 +745,8 @@ declare class MemoryCache implements CacheStore {
|
|
|
526
745
|
set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
527
746
|
delete(key: string): Promise<void>;
|
|
528
747
|
clear(): Promise<void>;
|
|
748
|
+
prune(now?: number): number;
|
|
749
|
+
stats(): Readonly<MemoryCacheStats>;
|
|
529
750
|
}
|
|
530
751
|
|
|
531
752
|
interface CommandRegistrar {
|
|
@@ -556,4 +777,4 @@ declare class SqliteMuteStore implements MuteStore {
|
|
|
556
777
|
close(): void;
|
|
557
778
|
}
|
|
558
779
|
|
|
559
|
-
export { type AddMuteOptions, type AddMuteResult, type AppEvents, type AppHealth, type AppHealthStatus, ArgsParser, type AudioContent, Browser, type CacheOptions, type CacheStore, type CallEvent, type CallStatus, type ChangeResult, type CommandDefinition, type CommandRegistrar, CommandRouter, type ConnectionState, type ConnectionUpdate, type CreateOptions, type DownloadedMedia, type GroupAccess, type GroupAddressingMode, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, 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 MentionTarget, type Message, type MessageContent, type MessageKey, type MessageMedia, type MuteChangeResult, type MuteEnforcement, type MuteOptions, type MuteRecord, MuteService, type MuteStore, type ParticipantUpdateResult, type PresenceState, type QuotedMessage, type ReconnectOptions, type RemoveMuteResult, type RouterOptions, type SentMessage, SqliteMuteStore, type StoredMute, type TextContent, User, type UserData, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, type WhatsAppProvider, create, defineCommand, defineCommands, loadCommands, toWhaNextError };
|
|
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 };
|