@whanext/core 0.19.18 → 0.19.20

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 CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.19.20
4
+
5
+ ### Ingress diagnostics
6
+ - Added opt-in provider ingress tracing with `providerDiagnostics.ingress`, correlating Zapo transport message stanzas through decrypt and terminal provider events without logging message content or decrypted bytes.
7
+ - Added a bounded ingress watchdog through `providerDiagnostics.ingressStallTimeoutMs`, defaulting to 10 seconds. A decoded `<message>` stanza that never becomes `message`, `message_unavailable`, a decode failure, or a decrypt failure emits `messageIngressStalled` and temporarily marks the provider as degraded.
8
+ - Added transport decode diagnostics from Zapo 1.8.0 `debug_transport_decode_error` with a typed `transportDecodeFailure` event. Only frame size and error metadata are exposed; raw frame bytes are never logged or emitted.
9
+ - Expanded `health().messaging` with `transportFramesIn`, `transportNodesIn`, `transportDecodeErrors`, `messageStanzasIn`, and `ingressStalls`.
10
+ - When ingress diagnostics are enabled, message stanzas log their stanza id, chat, participant, addressing mode, encryption types, decrypt stage, and terminal provider stage. Message text and plaintext payloads are never included.
11
+
12
+ ### Reliability
13
+ - Correlates decrypt warnings with pending message stanzas so known Signal failures do not appear as generic ingress stalls.
14
+ - Normalizes device-qualified PN/LID JIDs before ingress correlation, keeping group and direct-message diagnostics aligned with Zapo message keys.
15
+
16
+ ## 0.19.19
17
+
18
+ ### Provider
19
+ - Updated the official provider from `zapo-js@1.7.1` to `zapo-js@1.8.0`.
20
+ - Kept full received LID/PN addressing metadata when replying, reacting, editing, revoking, and pinning messages.
21
+ - 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.
22
+
23
+ ### Incoming message observability
24
+ - Added `message_unavailable` tracking with primary-device resend correlation and a bounded 30-second recovery window.
25
+ - Added `debug_decrypted_payload` correlation with `debug_unhandled_stanza` so decrypted-but-undecodable payloads are visible without logging plaintext bytes.
26
+ - Expanded `health().messaging` with `decryptedPayloads`, `unavailable`, `resendRequested`, `recovered`, `recoveryFailed`, `unavailableUnrecoverable`, `decodeFailures`, `unhandledStanzas`, `ignoredOffline`, `duplicates`, and `normalizationFailures`.
27
+ - Added typed `messageUnavailable`, `messageRecovered`, `messageRecoveryFailed`, `messageDecodeFailure`, and `messageDiscarded` application events.
28
+ - 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.
29
+
30
+ ### Safety
31
+ - Raw decrypted payload bytes from Zapo are never emitted through the WhaNext public events or written to logs.
32
+ - 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`.
33
+
3
34
  ## 0.19.18
4
35
 
5
36
  ### Stability
package/README.md CHANGED
@@ -331,7 +331,34 @@ console.log(health.timeouts);
331
331
 
332
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
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. O router contabiliza execuções ativas, fila atual, expirações e rejeições por fila cheia.
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.
349
+
350
+ Para diagnosticar mensagens que chegam ao socket mas não viram um `Message` público, ative a trilha de ingresso:
351
+
352
+ ```ts
353
+ const app = await create({
354
+ providerDiagnostics: {
355
+ ingress: true,
356
+ ingressStallTimeoutMs: 10_000,
357
+ },
358
+ });
359
+ ```
360
+
361
+ Com essa opção, o provider registra apenas metadados seguros de stanzas `<message>` e correlaciona `debug_transport_node_in`, `debug_decrypted_payload`, `message`, `message_unavailable`, falhas de decrypt e falhas de decode. `health().messaging` também expõe `transportFramesIn`, `transportNodesIn`, `transportDecodeErrors`, `messageStanzasIn` e `ingressStalls`. Frames brutos, bytes descriptografados e texto das mensagens nunca são escritos nos logs.
335
362
 
336
363
  ```ts
337
364
  server.get('/health', async () => app.health());
@@ -390,6 +417,26 @@ app.on('cryptoDegraded', ({ kind, chatId }) => {
390
417
  console.log(kind, chatId);
391
418
  });
392
419
 
420
+ app.on('messageUnavailable', ({ messageId, resendRequested }) => {
421
+ console.log(messageId, resendRequested);
422
+ });
423
+
424
+ app.on('messageRecovered', ({ messageId, recoveryMs }) => {
425
+ console.log(messageId, recoveryMs);
426
+ });
427
+
428
+ app.on('messageRecoveryFailed', ({ messageId, waitedMs }) => {
429
+ console.log(messageId, waitedMs);
430
+ });
431
+
432
+ app.on('messageDecodeFailure', ({ stanzaId, reason }) => {
433
+ console.log(stanzaId, reason);
434
+ });
435
+
436
+ app.on('messageDiscarded', ({ messageId, reason }) => {
437
+ console.log(messageId, reason);
438
+ });
439
+
393
440
  app.on('commandQueueTimeout', ({ command, queuedForMs }) => {
394
441
  console.log(command, queuedForMs);
395
442
  });
package/dist/index.d.ts CHANGED
@@ -315,6 +315,22 @@ interface ProviderMessagingHealth {
315
315
  sent: number;
316
316
  received: number;
317
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
+ transportFramesIn: number;
330
+ transportNodesIn: number;
331
+ transportDecodeErrors: number;
332
+ messageStanzasIn: number;
333
+ ingressStalls: number;
318
334
  lastIncomingAt?: Date;
319
335
  lastOutgoingAt?: Date;
320
336
  }
@@ -354,12 +370,86 @@ interface CryptoDegradedEvent {
354
370
  chatId?: string;
355
371
  participantId?: string;
356
372
  }
373
+ interface MessageUnavailableEvent {
374
+ kind: 'view_once' | 'hosted' | 'bot' | 'other';
375
+ resendRequested: boolean;
376
+ occurredAt: Date;
377
+ messageId?: string;
378
+ chatId?: string;
379
+ participantId?: string;
380
+ }
381
+ interface MessageRecoveredEvent {
382
+ recoveredAt: Date;
383
+ recoveryMs: number;
384
+ messageId?: string;
385
+ chatId?: string;
386
+ participantId?: string;
387
+ }
388
+ interface MessageRecoveryFailedEvent {
389
+ failedAt: Date;
390
+ waitedMs: number;
391
+ messageId?: string;
392
+ chatId?: string;
393
+ participantId?: string;
394
+ }
395
+ interface MessageDecodeFailureEvent {
396
+ occurredAt: Date;
397
+ reason: string;
398
+ stanzaId?: string;
399
+ chatId?: string;
400
+ encType?: string;
401
+ }
402
+ type MessageDiscardReason = 'offline' | 'duplicate' | 'normalization_failed';
403
+ interface MessageDiscardedEvent {
404
+ reason: MessageDiscardReason;
405
+ occurredAt: Date;
406
+ messageId?: string;
407
+ chatId?: string;
408
+ }
409
+ type MessageIngressStage = 'stanza_received' | 'decrypted';
410
+ interface MessageIngressStalledEvent {
411
+ occurredAt: Date;
412
+ waitedMs: number;
413
+ lastStage: MessageIngressStage;
414
+ stanzaId: string;
415
+ chatId?: string;
416
+ participantId?: string;
417
+ stanzaType?: string;
418
+ addressingMode?: string;
419
+ }
420
+ interface TransportDecodeFailureEvent {
421
+ occurredAt: Date;
422
+ frameBytes: number;
423
+ errorName: string;
424
+ errorMessage: string;
425
+ }
357
426
  type ProviderStabilityEvent = {
358
427
  type: 'groupMetadataRecovered';
359
428
  payload: GroupMetadataRecoveredEvent;
360
429
  } | {
361
430
  type: 'cryptoDegraded';
362
431
  payload: CryptoDegradedEvent;
432
+ } | {
433
+ type: 'messageUnavailable';
434
+ payload: MessageUnavailableEvent;
435
+ } | {
436
+ type: 'messageRecovered';
437
+ payload: MessageRecoveredEvent;
438
+ } | {
439
+ type: 'messageRecoveryFailed';
440
+ payload: MessageRecoveryFailedEvent;
441
+ } | {
442
+ type: 'messageDecodeFailure';
443
+ payload: MessageDecodeFailureEvent;
444
+ } | {
445
+ type: 'messageDiscarded';
446
+ payload: MessageDiscardedEvent;
447
+ } | {
448
+ type: 'messageIngressStalled';
449
+ payload: MessageIngressStalledEvent;
450
+ } | {
451
+ type: 'transportDecodeFailure';
452
+ payload: TransportDecodeFailureEvent;
363
453
  } | {
364
454
  type: 'healthRefresh';
365
455
  payload: {
@@ -936,6 +1026,13 @@ interface AppEvents {
936
1026
  connectionRecovered: ConnectionRecoveredEvent;
937
1027
  groupMetadataRecovered: GroupMetadataRecoveredEvent;
938
1028
  cryptoDegraded: CryptoDegradedEvent;
1029
+ messageUnavailable: MessageUnavailableEvent;
1030
+ messageRecovered: MessageRecoveredEvent;
1031
+ messageRecoveryFailed: MessageRecoveryFailedEvent;
1032
+ messageDecodeFailure: MessageDecodeFailureEvent;
1033
+ messageDiscarded: MessageDiscardedEvent;
1034
+ messageIngressStalled: MessageIngressStalledEvent;
1035
+ transportDecodeFailure: TransportDecodeFailureEvent;
939
1036
  commandQueueTimeout: CommandQueueTimeoutEvent;
940
1037
  commandQueueFull: CommandQueueFullEvent;
941
1038
  }
@@ -1001,6 +1098,10 @@ interface ProviderTimeoutOptions {
1001
1098
  connectTimeoutMs?: number;
1002
1099
  nodeQueryTimeoutMs?: number;
1003
1100
  }
1101
+ interface ProviderDiagnosticsOptions {
1102
+ ingress?: boolean;
1103
+ ingressStallTimeoutMs?: number;
1104
+ }
1004
1105
  interface ReconnectOptions {
1005
1106
  enabled?: boolean;
1006
1107
  maxAttempts?: number;
@@ -1018,6 +1119,7 @@ interface CreateOptions {
1018
1119
  router?: Omit<RouterOptions, 'prefix'>;
1019
1120
  reconnect?: ReconnectOptions;
1020
1121
  providerTimeouts?: ProviderTimeoutOptions;
1122
+ providerDiagnostics?: ProviderDiagnosticsOptions;
1021
1123
  messageCacheSize?: number;
1022
1124
  processOfflineMessages?: boolean;
1023
1125
  provider?: WhatsAppProvider;
@@ -1105,4 +1207,4 @@ declare class SqliteMuteStore implements MuteStore {
1105
1207
  close(): void;
1106
1208
  }
1107
1209
 
1108
- 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 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 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 };
1210
+ 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 MessageIngressStage, type MessageIngressStalledEvent, 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 ProviderDiagnosticsOptions, 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, type TransportDecodeFailureEvent, 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 };