baileys-diag
v0.1.1
Published
Protocol-level diagnostic capture for Baileys — flight recorder for debugging sync issues
Maintainers
Readme
baileys-diag
Protocol-level diagnostic capture for Baileys. Records a timeline of app state sync, history sync, key operations, and connection events into a single compressed file for offline debugging.
Install
npm install baileys-diag
# or
bun add baileys-diagRequires @whiskeysockets/baileys >= 7.0.0 as a peer dependency.
Usage
import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
import { makeDiagnosticCapture } from 'baileys-diag'
// create capture once — survives reconnects
const diag = makeDiagnosticCapture('./capture.diag.gz')
async function startSock() {
const { state, saveCreds } = await useMultiFileAuthState('./auth')
const sock = makeWASocket({ auth: state })
// attach to each new socket
diag.attachSocket(sock)
sock.ev.on('creds.update', saveCreds)
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
if (connection === 'close') {
// reconnect logic...
startSock()
}
})
}
startSock()
// Ctrl+C flushes the capture automaticallyReading captures
The output is gzipped NDJSON — one JSON object per line.
# quick check: did nctSalt arrive?
zcat capture.diag.gz | grep nctSalt
# list all event types
zcat capture.diag.gz | jq -r .type | sort | uniq -c | sort -rn
# see history sync details
zcat capture.diag.gz | jq 'select(.type == "history-sync")'
# see app state version changes
zcat capture.diag.gz | jq 'select(.type == "key-set" and .keyType == "app-state-sync-version")'
# see all syncd mutation effects
zcat capture.diag.gz | jq -r 'select(.type == "syncd-effect") | .event' | sort | uniq -c
# full timeline
zcat capture.diag.gz | jq -c '[.ts, .type, .generation] | @tsv'What it captures
| Record type | Source | Content |
|---|---|---|
| init | On create | Format version |
| socket-attach | attachSocket() | Session metadata, nctSalt status |
| creds-snapshot | attachSocket() | Full credentials (private keys redacted) |
| connection | connection.update | Connection state changes |
| creds-update | creds.update | Credential changes with nctSalt tracking |
| history-sync | messaging-history.set | Sync type, progress, chat/contact/message counts |
| syncd-effect | chats.update, settings.update, etc. | All effects of app state sync mutations |
| key-get | keys.get() | App state sync key and version reads |
| key-set | keys.set() | App state sync key and version writes |
| close | On shutdown | Signal that triggered close |
Options
makeDiagnosticCapture('./capture.diag.gz', {
captureCredsUpdates: true, // creds.update events (default: true)
captureKeyOps: true, // app-state-sync-key/version operations (default: true)
captureHistorySync: true, // messaging-history.set events (default: true)
captureAllKeyOps: false, // ALL key store operations, very verbose (default: false)
})Security
Private keys are automatically redacted in credential snapshots:
noiseKey.privatesignedIdentityKey.privatepairingEphemeralKeyPair.privatesignedPreKey.keyPair.privateadvSecretKey
Public keys, account identifiers, and app state sync keys are preserved since they're needed for offline replay.
How it works
The capture hooks into the Baileys socket non-invasively:
- Event listeners on
ev.on()for connection, creds, history sync, and syncd effect events - Key store interception by wrapping
keys.get()andkeys.set()to capture app state sync operations - Periodic gzip flush (every 5s) so the file is readable while the session is still running
- SIGINT/SIGTERM handler flushes the capture before process exit
No Baileys internals are modified. The capture attaches and detaches cleanly via attachSocket() and close().
License
MIT
