baileys-redis-auth 1.0.14 → 2.0.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/LOGOUT_GUIDE.md +210 -0
- package/README.md +299 -21
- package/lib/index.d.ts +43 -0
- package/lib/index.js +169 -0
- package/package.json +47 -20
- package/.eslintrc +0 -30
- package/.prettierrc +0 -8
- package/.vscode/settings.json +0 -20
- package/lib/package.json +0 -43
- package/lib/src/Example/example.d.ts +0 -1
- package/lib/src/Example/example.js +0 -222
- package/lib/src/Example/logger-pino.d.ts +0 -17
- package/lib/src/Example/logger-pino.js +0 -39
- package/lib/src/index.d.ts +0 -23
- package/lib/src/index.js +0 -135
- package/src/Example/example.ts +0 -240
- package/src/Example/logger-pino.ts +0 -38
- package/src/index.ts +0 -172
- package/tsconfig.json +0 -25
package/LOGOUT_GUIDE.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Logout Implementation Guide
|
|
2
|
+
|
|
3
|
+
This document explains how to properly implement logout functionality with `baileys-redis-auth`.
|
|
4
|
+
|
|
5
|
+
## How Baileys Logout Works
|
|
6
|
+
|
|
7
|
+
When you call `sock.logout()`, Baileys:
|
|
8
|
+
|
|
9
|
+
1. Sends a "remove-companion-device" request to WhatsApp servers
|
|
10
|
+
2. Triggers a connection close with `DisconnectReason.loggedOut` status code
|
|
11
|
+
3. **Does NOT automatically clear auth state** - this is the responsibility of your application
|
|
12
|
+
|
|
13
|
+
## Important: Auth State Does Not Auto-Clear
|
|
14
|
+
|
|
15
|
+
Unlike some other libraries, **Baileys does not automatically clear authentication state when logout() is called**. This is intentional and follows the file-based auth state pattern.
|
|
16
|
+
|
|
17
|
+
Your application MUST manually clear the Redis session when it detects a logout.
|
|
18
|
+
|
|
19
|
+
## Proper Logout Implementation
|
|
20
|
+
|
|
21
|
+
### Step 1: Detect Logout in Connection Handler
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {deleteKeysWithPattern, useRedisAuthState} from 'baileys-redis-auth'
|
|
25
|
+
import {DisconnectReason} from '@whiskeysockets/baileys'
|
|
26
|
+
|
|
27
|
+
const {state, saveCreds, redis} = await useRedisAuthState(redisOptions, 'my-session')
|
|
28
|
+
|
|
29
|
+
sock.ev.on('connection.update', async (update) => {
|
|
30
|
+
const {connection, lastDisconnect} = update
|
|
31
|
+
|
|
32
|
+
if (connection === 'close') {
|
|
33
|
+
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
|
|
34
|
+
|
|
35
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
36
|
+
// User logged out - clear the session
|
|
37
|
+
await deleteKeysWithPattern({
|
|
38
|
+
redis,
|
|
39
|
+
pattern: 'my-session:*', // Must match your session prefix
|
|
40
|
+
logger: console.log // Optional: pass logger for debugging
|
|
41
|
+
})
|
|
42
|
+
console.log('Session cleared after logout')
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Step 2: Call Logout When Needed
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// When user wants to logout
|
|
52
|
+
try {
|
|
53
|
+
await sock.logout()
|
|
54
|
+
} catch (error) {
|
|
55
|
+
// Logout throws "Intentional Logout" error - this is expected
|
|
56
|
+
// The connection.update handler will handle cleanup
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Using Hash-Based Storage (useRedisAuthStateWithHSet)
|
|
61
|
+
|
|
62
|
+
If you're using `useRedisAuthStateWithHSet`, use `deleteHSetKeys` instead:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import {deleteHSetKeys, useRedisAuthStateWithHSet} from 'baileys-redis-auth'
|
|
66
|
+
|
|
67
|
+
const {state, saveCreds, redis} = await useRedisAuthStateWithHSet(redisOptions, 'my-session')
|
|
68
|
+
|
|
69
|
+
sock.ev.on('connection.update', async (update) => {
|
|
70
|
+
const {connection, lastDisconnect} = update
|
|
71
|
+
|
|
72
|
+
if (connection === 'close') {
|
|
73
|
+
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
|
|
74
|
+
|
|
75
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
76
|
+
// Clear HSet-based session
|
|
77
|
+
await deleteHSetKeys({
|
|
78
|
+
redis,
|
|
79
|
+
key: 'my-session',
|
|
80
|
+
logger: console.log // Optional: pass logger for debugging
|
|
81
|
+
})
|
|
82
|
+
console.log('Session cleared after logout')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Complete Example
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import {deleteKeysWithPattern, useRedisAuthState} from 'baileys-redis-auth'
|
|
92
|
+
import makeWASocket, {DisconnectReason} from '@whiskeysockets/baileys'
|
|
93
|
+
import type {Boom} from '@hapi/boom'
|
|
94
|
+
|
|
95
|
+
async function startWhatsApp() {
|
|
96
|
+
const sessionPrefix = 'my-session'
|
|
97
|
+
|
|
98
|
+
const {state, saveCreds, redis} = await useRedisAuthState({
|
|
99
|
+
host: 'localhost',
|
|
100
|
+
port: 6379,
|
|
101
|
+
}, sessionPrefix)
|
|
102
|
+
|
|
103
|
+
const sock = makeWASocket({
|
|
104
|
+
auth: state,
|
|
105
|
+
// ... other options
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// Save credentials on update
|
|
109
|
+
sock.ev.on('creds.update', saveCreds)
|
|
110
|
+
|
|
111
|
+
// Handle connection updates
|
|
112
|
+
sock.ev.on('connection.update', async (update) => {
|
|
113
|
+
const {connection, lastDisconnect} = update
|
|
114
|
+
|
|
115
|
+
if (connection === 'close') {
|
|
116
|
+
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
|
|
117
|
+
|
|
118
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
119
|
+
// THIS IS CRITICAL: Clear Redis session on logout
|
|
120
|
+
await deleteKeysWithPattern({
|
|
121
|
+
redis,
|
|
122
|
+
pattern: `${sessionPrefix}:*`,
|
|
123
|
+
logger: console.log // Optional: pass logger for debugging
|
|
124
|
+
})
|
|
125
|
+
console.log('✅ Session cleared successfully')
|
|
126
|
+
} else {
|
|
127
|
+
// Reconnect on other errors
|
|
128
|
+
console.log('Reconnecting...')
|
|
129
|
+
startWhatsApp()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
return sock
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Usage
|
|
138
|
+
const sock = await startWhatsApp()
|
|
139
|
+
|
|
140
|
+
// Later, when user wants to logout:
|
|
141
|
+
await sock.logout() // This will trigger the cleanup in connection.update handler
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Why This Design?
|
|
145
|
+
|
|
146
|
+
This design follows Baileys' philosophy:
|
|
147
|
+
|
|
148
|
+
1. **Separation of Concerns**: Auth state storage is separate from connection management
|
|
149
|
+
2. **Flexibility**: You can choose when and how to clear sessions
|
|
150
|
+
3. **Consistency**: Works the same way as file-based auth state
|
|
151
|
+
4. **Control**: You have full control over session lifecycle
|
|
152
|
+
|
|
153
|
+
## Common Mistakes
|
|
154
|
+
|
|
155
|
+
### ❌ Wrong: Calling logout without cleanup handler
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// This will NOT clear your Redis session!
|
|
159
|
+
await sock.logout()
|
|
160
|
+
// Session data still exists in Redis
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### ❌ Wrong: Clearing session before logout completes
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
await sock.logout()
|
|
167
|
+
await deleteKeysWithPattern({redis, pattern: 'session:*'})
|
|
168
|
+
// Race condition - might clear before logout message is sent
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### ✅ Correct: Handle cleanup in connection.update
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
sock.ev.on('connection.update', async (update) => {
|
|
175
|
+
if (connection === 'close' && statusCode === DisconnectReason.loggedOut) {
|
|
176
|
+
await deleteKeysWithPattern({redis, pattern: 'session:*'})
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// Later...
|
|
181
|
+
await sock.logout() // Cleanup happens automatically
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Exported Functions Reference
|
|
185
|
+
|
|
186
|
+
### For Key-Value Storage
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
deleteKeysWithPattern({
|
|
190
|
+
redis: RedisClient, // Redis client from useRedisAuthState
|
|
191
|
+
pattern: string, // Pattern to match (e.g., 'session:*')
|
|
192
|
+
logger?: (message: string, ...args: unknown[]) => void // Optional logger function
|
|
193
|
+
}): Promise<void>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### For Hash Storage
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
deleteHSetKeys({
|
|
200
|
+
redis: RedisClient, // Redis client from useRedisAuthStateWithHSet
|
|
201
|
+
key: string, // Session prefix (e.g., 'session')
|
|
202
|
+
logger?: (message: string, ...args: unknown[]) => void // Optional logger function
|
|
203
|
+
}): Promise<void>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## See Also
|
|
207
|
+
|
|
208
|
+
- [Example Implementation](./example/example.ts) - Complete working example with logout
|
|
209
|
+
- [Main Documentation](./CLAUDE.md) - Full library documentation
|
|
210
|
+
- [Baileys Documentation](https://github.com/WhiskeySockets/Baileys) - Official Baileys docs
|
package/README.md
CHANGED
|
@@ -1,36 +1,314 @@
|
|
|
1
1
|
# baileys-redis-auth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`baileys-redis-auth` is a library designed to seamlessly integrate Redis as an authentication state storage solution for [Baileys](https://github.com/WhiskeySockets/Baileys), the powerful WhatsApp Web API library. By leveraging Redis, this module allows you to persist Baileys sessions, enabling your application to resume connections without needing to re-scan QR codes frequently. This is particularly useful for applications requiring robust and scalable session management.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This library provides flexible ways to store authentication data in Redis, using either simple key-value pairs or Redis Hashes for optimized storage.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## ⚠️ Version Compatibility
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
| baileys-redis-auth | Baileys Version | Package Name |
|
|
10
|
+
|-------------------|-----------------|--------------|
|
|
11
|
+
| v2.x | `baileys` v7.0.0-rc.1+ | `baileys` |
|
|
12
|
+
| v1.x | `@whiskeysockets/baileys` v6.x | `@whiskeysockets/baileys` |
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
**v2.0.0 Breaking Changes:**
|
|
15
|
+
- Now requires **Baileys v7+** (the new `baileys` package)
|
|
16
|
+
- Library is now **ESM-only** (no CommonJS support)
|
|
17
|
+
- Baileys is now a **peer dependency** - you must install it separately
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
host: 'localhost',
|
|
15
|
-
port: 6379,
|
|
16
|
-
};
|
|
19
|
+
## Prerequisites
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
Before using `baileys-redis-auth`, ensure you have the following installed and configured:
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
* **Node.js:** Version 18.x or higher is recommended.
|
|
24
|
+
* **Redis:** A running Redis server instance. You'll need its connection details (host, port, password if any).
|
|
25
|
+
* **Baileys v7+:** This library is an auth handler for Baileys. Install the new `baileys` package (not `@whiskeysockets/baileys`).
|
|
22
26
|
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Install both the auth library and Baileys v7
|
|
31
|
+
npm install baileys-redis-auth baileys
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or with other package managers:
|
|
35
|
+
```bash
|
|
36
|
+
# Bun
|
|
37
|
+
bun add baileys-redis-auth baileys
|
|
38
|
+
|
|
39
|
+
# Yarn
|
|
40
|
+
yarn add baileys-redis-auth baileys
|
|
41
|
+
|
|
42
|
+
# pnpm
|
|
43
|
+
pnpm add baileys-redis-auth baileys
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
### Using `useRedisAuthStateWithHSet` (Recommended)
|
|
49
|
+
|
|
50
|
+
This is the recommended method for storing Baileys authentication data in Redis. It utilizes Redis Hashes (HSET) to store all authentication credentials and keys under a single Redis key per session prefix. This approach is generally more efficient and organized, especially when managing multiple Baileys sessions.
|
|
51
|
+
|
|
52
|
+
**Parameters:**
|
|
53
|
+
* `redisOptions`: An object containing your Redis server connection details (e.g., `host`, `port`, `password`). This is passed directly to the `ioredis` constructor.
|
|
54
|
+
* `prefix`: A string used to namespace your Baileys session data in Redis. For example, if your `prefix` is `'DB1'`, all data for this session will be stored under a Redis key like `authState:DB1`. This allows you to manage multiple independent Baileys sessions in the same Redis database.
|
|
55
|
+
* `logger` (optional): A function `(message: string, ...args: unknown[]) => void` for logging Redis connection events. Pass `console.log` or your custom logger function.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import {useRedisAuthStateWithHSet, deleteHSetKeys} from 'baileys-redis-auth';
|
|
59
|
+
import type {RedisOptions} from 'ioredis';
|
|
60
|
+
|
|
61
|
+
// Define your Redis connection options
|
|
62
|
+
const redisOptions: RedisOptions = {
|
|
63
|
+
host: 'localhost',
|
|
64
|
+
port: 6379,
|
|
65
|
+
// password: 'your_redis_password', // Uncomment if your Redis has a password
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Define a unique prefix for this Baileys session
|
|
69
|
+
const sessionPrefix = 'baileys_session_1';
|
|
70
|
+
|
|
71
|
+
async function initializeBaileysWithHSet() {
|
|
72
|
+
// Initialize a new Redis client instance if you need to pass it around or use it elsewhere
|
|
73
|
+
// const redis = new Redis(redisOptions);
|
|
74
|
+
// redis.on('connect', () => console.log('Connected to Redis for HSet method!'));
|
|
75
|
+
// Note: useRedisAuthStateWithHSet creates its own Redis instance internally based on redisOptions.
|
|
76
|
+
// If you pass an existing ioredis instance, it should be the first argument,
|
|
77
|
+
// and redisOptions the second, though the current library signature seems to expect options first.
|
|
78
|
+
// For simplicity, we'll let the function create its own connection.
|
|
79
|
+
|
|
80
|
+
const {state, saveCreds, redis: authRedisInstance} = await useRedisAuthStateWithHSet(
|
|
81
|
+
redisOptions,
|
|
82
|
+
sessionPrefix,
|
|
83
|
+
console.log // Optional: pass logger for Redis connection events
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// 'state' will be used to initialize Baileys
|
|
87
|
+
// 'saveCreds' is a function to periodically save the authentication state
|
|
88
|
+
// 'authRedisInstance' is the Redis client instance used by the auth state hook
|
|
89
|
+
|
|
90
|
+
console.log('Baileys state loaded using HSet method.');
|
|
91
|
+
|
|
92
|
+
// Example: Listen for Redis connection events on the instance returned by the hook
|
|
93
|
+
authRedisInstance.on('connect', () => console.log(`Redis (from hook) connected for session: ${sessionPrefix}`));
|
|
94
|
+
authRedisInstance.on('error', (err) => console.error(`Redis (from hook) error for session ${sessionPrefix}:`, err));
|
|
95
|
+
|
|
96
|
+
// ... your Baileys setup code using 'state' and 'saveCreds'
|
|
97
|
+
|
|
98
|
+
// Example of how to delete all keys for this specific session prefix if needed:
|
|
99
|
+
// await deleteHSetKeys({redis: authRedisInstance, key: sessionPrefix});
|
|
100
|
+
// console.log(`Authentication data for session ${sessionPrefix} deleted.`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
initializeBaileysWithHSet().catch(console.error);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Deleting Session Data (`deleteHSetKeys`)
|
|
107
|
+
|
|
108
|
+
To remove all authentication data associated with a specific session prefix used with `useRedisAuthStateWithHSet`, you can use the `deleteHSetKeys` utility function.
|
|
109
|
+
|
|
110
|
+
**Usage:**
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { deleteHSetKeys } from 'baileys-redis-auth';
|
|
114
|
+
// Use the Redis instance from useRedisAuthStateWithHSet
|
|
115
|
+
|
|
116
|
+
// Assuming 'authRedisInstance' is the Redis instance from useRedisAuthStateWithHSet
|
|
117
|
+
// or a new instance configured with the same options.
|
|
118
|
+
// const redisClient = new Redis(redisOptions);
|
|
119
|
+
// const sessionPrefixToDelete = 'baileys_session_1';
|
|
120
|
+
|
|
121
|
+
// await deleteHSetKeys({redis: authRedisInstance, key: sessionPrefixToDelete});
|
|
122
|
+
// console.log(`All HSet data for prefix '${sessionPrefixToDelete}' deleted.`);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Parameters:**
|
|
126
|
+
* `options`: An object with the following properties:
|
|
127
|
+
* `redis`: An active `ioredis` client instance.
|
|
128
|
+
* `key`: The session `prefix` string (e.g., `'baileys_session_1'`) whose data needs to be deleted. This corresponds to the `prefix` you used with `useRedisAuthStateWithHSet`.
|
|
129
|
+
* `logger` (optional): A function for logging deletion operations.
|
|
130
|
+
|
|
131
|
+
### Using `useRedisAuthState`
|
|
132
|
+
|
|
133
|
+
This method stores each piece of authentication data as a separate key-value pair in Redis, prefixed by the `prefix` string. While functional, it can lead to a larger number of individual keys in your Redis database compared to the HSET method.
|
|
134
|
+
|
|
135
|
+
**Parameters:**
|
|
136
|
+
* `redisOptions`: An object containing your Redis server connection details (e.g., `host`, `port`, `password`). This is passed directly to the `ioredis` constructor.
|
|
137
|
+
* `prefix`: A string used to prefix all Redis keys for this Baileys session. For example, if your `prefix` is `'DB1'`, keys will be stored like `DB1:creds`, `DB1:pre-key-1`, etc.
|
|
138
|
+
* `logger` (optional): A function `(message: string, ...args: unknown[]) => void` for logging Redis connection events. Pass `console.log` or your custom logger function.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import {useRedisAuthState, deleteKeysWithPattern} from 'baileys-redis-auth';
|
|
142
|
+
import type {RedisOptions} from 'ioredis';
|
|
143
|
+
|
|
144
|
+
// Define your Redis connection options
|
|
145
|
+
const redisOptions: RedisOptions = {
|
|
146
|
+
host: 'localhost',
|
|
147
|
+
port: 6379,
|
|
148
|
+
// password: 'your_redis_password', // Uncomment if your Redis has a password
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Define a unique prefix for this Baileys session
|
|
152
|
+
const sessionPrefix = 'baileys_session_2';
|
|
153
|
+
|
|
154
|
+
async function initializeBaileysSimple() {
|
|
155
|
+
// Initialize a new Redis client instance if you need to pass it around
|
|
156
|
+
// const redis = new Redis(redisOptions);
|
|
157
|
+
// redis.on('connect', () => console.log('Connected to Redis for simple method!'));
|
|
158
|
+
// As with HSet, useRedisAuthState creates its own Redis instance.
|
|
159
|
+
|
|
160
|
+
const {state, saveCreds, redis: authRedisInstance} = await useRedisAuthState(
|
|
161
|
+
redisOptions,
|
|
162
|
+
sessionPrefix,
|
|
163
|
+
console.log // Optional: pass logger for Redis connection events
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// 'state' will be used to initialize Baileys
|
|
167
|
+
// 'saveCreds' is a function to periodically save the authentication state
|
|
168
|
+
// 'authRedisInstance' is the Redis client instance used by the auth state hook
|
|
169
|
+
|
|
170
|
+
console.log('Baileys state loaded using simple key-value method.');
|
|
23
171
|
|
|
24
|
-
|
|
172
|
+
// Example: Listen for Redis connection events on the instance returned by the hook
|
|
173
|
+
authRedisInstance.on('connect', () => console.log(`Redis (from hook) connected for session: ${sessionPrefix}`));
|
|
174
|
+
authRedisInstance.on('error', (err) => console.error(`Redis (from hook) error for session ${sessionPrefix}:`, err));
|
|
175
|
+
|
|
176
|
+
// ... your Baileys setup code using 'state' and 'saveCreds'
|
|
177
|
+
|
|
178
|
+
// Example of how to delete all keys for this specific session prefix if needed:
|
|
179
|
+
// The pattern should match the prefix used.
|
|
180
|
+
// await deleteKeysWithPattern({redis: authRedisInstance, pattern: `${sessionPrefix}:*`});
|
|
181
|
+
// console.log(`Authentication data for session ${sessionPrefix} (pattern: ${sessionPrefix}:*) deleted.`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
initializeBaileysSimple().catch(console.error);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### Deleting Session Data (`deleteKeysWithPattern`)
|
|
188
|
+
|
|
189
|
+
To remove all authentication data associated with a specific session prefix used with `useRedisAuthState`, you can use the `deleteKeysWithPattern` utility function. This function deletes all Redis keys matching a given pattern.
|
|
190
|
+
|
|
191
|
+
**Usage:**
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import { deleteKeysWithPattern } from 'baileys-redis-auth';
|
|
195
|
+
// Use the Redis instance from useRedisAuthState
|
|
196
|
+
|
|
197
|
+
// Assuming 'authRedisInstance' is the Redis instance from useRedisAuthState
|
|
198
|
+
// or a new instance configured with the same options.
|
|
199
|
+
// const redisClient = new Redis(redisOptions);
|
|
200
|
+
// const sessionPrefixToDelete = 'baileys_session_2';
|
|
201
|
+
|
|
202
|
+
// The pattern must match how useRedisAuthState stores keys, typically `prefix:*`
|
|
203
|
+
// await deleteKeysWithPattern({redis: authRedisInstance, pattern: `${sessionPrefixToDelete}:*`});
|
|
204
|
+
// console.log(`All keys matching pattern '${sessionPrefixToDelete}:*' deleted.`);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Parameters:**
|
|
208
|
+
* `options`: An object with the following properties:
|
|
209
|
+
* `redis`: An active `ioredis` client instance.
|
|
210
|
+
* `pattern`: The key pattern to delete (e.g., `'baileys_session_2:*'`). This should align with the `prefix` used in `useRedisAuthState`, followed by `:*` to match all related keys.
|
|
211
|
+
* `logger` (optional): A function for logging deletion operations.
|
|
212
|
+
|
|
213
|
+
## Logout and Session Cleanup
|
|
214
|
+
|
|
215
|
+
**Important**: When you call `sock.logout()`, Baileys does NOT automatically clear your Redis session. You must manually handle session cleanup in your `connection.update` event handler.
|
|
216
|
+
|
|
217
|
+
### Proper Logout Implementation
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import {deleteKeysWithPattern, useRedisAuthState} from 'baileys-redis-auth'
|
|
221
|
+
import makeWASocket, {DisconnectReason} from 'baileys'
|
|
222
|
+
import type {Boom} from '@hapi/boom'
|
|
223
|
+
|
|
224
|
+
const sessionPrefix = 'my-session'
|
|
225
|
+
const {state, saveCreds, redis} = await useRedisAuthState(redisOptions, sessionPrefix, console.log)
|
|
226
|
+
|
|
227
|
+
const sock = makeWASocket({auth: state})
|
|
228
|
+
|
|
229
|
+
// Handle connection updates
|
|
230
|
+
sock.ev.on('connection.update', async (update) => {
|
|
231
|
+
const {connection, lastDisconnect} = update
|
|
232
|
+
|
|
233
|
+
if (connection === 'close') {
|
|
234
|
+
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
|
|
235
|
+
|
|
236
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
237
|
+
// Clear Redis session on logout
|
|
238
|
+
await deleteKeysWithPattern({
|
|
239
|
+
redis,
|
|
240
|
+
pattern: `${sessionPrefix}:*`,
|
|
241
|
+
logger: console.log // Optional: pass logger for debugging
|
|
242
|
+
})
|
|
243
|
+
console.log('Session cleared')
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
// When you want to logout
|
|
249
|
+
await sock.logout() // Session cleanup happens in connection.update handler
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
For detailed logout implementation guide, see [LOGOUT_GUIDE.md](./LOGOUT_GUIDE.md).
|
|
253
|
+
|
|
254
|
+
## Running the Example
|
|
255
|
+
|
|
256
|
+
This project includes an example script to demonstrate the usage of `baileys-redis-auth`. To run it:
|
|
257
|
+
|
|
258
|
+
1. **Clone the repository (if you haven't already):**
|
|
259
|
+
```bash
|
|
260
|
+
git clone https://github.com/hbinduni/baileys-redis-auth.git
|
|
261
|
+
cd baileys-redis-auth
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
2. **Install dependencies:**
|
|
265
|
+
```bash
|
|
266
|
+
npm install
|
|
267
|
+
# or
|
|
268
|
+
# pnpm install
|
|
269
|
+
# or
|
|
270
|
+
# yarn install
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
3. **Ensure you have a Redis server running** and accessible on `localhost:6379` (or update the example script with your Redis configuration).
|
|
274
|
+
|
|
275
|
+
4. **Configure environment variables:**
|
|
276
|
+
```bash
|
|
277
|
+
cp .env.example .env
|
|
278
|
+
# Edit .env with your Redis configuration
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
5. **Run the example script:**
|
|
282
|
+
```bash
|
|
283
|
+
npm run example
|
|
284
|
+
# or
|
|
285
|
+
# pnpm example
|
|
286
|
+
# or
|
|
287
|
+
# bun run example
|
|
288
|
+
```
|
|
289
|
+
This command executes `tsx example/example.ts`.
|
|
290
|
+
The example will guide you through connecting to WhatsApp using Baileys with Redis for authentication storage. You'll see a QR code in your terminal to scan with WhatsApp.
|
|
291
|
+
|
|
292
|
+
**Interactive Commands:**
|
|
293
|
+
- `send <phone> <message>` - Send a WhatsApp message
|
|
294
|
+
- `logout` - Logout and clear session
|
|
295
|
+
- `help` - Show available commands
|
|
296
|
+
- `exit` - Exit the application
|
|
297
|
+
|
|
298
|
+
## Contributing
|
|
299
|
+
|
|
300
|
+
Contributions are welcome! If you have suggestions for improvements, bug fixes, or new features, please feel free to:
|
|
25
301
|
|
|
26
|
-
|
|
302
|
+
1. Fork the repository.
|
|
303
|
+
2. Create a new branch (`git checkout -b feature/your-feature-name`).
|
|
304
|
+
3. Make your changes.
|
|
305
|
+
4. Commit your changes (`git commit -m 'Add some feature'`).
|
|
306
|
+
5. Push to the branch (`git push origin feature/your-feature-name`).
|
|
307
|
+
6. Open a Pull Request.
|
|
27
308
|
|
|
28
|
-
|
|
29
|
-
host: 'localhost',
|
|
30
|
-
port: 6379,
|
|
31
|
-
};
|
|
309
|
+
Please ensure your code adheres to the existing style and that any new functionality is appropriately documented.
|
|
32
310
|
|
|
33
|
-
|
|
311
|
+
## License
|
|
34
312
|
|
|
35
|
-
|
|
36
|
-
|
|
313
|
+
This project is licensed under the MIT License. Refer to the license information in the `package.json` for details.
|
|
314
|
+
```
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type AuthenticationState } from 'baileys';
|
|
2
|
+
import { Redis, type RedisOptions } from 'ioredis';
|
|
3
|
+
type RedisClient = Redis;
|
|
4
|
+
interface IDeleteHSetKeyOptions {
|
|
5
|
+
redis: RedisClient;
|
|
6
|
+
key: string;
|
|
7
|
+
logger?: (message: string, ...args: unknown[]) => void;
|
|
8
|
+
}
|
|
9
|
+
interface IDeleteKeysOptions {
|
|
10
|
+
redis: RedisClient;
|
|
11
|
+
pattern: string;
|
|
12
|
+
logger?: (message: string, ...args: unknown[]) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Redis-based authentication state storage using Hash (HSET) - Recommended
|
|
16
|
+
* Stores all authentication data in a single Redis Hash per prefix
|
|
17
|
+
* More efficient than key-value approach for Redis memory and operations
|
|
18
|
+
*/
|
|
19
|
+
export declare const useRedisAuthStateWithHSet: (redisOptions: RedisOptions, prefix?: string, logger?: (message: string, ...args: unknown[]) => void) => Promise<{
|
|
20
|
+
state: AuthenticationState;
|
|
21
|
+
saveCreds: () => Promise<void>;
|
|
22
|
+
redis: RedisClient;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Deletes all authentication data for a specific prefix using Hash (HSET)
|
|
26
|
+
*/
|
|
27
|
+
export declare const deleteHSetKeys: ({ redis, key, logger }: IDeleteHSetKeyOptions) => Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Redis-based authentication state storage using key-value pairs
|
|
30
|
+
* Stores each piece of authentication data as a separate Redis key
|
|
31
|
+
* Less efficient than Hash approach but more compatible with existing systems
|
|
32
|
+
*/
|
|
33
|
+
export declare const useRedisAuthState: (redisOptions: RedisOptions, prefix?: string, logger?: (message: string, ...args: unknown[]) => void) => Promise<{
|
|
34
|
+
state: AuthenticationState;
|
|
35
|
+
saveCreds: () => Promise<void>;
|
|
36
|
+
redis: RedisClient;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Deletes all authentication keys matching a pattern using key-value approach
|
|
40
|
+
* Uses SCAN to safely iterate through keys without blocking Redis
|
|
41
|
+
*/
|
|
42
|
+
export declare const deleteKeysWithPattern: ({ redis, pattern, logger }: IDeleteKeysOptions) => Promise<void>;
|
|
43
|
+
export {};
|