@whanext/core 0.19.16 → 0.19.19
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 +53 -0
- package/README.md +120 -6
- package/dist/index.d.ts +202 -2
- package/dist/index.js +815 -87
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.19.19
|
|
4
|
+
|
|
5
|
+
### Provider
|
|
6
|
+
- Updated the official provider from `zapo-js@1.7.1` to `zapo-js@1.8.0`.
|
|
7
|
+
- Kept full received LID/PN addressing metadata when replying, reacting, editing, revoking, and pinning messages.
|
|
8
|
+
- Inherits Zapo 1.8.0 mailbox `fromMe` persistence fixes, group-status stanza attribute unwrapping, username support, expired-CDN media resend support, and mobile-primary WhatsApp Business support.
|
|
9
|
+
|
|
10
|
+
### Incoming message observability
|
|
11
|
+
- Added `message_unavailable` tracking with primary-device resend correlation and a bounded 30-second recovery window.
|
|
12
|
+
- Added `debug_decrypted_payload` correlation with `debug_unhandled_stanza` so decrypted-but-undecodable payloads are visible without logging plaintext bytes.
|
|
13
|
+
- Expanded `health().messaging` with `decryptedPayloads`, `unavailable`, `resendRequested`, `recovered`, `recoveryFailed`, `unavailableUnrecoverable`, `decodeFailures`, `unhandledStanzas`, `ignoredOffline`, `duplicates`, and `normalizationFailures`.
|
|
14
|
+
- Added typed `messageUnavailable`, `messageRecovered`, `messageRecoveryFailed`, `messageDecodeFailure`, and `messageDiscarded` application events.
|
|
15
|
+
- Recovery failures and decrypted-payload decode failures temporarily mark provider stability as `degraded`; expected unrecoverable placeholders such as consumed view-once messages are counted without automatically degrading the session.
|
|
16
|
+
|
|
17
|
+
### Safety
|
|
18
|
+
- Raw decrypted payload bytes from Zapo are never emitted through the WhaNext public events or written to logs.
|
|
19
|
+
- Existing `received`, `sent`, and `failed` counters keep their previous semantics; the new counters explain why an inbound stanza may not have become a public WhaNext `Message`.
|
|
20
|
+
|
|
21
|
+
## 0.19.18
|
|
22
|
+
|
|
23
|
+
### Stability
|
|
24
|
+
- Added bounded command queues for `strategy: 'queue'`: `maxQueue` defaults to 10 waiting executions and `queueTimeoutMs` defaults to 60 seconds. Set either option to `0` to disable that limit.
|
|
25
|
+
- Added `COMMAND_QUEUE_FULL` and `COMMAND_QUEUE_TIMEOUT` with typed `commandQueueFull` and `commandQueueTimeout` application events.
|
|
26
|
+
- Added explicit Zapo transport/query timeouts through `providerTimeouts.connectTimeoutMs` and `providerTimeouts.nodeQueryTimeoutMs`, defaulting to 15 seconds and 30 seconds.
|
|
27
|
+
- Stability event listeners are isolated from provider recovery work so consumer handler failures cannot turn a successful metadata recovery into a provider failure.
|
|
28
|
+
|
|
29
|
+
### Health
|
|
30
|
+
- Expanded `app.health()` without removing the existing fields. It now exposes `stability`, connection/reconnect state, messaging counters, crypto degradation counters, group metadata recovery counters, command queue metrics, and effective provider timeouts.
|
|
31
|
+
- Added `healthy`, `degraded`, `reconnecting`, and `offline` operational stability states. Transient crypto/group warnings move the provider to `degraded` for a bounded window and automatically return it to `healthy`.
|
|
32
|
+
- Added typed `healthChanged`, `connectionRecovered`, `groupMetadataRecovered`, and `cryptoDegraded` events.
|
|
33
|
+
|
|
34
|
+
### Performance
|
|
35
|
+
- Added `@zapo-js/native@0.1.0` as an optional dependency. Zapo automatically uses its X25519/XEdDSA accelerator when available and falls back to JavaScript when unavailable.
|
|
36
|
+
- Health reports the detected crypto backend as `napi`, `wasm`, `js`, or `unknown`; the published optional package is detected as WASM on supported Node runtimes while locally built N-API addons are reported only when they can actually be loaded.
|
|
37
|
+
|
|
38
|
+
### Compatibility
|
|
39
|
+
- Existing command concurrency declarations remain valid; the queue limits only affect commands that already use `strategy: 'queue'`.
|
|
40
|
+
- Custom providers are not required to implement `health()`; WhaNext supplies neutral health fallbacks when a provider does not expose runtime metrics.
|
|
41
|
+
|
|
42
|
+
## 0.19.17
|
|
43
|
+
|
|
44
|
+
### Reliability
|
|
45
|
+
- Group sends now self-heal when Zapo reports an acknowledged participant-hash mismatch: WhaNext invalidates only the affected group's metadata cache, fetches fresh server metadata, invalidates the public group snapshot, and rate-limits recovery to once per group per minute.
|
|
46
|
+
- Volatile Zapo `groupMetadata` and `deviceList` memory caches now expire after 3 minutes instead of the 5-minute default, reducing stale LID/device fan-out windows without disabling caching or forcing an IQ/usync on every send.
|
|
47
|
+
- Transient WhatsApp disconnects now retry indefinitely by default with the existing exponential backoff; applications that set `reconnect.maxAttempts` keep their explicit limit. Fatal/logout reasons still stop reconnection immediately.
|
|
48
|
+
|
|
49
|
+
### Performance
|
|
50
|
+
- The shared Zapo SQLite store now uses `WAL`, `synchronous=NORMAL`, and a 5-second `busy_timeout`, improving concurrent reads/writes for persisted Signal, sender-key, mailbox, and app-state data.
|
|
51
|
+
- The WhaNext mutation-snapshot SQLite database now uses the same WAL/NORMAL settings, reducing fsync contention on active bots.
|
|
52
|
+
|
|
53
|
+
### Safety
|
|
54
|
+
- Sender keys and Signal sessions are never globally reset during mismatch recovery. Zapo's normal retry-receipt/decryption recovery remains authoritative; WhaNext only refreshes stale group metadata.
|
|
55
|
+
|
|
3
56
|
## 0.19.16
|
|
4
57
|
|
|
5
58
|
### Fixed
|
package/README.md
CHANGED
|
@@ -311,20 +311,41 @@ const app = await create({
|
|
|
311
311
|
|
|
312
312
|
## Health checks
|
|
313
313
|
|
|
314
|
-
`app.health()` entrega um snapshot sem consultar o WhatsApp novamente:
|
|
314
|
+
`app.health()` entrega um snapshot local e barato, sem consultar o WhatsApp novamente. Os campos antigos permanecem disponíveis e a camada de estabilidade acrescenta conexão, mensagens, crypto, grupos, filas e timeouts:
|
|
315
315
|
|
|
316
316
|
```ts
|
|
317
317
|
const health = app.health();
|
|
318
318
|
|
|
319
319
|
console.log(health.status);
|
|
320
|
+
console.log(health.stability);
|
|
320
321
|
console.log(health.ready);
|
|
321
322
|
console.log(health.state);
|
|
322
323
|
console.log(health.uptimeMs);
|
|
323
|
-
console.log(health.
|
|
324
|
-
console.log(health.
|
|
324
|
+
console.log(health.connection);
|
|
325
|
+
console.log(health.messaging);
|
|
326
|
+
console.log(health.crypto);
|
|
327
|
+
console.log(health.groups);
|
|
328
|
+
console.log(health.commands);
|
|
329
|
+
console.log(health.timeouts);
|
|
325
330
|
```
|
|
326
331
|
|
|
327
|
-
|
|
332
|
+
`status` continua representando o ciclo da aplicação: `idle`, `starting`, `ready` ou `stopped`. `stability` representa a saúde operacional do provider: `healthy`, `degraded`, `reconnecting` ou `offline`.
|
|
333
|
+
|
|
334
|
+
O provider Zapo contabiliza reconexões, mensagens enviadas/recebidas, falhas de envio, falhas de descriptografia, `sender key id mismatch`, falhas de addons, divergências de `phash` e recuperações de metadata. Com Zapo 1.8.0, `health.messaging` também mostra mensagens indisponíveis, pedidos de resend, recuperações, payloads descriptografados, falhas de decode, stanzas não tratadas, duplicatas, mensagens offline ignoradas e falhas de normalização. O router contabiliza execuções ativas, fila atual, expirações e rejeições por fila cheia.
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
const { messaging } = app.health();
|
|
338
|
+
|
|
339
|
+
console.log(messaging.unavailable);
|
|
340
|
+
console.log(messaging.resendRequested);
|
|
341
|
+
console.log(messaging.recovered);
|
|
342
|
+
console.log(messaging.recoveryFailed);
|
|
343
|
+
console.log(messaging.decodeFailures);
|
|
344
|
+
console.log(messaging.ignoredOffline);
|
|
345
|
+
console.log(messaging.duplicates);
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
`decryptedPayloads` conta payloads `<enc>` individuais, portanto pode ser maior que `received` em fanout para vários devices. O WhaNext usa esse sinal apenas para correlação e nunca expõe os bytes descriptografados no health, eventos públicos ou logs.
|
|
328
349
|
|
|
329
350
|
```ts
|
|
330
351
|
server.get('/health', async () => app.health());
|
|
@@ -333,11 +354,87 @@ server.get('/health', async () => app.health());
|
|
|
333
354
|
Para uma verificação simples:
|
|
334
355
|
|
|
335
356
|
```ts
|
|
336
|
-
if (app.isReady) {
|
|
337
|
-
console.log('Aplicação pronta.');
|
|
357
|
+
if (app.isReady && app.health().stability === 'healthy') {
|
|
358
|
+
console.log('Aplicação pronta e saudável.');
|
|
338
359
|
}
|
|
339
360
|
```
|
|
340
361
|
|
|
362
|
+
## Estabilidade do provider
|
|
363
|
+
|
|
364
|
+
O provider oficial usa timeouts explícitos para conexão e queries de protocolo. Os padrões são 15 segundos para conexão e 30 segundos para queries; ambos podem ser ajustados na criação da aplicação:
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
const app = await create({
|
|
368
|
+
providerTimeouts: {
|
|
369
|
+
connectTimeoutMs: 15_000,
|
|
370
|
+
nodeQueryTimeoutMs: 30_000,
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Valores menores que 1 segundo são normalizados para 1 segundo. Os valores efetivos ficam disponíveis em `app.health().timeouts`.
|
|
376
|
+
|
|
377
|
+
A aceleração crypto do Zapo também é integrada de forma opcional. `@zapo-js/native` acelera X25519 e XEdDSA e o provider continua funcionando com o backend JavaScript caso o acelerador não esteja disponível. O pacote publicado usa WASM; um build N-API local também é detectado quando realmente carregável.
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
const health = app.health();
|
|
381
|
+
|
|
382
|
+
console.log(health.crypto.backend);
|
|
383
|
+
console.log(health.crypto.acceleration);
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Backends reportados: `napi`, `wasm`, `js` ou `unknown`. Para forçar o fallback JavaScript, inicie o processo com `ZAPO_NATIVE_BACKEND=js`.
|
|
387
|
+
|
|
388
|
+
A aplicação expõe eventos tipados para observabilidade sem parsing de logs:
|
|
389
|
+
|
|
390
|
+
```ts
|
|
391
|
+
app.on('healthChanged', ({ previous, current }) => {
|
|
392
|
+
console.log(previous, current);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
app.on('connectionRecovered', ({ recoveredAt, reconnects }) => {
|
|
396
|
+
console.log(recoveredAt, reconnects);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
app.on('groupMetadataRecovered', ({ groupId }) => {
|
|
400
|
+
console.log(groupId);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
app.on('cryptoDegraded', ({ kind, chatId }) => {
|
|
404
|
+
console.log(kind, chatId);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
app.on('messageUnavailable', ({ messageId, resendRequested }) => {
|
|
408
|
+
console.log(messageId, resendRequested);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
app.on('messageRecovered', ({ messageId, recoveryMs }) => {
|
|
412
|
+
console.log(messageId, recoveryMs);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
app.on('messageRecoveryFailed', ({ messageId, waitedMs }) => {
|
|
416
|
+
console.log(messageId, waitedMs);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
app.on('messageDecodeFailure', ({ stanzaId, reason }) => {
|
|
420
|
+
console.log(stanzaId, reason);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
app.on('messageDiscarded', ({ messageId, reason }) => {
|
|
424
|
+
console.log(messageId, reason);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
app.on('commandQueueTimeout', ({ command, queuedForMs }) => {
|
|
428
|
+
console.log(command, queuedForMs);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
app.on('commandQueueFull', ({ command, queued }) => {
|
|
432
|
+
console.log(command, queued);
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Falhas criptográficas transitórias deixam o provider em `degraded` por uma janela curta; a volta para `healthy` também dispara `healthChanged`. A recuperação de metadata por `phash` continua específica ao grupo afetado e não apaga Sender Keys nem sessões Signal.
|
|
437
|
+
|
|
341
438
|
## Usuários
|
|
342
439
|
|
|
343
440
|
Toda mensagem possui `message.sender: User`. Menções ficam em `message.mentionedUsers`, e o remetente de um reply em `message.quoted?.sender`.
|
|
@@ -697,6 +794,8 @@ app.commands.command(
|
|
|
697
794
|
scope: 'chat',
|
|
698
795
|
max: 1,
|
|
699
796
|
strategy: 'queue',
|
|
797
|
+
maxQueue: 10,
|
|
798
|
+
queueTimeoutMs: 60_000,
|
|
700
799
|
},
|
|
701
800
|
|
|
702
801
|
async execute(ctx) {
|
|
@@ -715,6 +814,21 @@ app.commands.command(
|
|
|
715
814
|
);
|
|
716
815
|
```
|
|
717
816
|
|
|
817
|
+
Para `strategy: 'queue'`, o WhaNext limita por padrão a fila a 10 execuções aguardando e cada entrada pode esperar até 60 segundos. `maxQueue: 0` remove o limite de quantidade e `queueTimeoutMs: 0` remove o timeout. Quando os limites são atingidos, o router usa `COMMAND_QUEUE_FULL` ou `COMMAND_QUEUE_TIMEOUT` e emite os eventos tipados correspondentes.
|
|
818
|
+
|
|
819
|
+
```ts
|
|
820
|
+
app.commands.onError(async (ctx, error) => {
|
|
821
|
+
if (error.code === 'COMMAND_QUEUE_FULL') {
|
|
822
|
+
await ctx.reply('Muitos comandos estão aguardando. Tente novamente em instantes.');
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if (error.code === 'COMMAND_QUEUE_TIMEOUT') {
|
|
827
|
+
await ctx.reply('A fila demorou demais. Envie o comando novamente.');
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
```
|
|
831
|
+
|
|
718
832
|
### Comandos exclusivos do dono
|
|
719
833
|
|
|
720
834
|
O dono é a própria conta conectada naquela aplicação. Não é necessário salvar número, JID ou LID manualmente. O provider usa a marca de mensagem enviada pela própria conta e, quando necessário, compara as identidades normalizadas da sessão.
|
package/dist/index.d.ts
CHANGED
|
@@ -289,6 +289,8 @@ interface CallEvent {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
type ConnectionState = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'closed';
|
|
292
|
+
type StabilityHealthStatus = 'healthy' | 'degraded' | 'reconnecting' | 'offline';
|
|
293
|
+
type CryptoAccelerationBackend = 'napi' | 'wasm' | 'js' | 'unknown';
|
|
292
294
|
type PresenceState = 'typing' | 'recording' | 'paused';
|
|
293
295
|
type ParticipantAction = 'remove' | 'promote' | 'demote';
|
|
294
296
|
interface ParticipantUpdateResult {
|
|
@@ -301,6 +303,131 @@ interface ConnectionUpdate {
|
|
|
301
303
|
attempt?: number;
|
|
302
304
|
error?: Error;
|
|
303
305
|
}
|
|
306
|
+
interface ProviderConnectionHealth {
|
|
307
|
+
state: ConnectionState;
|
|
308
|
+
uptimeMs: number;
|
|
309
|
+
reconnects: number;
|
|
310
|
+
reconnectAttempt: number;
|
|
311
|
+
lastConnectedAt?: Date;
|
|
312
|
+
lastDisconnectedAt?: Date;
|
|
313
|
+
}
|
|
314
|
+
interface ProviderMessagingHealth {
|
|
315
|
+
sent: number;
|
|
316
|
+
received: number;
|
|
317
|
+
failed: number;
|
|
318
|
+
decryptedPayloads: number;
|
|
319
|
+
unavailable: number;
|
|
320
|
+
resendRequested: number;
|
|
321
|
+
recovered: number;
|
|
322
|
+
recoveryFailed: number;
|
|
323
|
+
unavailableUnrecoverable: number;
|
|
324
|
+
decodeFailures: number;
|
|
325
|
+
unhandledStanzas: number;
|
|
326
|
+
ignoredOffline: number;
|
|
327
|
+
duplicates: number;
|
|
328
|
+
normalizationFailures: number;
|
|
329
|
+
lastIncomingAt?: Date;
|
|
330
|
+
lastOutgoingAt?: Date;
|
|
331
|
+
}
|
|
332
|
+
interface ProviderCryptoHealth {
|
|
333
|
+
backend: CryptoAccelerationBackend;
|
|
334
|
+
acceleration: boolean;
|
|
335
|
+
decryptFailures: number;
|
|
336
|
+
addonDecryptFailures: number;
|
|
337
|
+
senderKeyMismatches: number;
|
|
338
|
+
}
|
|
339
|
+
interface ProviderGroupHealth {
|
|
340
|
+
phashMismatches: number;
|
|
341
|
+
metadataRecoveries: number;
|
|
342
|
+
metadataRecoveryFailures: number;
|
|
343
|
+
}
|
|
344
|
+
interface ProviderTimeoutHealth {
|
|
345
|
+
connectTimeoutMs: number;
|
|
346
|
+
nodeQueryTimeoutMs: number;
|
|
347
|
+
}
|
|
348
|
+
interface ProviderHealth {
|
|
349
|
+
stability: StabilityHealthStatus;
|
|
350
|
+
connection: ProviderConnectionHealth;
|
|
351
|
+
messaging: ProviderMessagingHealth;
|
|
352
|
+
crypto: ProviderCryptoHealth;
|
|
353
|
+
groups: ProviderGroupHealth;
|
|
354
|
+
timeouts: ProviderTimeoutHealth;
|
|
355
|
+
}
|
|
356
|
+
interface GroupMetadataRecoveredEvent {
|
|
357
|
+
groupId: string;
|
|
358
|
+
recoveredAt: Date;
|
|
359
|
+
}
|
|
360
|
+
type CryptoDegradationKind = 'decrypt_failure' | 'addon_decrypt_failure' | 'sender_key_mismatch';
|
|
361
|
+
interface CryptoDegradedEvent {
|
|
362
|
+
kind: CryptoDegradationKind;
|
|
363
|
+
occurredAt: Date;
|
|
364
|
+
messageId?: string;
|
|
365
|
+
chatId?: string;
|
|
366
|
+
participantId?: string;
|
|
367
|
+
}
|
|
368
|
+
interface MessageUnavailableEvent {
|
|
369
|
+
kind: 'view_once' | 'hosted' | 'bot' | 'other';
|
|
370
|
+
resendRequested: boolean;
|
|
371
|
+
occurredAt: Date;
|
|
372
|
+
messageId?: string;
|
|
373
|
+
chatId?: string;
|
|
374
|
+
participantId?: string;
|
|
375
|
+
}
|
|
376
|
+
interface MessageRecoveredEvent {
|
|
377
|
+
recoveredAt: Date;
|
|
378
|
+
recoveryMs: number;
|
|
379
|
+
messageId?: string;
|
|
380
|
+
chatId?: string;
|
|
381
|
+
participantId?: string;
|
|
382
|
+
}
|
|
383
|
+
interface MessageRecoveryFailedEvent {
|
|
384
|
+
failedAt: Date;
|
|
385
|
+
waitedMs: number;
|
|
386
|
+
messageId?: string;
|
|
387
|
+
chatId?: string;
|
|
388
|
+
participantId?: string;
|
|
389
|
+
}
|
|
390
|
+
interface MessageDecodeFailureEvent {
|
|
391
|
+
occurredAt: Date;
|
|
392
|
+
reason: string;
|
|
393
|
+
stanzaId?: string;
|
|
394
|
+
chatId?: string;
|
|
395
|
+
encType?: string;
|
|
396
|
+
}
|
|
397
|
+
type MessageDiscardReason = 'offline' | 'duplicate' | 'normalization_failed';
|
|
398
|
+
interface MessageDiscardedEvent {
|
|
399
|
+
reason: MessageDiscardReason;
|
|
400
|
+
occurredAt: Date;
|
|
401
|
+
messageId?: string;
|
|
402
|
+
chatId?: string;
|
|
403
|
+
}
|
|
404
|
+
type ProviderStabilityEvent = {
|
|
405
|
+
type: 'groupMetadataRecovered';
|
|
406
|
+
payload: GroupMetadataRecoveredEvent;
|
|
407
|
+
} | {
|
|
408
|
+
type: 'cryptoDegraded';
|
|
409
|
+
payload: CryptoDegradedEvent;
|
|
410
|
+
} | {
|
|
411
|
+
type: 'messageUnavailable';
|
|
412
|
+
payload: MessageUnavailableEvent;
|
|
413
|
+
} | {
|
|
414
|
+
type: 'messageRecovered';
|
|
415
|
+
payload: MessageRecoveredEvent;
|
|
416
|
+
} | {
|
|
417
|
+
type: 'messageRecoveryFailed';
|
|
418
|
+
payload: MessageRecoveryFailedEvent;
|
|
419
|
+
} | {
|
|
420
|
+
type: 'messageDecodeFailure';
|
|
421
|
+
payload: MessageDecodeFailureEvent;
|
|
422
|
+
} | {
|
|
423
|
+
type: 'messageDiscarded';
|
|
424
|
+
payload: MessageDiscardedEvent;
|
|
425
|
+
} | {
|
|
426
|
+
type: 'healthRefresh';
|
|
427
|
+
payload: {
|
|
428
|
+
occurredAt: Date;
|
|
429
|
+
};
|
|
430
|
+
};
|
|
304
431
|
interface ProviderEvents {
|
|
305
432
|
message: Message;
|
|
306
433
|
messageDeleted: MessageDeleted;
|
|
@@ -311,6 +438,7 @@ interface ProviderEvents {
|
|
|
311
438
|
};
|
|
312
439
|
groupParticipantsChanged: GroupParticipantsChanged;
|
|
313
440
|
call: CallEvent;
|
|
441
|
+
stability: ProviderStabilityEvent;
|
|
314
442
|
}
|
|
315
443
|
type Unsubscribe = () => void;
|
|
316
444
|
interface WhatsAppProvider {
|
|
@@ -319,6 +447,7 @@ interface WhatsAppProvider {
|
|
|
319
447
|
getCurrentUserIds(): string[];
|
|
320
448
|
requestPairingCode(phone: string): Promise<string>;
|
|
321
449
|
on<Event extends keyof ProviderEvents>(event: Event, listener: (payload: ProviderEvents[Event]) => void | Promise<void>): Unsubscribe;
|
|
450
|
+
health?(): ProviderHealth;
|
|
322
451
|
sendMessage(chatId: string, content: MessageContent, replyTo?: MessageKey): Promise<SentMessage>;
|
|
323
452
|
repostMessage(source: MessageKey, chatId: string, options?: RepostMessageOptions): Promise<SentMessage>;
|
|
324
453
|
reactToMessage(key: MessageKey, emoji?: string): Promise<SentMessage>;
|
|
@@ -616,7 +745,7 @@ declare class DeferredReply {
|
|
|
616
745
|
delete(): Promise<void>;
|
|
617
746
|
}
|
|
618
747
|
|
|
619
|
-
type WhaNextErrorCode = 'AUTH_INVALID_PHONE' | 'AUTH_EXPIRED' | 'AUTH_PASSKEY_REQUIRED' | 'CONNECTION_CLOSED' | 'CONNECTION_FAILED' | 'GROUP_NOT_FOUND' | 'MEMBER_NOT_FOUND' | 'BOT_NOT_ADMIN' | 'MESSAGE_NOT_FOUND' | 'MEDIA_NOT_AVAILABLE' | 'MESSAGE_REACHOUT_LOCKED' | 'MUTE_DISABLED' | 'STORAGE_ERROR' | 'ARGUMENT_MISSING' | 'ARGUMENT_INVALID' | 'COMMAND_NOT_ALLOWED' | 'COMMAND_COOLDOWN' | 'COMMAND_BUSY' | 'COMMAND_LOAD_FAILED' | 'PROVIDER_ERROR' | 'UNKNOWN_ERROR';
|
|
748
|
+
type WhaNextErrorCode = 'AUTH_INVALID_PHONE' | 'AUTH_EXPIRED' | 'AUTH_PASSKEY_REQUIRED' | 'CONNECTION_CLOSED' | 'CONNECTION_FAILED' | 'GROUP_NOT_FOUND' | 'MEMBER_NOT_FOUND' | 'BOT_NOT_ADMIN' | 'MESSAGE_NOT_FOUND' | 'MEDIA_NOT_AVAILABLE' | 'MESSAGE_REACHOUT_LOCKED' | 'MUTE_DISABLED' | 'STORAGE_ERROR' | 'ARGUMENT_MISSING' | 'ARGUMENT_INVALID' | 'COMMAND_NOT_ALLOWED' | 'COMMAND_COOLDOWN' | 'COMMAND_BUSY' | 'COMMAND_QUEUE_FULL' | 'COMMAND_QUEUE_TIMEOUT' | 'COMMAND_LOAD_FAILED' | 'PROVIDER_ERROR' | 'UNKNOWN_ERROR';
|
|
620
749
|
interface WhaNextErrorOptions {
|
|
621
750
|
cause?: unknown;
|
|
622
751
|
context?: Readonly<Record<string, unknown>>;
|
|
@@ -656,6 +785,8 @@ interface CommandConcurrency {
|
|
|
656
785
|
max?: number;
|
|
657
786
|
scope?: CommandScope;
|
|
658
787
|
strategy?: ConcurrencyStrategy;
|
|
788
|
+
maxQueue?: number;
|
|
789
|
+
queueTimeoutMs?: number;
|
|
659
790
|
}
|
|
660
791
|
interface CommandLocalization {
|
|
661
792
|
name?: string;
|
|
@@ -710,6 +841,37 @@ declare function defineCommandGroup<const Group extends CommandGroupDefinition>(
|
|
|
710
841
|
declare function defineCommands<const Commands extends readonly CommandDefinition[]>(...commands: Commands): Commands;
|
|
711
842
|
declare function isCommandGroup(definition: CommandDefinition): definition is CommandGroupDefinition;
|
|
712
843
|
|
|
844
|
+
interface CommandConcurrencyContext {
|
|
845
|
+
command: string;
|
|
846
|
+
messageId: string;
|
|
847
|
+
chatId: string;
|
|
848
|
+
userId: string;
|
|
849
|
+
}
|
|
850
|
+
interface CommandQueueTimeoutEvent extends CommandConcurrencyContext {
|
|
851
|
+
key: string;
|
|
852
|
+
queuedForMs: number;
|
|
853
|
+
queueTimeoutMs: number;
|
|
854
|
+
queued: number;
|
|
855
|
+
}
|
|
856
|
+
interface CommandQueueFullEvent extends CommandConcurrencyContext {
|
|
857
|
+
key: string;
|
|
858
|
+
maxQueue: number;
|
|
859
|
+
queued: number;
|
|
860
|
+
}
|
|
861
|
+
interface CommandConcurrencyHealth {
|
|
862
|
+
running: number;
|
|
863
|
+
queued: number;
|
|
864
|
+
queueTimeouts: number;
|
|
865
|
+
queueRejected: number;
|
|
866
|
+
}
|
|
867
|
+
type CommandConcurrencyEvent = {
|
|
868
|
+
type: 'commandQueueTimeout';
|
|
869
|
+
payload: CommandQueueTimeoutEvent;
|
|
870
|
+
} | {
|
|
871
|
+
type: 'commandQueueFull';
|
|
872
|
+
payload: CommandQueueFullEvent;
|
|
873
|
+
};
|
|
874
|
+
|
|
713
875
|
interface CommandRegistrar {
|
|
714
876
|
command(definition: CommandDefinition): unknown;
|
|
715
877
|
}
|
|
@@ -743,6 +905,10 @@ interface CommandHelpOptions extends CommandCatalogOptions {
|
|
|
743
905
|
title?: string;
|
|
744
906
|
}
|
|
745
907
|
type CommandErrorHandler = (context: CommandContext, error: WhaNextError) => void | Promise<void>;
|
|
908
|
+
interface CommandRouterEvents {
|
|
909
|
+
commandQueueTimeout: CommandQueueTimeoutEvent;
|
|
910
|
+
commandQueueFull: CommandQueueFullEvent;
|
|
911
|
+
}
|
|
746
912
|
declare class CommandRouter {
|
|
747
913
|
#private;
|
|
748
914
|
constructor(services: CommandRuntimeServices, options?: RouterOptions);
|
|
@@ -751,6 +917,8 @@ declare class CommandRouter {
|
|
|
751
917
|
get prefixes(): readonly string[];
|
|
752
918
|
setPrefixes(prefixes: string | readonly string[]): this;
|
|
753
919
|
get size(): number;
|
|
920
|
+
health(): CommandConcurrencyHealth;
|
|
921
|
+
on<Event extends keyof CommandRouterEvents>(event: Event, listener: (payload: CommandRouterEvents[Event]) => void | Promise<void>): () => void;
|
|
754
922
|
command(definition: CommandDefinition): this;
|
|
755
923
|
load(dirPath: string | URL, options?: LoadCommandsOptions): Promise<LoadCommandsResult>;
|
|
756
924
|
use(middleware: CommandMiddleware): this;
|
|
@@ -808,6 +976,15 @@ declare class AccountService {
|
|
|
808
976
|
isOwner(message: Pick<Message, 'keys' | 'senderIds'>): boolean;
|
|
809
977
|
}
|
|
810
978
|
|
|
979
|
+
interface HealthChangedEvent {
|
|
980
|
+
previous: StabilityHealthStatus;
|
|
981
|
+
current: StabilityHealthStatus;
|
|
982
|
+
health: AppHealth;
|
|
983
|
+
}
|
|
984
|
+
interface ConnectionRecoveredEvent {
|
|
985
|
+
recoveredAt: Date;
|
|
986
|
+
reconnects: number;
|
|
987
|
+
}
|
|
811
988
|
interface AppEvents {
|
|
812
989
|
message: Message;
|
|
813
990
|
messageDeleted: MessageDeleted;
|
|
@@ -817,6 +994,17 @@ interface AppEvents {
|
|
|
817
994
|
mute: MuteEnforcement;
|
|
818
995
|
call: CallEvent;
|
|
819
996
|
groupParticipantsChanged: GroupParticipantsChanged;
|
|
997
|
+
healthChanged: HealthChangedEvent;
|
|
998
|
+
connectionRecovered: ConnectionRecoveredEvent;
|
|
999
|
+
groupMetadataRecovered: GroupMetadataRecoveredEvent;
|
|
1000
|
+
cryptoDegraded: CryptoDegradedEvent;
|
|
1001
|
+
messageUnavailable: MessageUnavailableEvent;
|
|
1002
|
+
messageRecovered: MessageRecoveredEvent;
|
|
1003
|
+
messageRecoveryFailed: MessageRecoveryFailedEvent;
|
|
1004
|
+
messageDecodeFailure: MessageDecodeFailureEvent;
|
|
1005
|
+
messageDiscarded: MessageDiscardedEvent;
|
|
1006
|
+
commandQueueTimeout: CommandQueueTimeoutEvent;
|
|
1007
|
+
commandQueueFull: CommandQueueFullEvent;
|
|
820
1008
|
}
|
|
821
1009
|
interface LoginOptions {
|
|
822
1010
|
onCode?: (code: string) => void | Promise<void>;
|
|
@@ -825,12 +1013,19 @@ interface LoginOptions {
|
|
|
825
1013
|
type AppHealthStatus = 'idle' | 'starting' | 'ready' | 'stopped';
|
|
826
1014
|
interface AppHealth {
|
|
827
1015
|
status: AppHealthStatus;
|
|
1016
|
+
stability: StabilityHealthStatus;
|
|
828
1017
|
state: ConnectionUpdate['state'];
|
|
829
1018
|
ready: boolean;
|
|
830
1019
|
uptimeMs: number;
|
|
831
1020
|
timestamp: Date;
|
|
832
1021
|
muteEnabled: boolean;
|
|
833
1022
|
logLevel: LogLevel;
|
|
1023
|
+
connection: ProviderConnectionHealth;
|
|
1024
|
+
messaging: ProviderMessagingHealth;
|
|
1025
|
+
crypto: ProviderCryptoHealth;
|
|
1026
|
+
groups: ProviderGroupHealth;
|
|
1027
|
+
commands: CommandConcurrencyHealth;
|
|
1028
|
+
timeouts: ProviderTimeoutHealth;
|
|
834
1029
|
}
|
|
835
1030
|
interface WhaNextAppOptions {
|
|
836
1031
|
phone?: string;
|
|
@@ -869,6 +1064,10 @@ declare enum Browser {
|
|
|
869
1064
|
Ubuntu = "ubuntu"
|
|
870
1065
|
}
|
|
871
1066
|
|
|
1067
|
+
interface ProviderTimeoutOptions {
|
|
1068
|
+
connectTimeoutMs?: number;
|
|
1069
|
+
nodeQueryTimeoutMs?: number;
|
|
1070
|
+
}
|
|
872
1071
|
interface ReconnectOptions {
|
|
873
1072
|
enabled?: boolean;
|
|
874
1073
|
maxAttempts?: number;
|
|
@@ -885,6 +1084,7 @@ interface CreateOptions {
|
|
|
885
1084
|
mute?: MuteOptions;
|
|
886
1085
|
router?: Omit<RouterOptions, 'prefix'>;
|
|
887
1086
|
reconnect?: ReconnectOptions;
|
|
1087
|
+
providerTimeouts?: ProviderTimeoutOptions;
|
|
888
1088
|
messageCacheSize?: number;
|
|
889
1089
|
processOfflineMessages?: boolean;
|
|
890
1090
|
provider?: WhatsAppProvider;
|
|
@@ -972,4 +1172,4 @@ declare class SqliteMuteStore implements MuteStore {
|
|
|
972
1172
|
close(): void;
|
|
973
1173
|
}
|
|
974
1174
|
|
|
975
|
-
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 InteractiveResponse, type InteractiveResponseKind, type InviteResult, type LinkButton, type ListContent, type ListRow, type ListSection, 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 MessageEdited, type MessageKey, type MessageMedia, type MessagePayloadKind, type MessageProtocolKind, 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 PollContent, type PresenceState, type QuickReplyButton, 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 };
|
|
1175
|
+
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 CommandConcurrencyContext, type CommandConcurrencyEvent, type CommandConcurrencyHealth, 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 CommandQueueFullEvent, type CommandQueueTimeoutEvent, type CommandRegistrar, CommandRouter, type CommandRouterEvents, type CommandRuntimeServices, type CommandScope, type ConcurrencyStrategy, type ConnectionRecoveredEvent, type ConnectionState, type ConnectionUpdate, type CopyCodeButton, type CreateMultiOptions, type CreateOptions, type CryptoAccelerationBackend, type CryptoDegradationKind, type CryptoDegradedEvent, DeferredReply, type DownloadedMedia, type DurationOption, type EnumOption, type ExecutableCommandDefinition, type GroupAccess, type GroupAddressingMode, type GroupMetadataRecoveredEvent, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, type GuardResult, type HealthChangedEvent, type ImageContent, type InteractiveResponse, type InteractiveResponseKind, type InviteResult, type LinkButton, type ListContent, type ListRow, type ListSection, 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 MessageDecodeFailureEvent, type MessageDeleted, type MessageDiscardReason, type MessageDiscardedEvent, type MessageEdited, type MessageKey, type MessageMedia, type MessagePayloadKind, type MessageProtocolKind, type MessageRecoveredEvent, type MessageRecoveryFailedEvent, type MessageUnavailableEvent, 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 PollContent, type PresenceState, type ProviderConnectionHealth, type ProviderCryptoHealth, type ProviderGroupHealth, type ProviderHealth, type ProviderMessagingHealth, type ProviderStabilityEvent, type ProviderTimeoutHealth, type ProviderTimeoutOptions, type QuickReplyButton, type QuotedMessage, type ReconnectOptions, type RegisteredCommand, type RemoveMuteResult, type ReplyOptions, type RepostMessageOptions, type RouterOptions, type SentMessage, SqliteMuteStore, type StabilityHealthStatus, 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 };
|