baileys-redis-auth 1.1.0 → 2.0.1
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 +9 -9
- package/README.md +262 -116
- package/lib/index.d.ts +194 -15
- package/lib/index.js +263 -50
- package/package.json +25 -11
package/LOGOUT_GUIDE.md
CHANGED
|
@@ -22,7 +22,7 @@ Your application MUST manually clear the Redis session when it detects a logout.
|
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
import {deleteKeysWithPattern, useRedisAuthState} from 'baileys-redis-auth'
|
|
25
|
-
import {DisconnectReason} from '
|
|
25
|
+
import {DisconnectReason} from 'baileys'
|
|
26
26
|
|
|
27
27
|
const {state, saveCreds, redis} = await useRedisAuthState(redisOptions, 'my-session')
|
|
28
28
|
|
|
@@ -36,7 +36,7 @@ sock.ev.on('connection.update', async (update) => {
|
|
|
36
36
|
// User logged out - clear the session
|
|
37
37
|
await deleteKeysWithPattern({
|
|
38
38
|
redis,
|
|
39
|
-
|
|
39
|
+
sessionId: 'my-session', // Must match your session prefix
|
|
40
40
|
logger: console.log // Optional: pass logger for debugging
|
|
41
41
|
})
|
|
42
42
|
console.log('Session cleared after logout')
|
|
@@ -76,7 +76,7 @@ sock.ev.on('connection.update', async (update) => {
|
|
|
76
76
|
// Clear HSet-based session
|
|
77
77
|
await deleteHSetKeys({
|
|
78
78
|
redis,
|
|
79
|
-
|
|
79
|
+
sessionId: 'my-session',
|
|
80
80
|
logger: console.log // Optional: pass logger for debugging
|
|
81
81
|
})
|
|
82
82
|
console.log('Session cleared after logout')
|
|
@@ -89,7 +89,7 @@ sock.ev.on('connection.update', async (update) => {
|
|
|
89
89
|
|
|
90
90
|
```typescript
|
|
91
91
|
import {deleteKeysWithPattern, useRedisAuthState} from 'baileys-redis-auth'
|
|
92
|
-
import makeWASocket, {DisconnectReason} from '
|
|
92
|
+
import makeWASocket, {DisconnectReason} from 'baileys'
|
|
93
93
|
import type {Boom} from '@hapi/boom'
|
|
94
94
|
|
|
95
95
|
async function startWhatsApp() {
|
|
@@ -119,7 +119,7 @@ async function startWhatsApp() {
|
|
|
119
119
|
// THIS IS CRITICAL: Clear Redis session on logout
|
|
120
120
|
await deleteKeysWithPattern({
|
|
121
121
|
redis,
|
|
122
|
-
|
|
122
|
+
sessionId: sessionPrefix,
|
|
123
123
|
logger: console.log // Optional: pass logger for debugging
|
|
124
124
|
})
|
|
125
125
|
console.log('✅ Session cleared successfully')
|
|
@@ -164,7 +164,7 @@ await sock.logout()
|
|
|
164
164
|
|
|
165
165
|
```typescript
|
|
166
166
|
await sock.logout()
|
|
167
|
-
await deleteKeysWithPattern({redis,
|
|
167
|
+
await deleteKeysWithPattern({redis, sessionId: 'session'})
|
|
168
168
|
// Race condition - might clear before logout message is sent
|
|
169
169
|
```
|
|
170
170
|
|
|
@@ -173,7 +173,7 @@ await deleteKeysWithPattern({redis, pattern: 'session:*'})
|
|
|
173
173
|
```typescript
|
|
174
174
|
sock.ev.on('connection.update', async (update) => {
|
|
175
175
|
if (connection === 'close' && statusCode === DisconnectReason.loggedOut) {
|
|
176
|
-
await deleteKeysWithPattern({redis,
|
|
176
|
+
await deleteKeysWithPattern({redis, sessionId: 'session'})
|
|
177
177
|
}
|
|
178
178
|
})
|
|
179
179
|
|
|
@@ -188,7 +188,7 @@ await sock.logout() // Cleanup happens automatically
|
|
|
188
188
|
```typescript
|
|
189
189
|
deleteKeysWithPattern({
|
|
190
190
|
redis: RedisClient, // Redis client from useRedisAuthState
|
|
191
|
-
|
|
191
|
+
sessionId: string, // Session ID (e.g., 'session')
|
|
192
192
|
logger?: (message: string, ...args: unknown[]) => void // Optional logger function
|
|
193
193
|
}): Promise<void>
|
|
194
194
|
```
|
|
@@ -198,7 +198,7 @@ deleteKeysWithPattern({
|
|
|
198
198
|
```typescript
|
|
199
199
|
deleteHSetKeys({
|
|
200
200
|
redis: RedisClient, // Redis client from useRedisAuthStateWithHSet
|
|
201
|
-
|
|
201
|
+
sessionId: string, // Session prefix (e.g., 'session')
|
|
202
202
|
logger?: (message: string, ...args: unknown[]) => void // Optional logger function
|
|
203
203
|
}): Promise<void>
|
|
204
204
|
```
|
package/README.md
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
# baileys-redis-auth
|
|
2
2
|
|
|
3
|
+
✅ **Baileys v7.0.0-rc.9 Compatible** - aligned with current latest npm release
|
|
4
|
+
|
|
3
5
|
`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
6
|
|
|
5
7
|
This library provides flexible ways to store authentication data in Redis, using either simple key-value pairs or Redis Hashes for optimized storage.
|
|
6
8
|
|
|
9
|
+
## NPM Package
|
|
10
|
+
|
|
11
|
+
- Package page: https://www.npmjs.com/package/baileys-redis-auth
|
|
12
|
+
|
|
7
13
|
## Prerequisites
|
|
8
14
|
|
|
9
15
|
Before using `baileys-redis-auth`, ensure you have the following installed and configured:
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
- **Node.js:** Version 18.x or higher is recommended.
|
|
18
|
+
- **Redis:** A running Redis server instance. You'll need its connection details (host, port, password if any).
|
|
19
|
+
- **Baileys:** This library is an auth handler for Baileys, so you should have Baileys as part of your project.
|
|
14
20
|
|
|
15
21
|
## Installation
|
|
16
22
|
|
|
@@ -22,168 +28,295 @@ npm install baileys-redis-auth
|
|
|
22
28
|
|
|
23
29
|
### Using `useRedisAuthStateWithHSet` (Recommended)
|
|
24
30
|
|
|
25
|
-
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
|
|
31
|
+
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. This approach is generally more efficient and organized, especially when managing multiple Baileys sessions.
|
|
26
32
|
|
|
27
33
|
**Parameters:**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
|
|
35
|
+
- `redisOptions`: An object containing your Redis server connection details (e.g., `host`, `port`, `password`). This is passed directly to the `ioredis` constructor.
|
|
36
|
+
- `sessionId`: A string used to identify and namespace your Baileys session data in Redis. For example, if your `sessionId` is `'user-123'`, all data for this session will be stored under a Redis key like `user-123:auth`. This allows you to manage multiple independent Baileys sessions in the same Redis database.
|
|
37
|
+
- `logger` (optional): A function `(message: string, ...args: unknown[]) => void` for logging Redis connection events. Pass `console.log` or your custom logger function.
|
|
31
38
|
|
|
32
39
|
```typescript
|
|
33
|
-
import {useRedisAuthStateWithHSet, deleteHSetKeys} from 'baileys-redis-auth'
|
|
34
|
-
import Redis, { RedisOptions } from 'ioredis'
|
|
40
|
+
import { useRedisAuthStateWithHSet, deleteHSetKeys } from 'baileys-redis-auth'
|
|
41
|
+
import Redis, { RedisOptions } from 'ioredis'
|
|
35
42
|
|
|
36
43
|
// Define your Redis connection options
|
|
37
44
|
const redisOptions: RedisOptions = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
45
|
+
host: 'localhost',
|
|
46
|
+
port: 6379
|
|
47
|
+
// password: 'your_redis_password', // Uncomment if your Redis has a password
|
|
48
|
+
}
|
|
42
49
|
|
|
43
|
-
// Define a unique
|
|
44
|
-
const
|
|
50
|
+
// Define a unique session identifier for this Baileys session
|
|
51
|
+
const sessionId = 'baileys_session_1'
|
|
45
52
|
|
|
46
53
|
async function initializeBaileysWithHSet() {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
54
|
+
// useRedisAuthStateWithHSet creates its own Redis instance internally based on redisOptions
|
|
55
|
+
|
|
56
|
+
const {
|
|
57
|
+
state,
|
|
58
|
+
saveCreds,
|
|
59
|
+
redis: authRedisInstance
|
|
60
|
+
} = await useRedisAuthStateWithHSet(
|
|
61
|
+
redisOptions,
|
|
62
|
+
sessionId,
|
|
63
|
+
console.log // Optional: pass logger for Redis connection events
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// 'state' will be used to initialize Baileys
|
|
67
|
+
// 'saveCreds' is a function to periodically save the authentication state
|
|
68
|
+
// 'authRedisInstance' is the Redis client instance used by the auth state hook
|
|
69
|
+
|
|
70
|
+
console.log('Baileys state loaded using HSet method.')
|
|
71
|
+
|
|
72
|
+
// Example: Listen for Redis connection events on the instance returned by the hook
|
|
73
|
+
authRedisInstance.on('connect', () =>
|
|
74
|
+
console.log(`Redis (from hook) connected for session: ${sessionId}`)
|
|
75
|
+
)
|
|
76
|
+
authRedisInstance.on('error', (err) =>
|
|
77
|
+
console.error(`Redis (from hook) error for session ${sessionId}:`, err)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
// ... your Baileys setup code using 'state' and 'saveCreds'
|
|
81
|
+
|
|
82
|
+
// Example of how to delete all data for this specific session if needed:
|
|
83
|
+
// await deleteHSetKeys({redis: authRedisInstance, sessionId: sessionId});
|
|
84
|
+
// console.log(`Authentication data for session ${sessionId} deleted.`);
|
|
76
85
|
}
|
|
77
86
|
|
|
78
|
-
initializeBaileysWithHSet().catch(console.error)
|
|
87
|
+
initializeBaileysWithHSet().catch(console.error)
|
|
79
88
|
```
|
|
80
89
|
|
|
81
90
|
#### Deleting Session Data (`deleteHSetKeys`)
|
|
82
91
|
|
|
83
|
-
To remove all authentication data associated with a specific session
|
|
92
|
+
To remove all authentication data associated with a specific session used with `useRedisAuthStateWithHSet`, you can use the `deleteHSetKeys` utility function.
|
|
84
93
|
|
|
85
94
|
**Usage:**
|
|
86
95
|
|
|
87
96
|
```typescript
|
|
88
|
-
import { deleteHSetKeys } from 'baileys-redis-auth'
|
|
89
|
-
import Redis, { RedisOptions } from 'ioredis'
|
|
97
|
+
import { deleteHSetKeys } from 'baileys-redis-auth'
|
|
98
|
+
import Redis, { RedisOptions } from 'ioredis' // Or use the instance from useRedisAuthStateWithHSet
|
|
90
99
|
|
|
91
100
|
// Assuming 'authRedisInstance' is the Redis instance from useRedisAuthStateWithHSet
|
|
92
101
|
// or a new instance configured with the same options.
|
|
93
102
|
// const redisClient = new Redis(redisOptions);
|
|
94
|
-
// const
|
|
103
|
+
// const sessionIdToDelete = 'baileys_session_1';
|
|
95
104
|
|
|
96
|
-
// await deleteHSetKeys({redis: authRedisInstance,
|
|
97
|
-
// console.log(`All HSet data for
|
|
105
|
+
// await deleteHSetKeys({redis: authRedisInstance, sessionId: sessionIdToDelete});
|
|
106
|
+
// console.log(`All HSet data for session '${sessionIdToDelete}' deleted.`);
|
|
98
107
|
```
|
|
99
108
|
|
|
100
109
|
**Parameters:**
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
|
|
111
|
+
- `options`: An object with the following properties:
|
|
112
|
+
- `redis`: An active `ioredis` client instance.
|
|
113
|
+
- `sessionId`: The session identifier string (e.g., `'baileys_session_1'`) whose data needs to be deleted. This corresponds to the `sessionId` you used with `useRedisAuthStateWithHSet`.
|
|
114
|
+
- `logger` (optional): A function for logging deletion operations.
|
|
105
115
|
|
|
106
116
|
### Using `useRedisAuthState`
|
|
107
117
|
|
|
108
|
-
This method stores each piece of authentication data as a separate key-value pair in Redis, prefixed by the `
|
|
118
|
+
This method stores each piece of authentication data as a separate key-value pair in Redis, prefixed by the `sessionId` string. While functional, it can lead to a larger number of individual keys in your Redis database compared to the HSET method.
|
|
109
119
|
|
|
110
120
|
**Parameters:**
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
|
|
122
|
+
- `redisOptions`: An object containing your Redis server connection details (e.g., `host`, `port`, `password`). This is passed directly to the `ioredis` constructor.
|
|
123
|
+
- `sessionId`: A string used to identify and prefix all Redis keys for this Baileys session. For example, if your `sessionId` is `'user-456'`, keys will be stored like `user-456:creds`, `user-456:pre-key-1`, etc.
|
|
124
|
+
- `logger` (optional): A function `(message: string, ...args: unknown[]) => void` for logging Redis connection events. Pass `console.log` or your custom logger function.
|
|
114
125
|
|
|
115
126
|
```typescript
|
|
116
|
-
import {useRedisAuthState, deleteKeysWithPattern} from 'baileys-redis-auth'
|
|
117
|
-
import Redis, { RedisOptions } from 'ioredis'
|
|
127
|
+
import { useRedisAuthState, deleteKeysWithPattern } from 'baileys-redis-auth'
|
|
128
|
+
import Redis, { RedisOptions } from 'ioredis'
|
|
118
129
|
|
|
119
130
|
// Define your Redis connection options
|
|
120
131
|
const redisOptions: RedisOptions = {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
132
|
+
host: 'localhost',
|
|
133
|
+
port: 6379
|
|
134
|
+
// password: 'your_redis_password', // Uncomment if your Redis has a password
|
|
135
|
+
}
|
|
125
136
|
|
|
126
|
-
// Define a unique
|
|
127
|
-
const
|
|
137
|
+
// Define a unique session identifier for this Baileys session
|
|
138
|
+
const sessionId = 'baileys_session_2'
|
|
128
139
|
|
|
129
140
|
async function initializeBaileysSimple() {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
141
|
+
// useRedisAuthState creates its own Redis instance internally based on redisOptions
|
|
142
|
+
|
|
143
|
+
const {
|
|
144
|
+
state,
|
|
145
|
+
saveCreds,
|
|
146
|
+
redis: authRedisInstance
|
|
147
|
+
} = await useRedisAuthState(
|
|
148
|
+
redisOptions,
|
|
149
|
+
sessionId,
|
|
150
|
+
console.log // Optional: pass logger for Redis connection events
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
// 'state' will be used to initialize Baileys
|
|
154
|
+
// 'saveCreds' is a function to periodically save the authentication state
|
|
155
|
+
// 'authRedisInstance' is the Redis client instance used by the auth state hook
|
|
156
|
+
|
|
157
|
+
console.log('Baileys state loaded using simple key-value method.')
|
|
158
|
+
|
|
159
|
+
// Example: Listen for Redis connection events on the instance returned by the hook
|
|
160
|
+
authRedisInstance.on('connect', () =>
|
|
161
|
+
console.log(`Redis (from hook) connected for session: ${sessionId}`)
|
|
162
|
+
)
|
|
163
|
+
authRedisInstance.on('error', (err) =>
|
|
164
|
+
console.error(`Redis (from hook) error for session ${sessionId}:`, err)
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
// ... your Baileys setup code using 'state' and 'saveCreds'
|
|
168
|
+
|
|
169
|
+
// Example of how to delete all keys for this specific session if needed:
|
|
170
|
+
// await deleteKeysWithPattern({redis: authRedisInstance, sessionId: sessionId});
|
|
171
|
+
// console.log(`Authentication data for session ${sessionId} deleted.`);
|
|
157
172
|
}
|
|
158
173
|
|
|
159
|
-
initializeBaileysSimple().catch(console.error)
|
|
174
|
+
initializeBaileysSimple().catch(console.error)
|
|
160
175
|
```
|
|
161
176
|
|
|
162
177
|
#### Deleting Session Data (`deleteKeysWithPattern`)
|
|
163
178
|
|
|
164
|
-
To remove all authentication data associated with a specific session
|
|
179
|
+
To remove all authentication data associated with a specific session used with `useRedisAuthState`, you can use the `deleteKeysWithPattern` utility function. This function deletes all Redis keys for the given session.
|
|
165
180
|
|
|
166
181
|
**Usage:**
|
|
167
182
|
|
|
168
183
|
```typescript
|
|
169
|
-
import { deleteKeysWithPattern } from 'baileys-redis-auth'
|
|
170
|
-
import Redis, { RedisOptions } from 'ioredis'
|
|
184
|
+
import { deleteKeysWithPattern } from 'baileys-redis-auth'
|
|
185
|
+
import Redis, { RedisOptions } from 'ioredis' // Or use the instance from useRedisAuthState
|
|
171
186
|
|
|
172
187
|
// Assuming 'authRedisInstance' is the Redis instance from useRedisAuthState
|
|
173
188
|
// or a new instance configured with the same options.
|
|
174
189
|
// const redisClient = new Redis(redisOptions);
|
|
175
|
-
// const
|
|
190
|
+
// const sessionIdToDelete = 'baileys_session_2';
|
|
176
191
|
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
// console.log(`All keys matching pattern '${sessionPrefixToDelete}:*' deleted.`);
|
|
192
|
+
// await deleteKeysWithPattern({redis: authRedisInstance, sessionId: sessionIdToDelete});
|
|
193
|
+
// console.log(`All keys for session '${sessionIdToDelete}' deleted.`);
|
|
180
194
|
```
|
|
181
195
|
|
|
182
196
|
**Parameters:**
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
197
|
+
|
|
198
|
+
- `options`: An object with the following properties:
|
|
199
|
+
- `redis`: An active `ioredis` client instance.
|
|
200
|
+
- `sessionId`: The session identifier string (e.g., `'baileys_session_2'`) whose data needs to be deleted. This corresponds to the `sessionId` you used with `useRedisAuthState`.
|
|
201
|
+
- `logger` (optional): A function for logging deletion operations.
|
|
202
|
+
|
|
203
|
+
## Listing Active Sessions
|
|
204
|
+
|
|
205
|
+
The library provides utility functions to discover all active sessions stored in Redis. This is useful for managing multiple WhatsApp connections or performing administrative tasks.
|
|
206
|
+
|
|
207
|
+
### `listHSetSessions` - List Hash-Based Sessions
|
|
208
|
+
|
|
209
|
+
Lists all session identifiers stored using the `useRedisAuthStateWithHSet` method.
|
|
210
|
+
|
|
211
|
+
**Usage:**
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { listHSetSessions } from 'baileys-redis-auth'
|
|
215
|
+
import Redis from 'ioredis'
|
|
216
|
+
|
|
217
|
+
const redis = new Redis({ host: 'localhost', port: 6379 })
|
|
218
|
+
|
|
219
|
+
async function showAllHashSessions() {
|
|
220
|
+
const sessions = await listHSetSessions({
|
|
221
|
+
redis,
|
|
222
|
+
logger: console.log // Optional: pass logger for debugging
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
console.log('Active Hash-based sessions:', sessions)
|
|
226
|
+
// Output: ['baileys_session_1', 'user-123', 'bot-789']
|
|
227
|
+
|
|
228
|
+
// You can now iterate and manage these sessions
|
|
229
|
+
for (const sessionId of sessions) {
|
|
230
|
+
console.log(`Found session: ${sessionId}`)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
showAllHashSessions().catch(console.error)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Parameters:**
|
|
238
|
+
|
|
239
|
+
- `options`: An object with the following properties:
|
|
240
|
+
- `redis`: An active `ioredis` client instance.
|
|
241
|
+
- `logger` (optional): A function for logging scan operations.
|
|
242
|
+
|
|
243
|
+
**Returns:** `Promise<string[]>` - An array of session identifiers.
|
|
244
|
+
|
|
245
|
+
### `listSessions` - List Key-Value Based Sessions
|
|
246
|
+
|
|
247
|
+
Lists all session identifiers stored using the `useRedisAuthState` method.
|
|
248
|
+
|
|
249
|
+
**Usage:**
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { listSessions } from 'baileys-redis-auth'
|
|
253
|
+
import Redis from 'ioredis'
|
|
254
|
+
|
|
255
|
+
const redis = new Redis({ host: 'localhost', port: 6379 })
|
|
256
|
+
|
|
257
|
+
async function showAllKeyValueSessions() {
|
|
258
|
+
const sessions = await listSessions({
|
|
259
|
+
redis,
|
|
260
|
+
logger: console.log // Optional: pass logger for debugging
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
console.log('Active key-value based sessions:', sessions)
|
|
264
|
+
// Output: ['baileys_session_2', 'user-456', 'bot-012']
|
|
265
|
+
|
|
266
|
+
// You can now iterate and manage these sessions
|
|
267
|
+
for (const sessionId of sessions) {
|
|
268
|
+
console.log(`Found session: ${sessionId}`)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
showAllKeyValueSessions().catch(console.error)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Parameters:**
|
|
276
|
+
|
|
277
|
+
- `options`: An object with the following properties:
|
|
278
|
+
- `redis`: An active `ioredis` client instance.
|
|
279
|
+
- `logger` (optional): A function for logging scan operations.
|
|
280
|
+
|
|
281
|
+
**Returns:** `Promise<string[]>` - An array of unique session identifiers.
|
|
282
|
+
|
|
283
|
+
### Practical Example: Managing Multiple Sessions
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import {
|
|
287
|
+
listHSetSessions,
|
|
288
|
+
listSessions,
|
|
289
|
+
deleteHSetKeys,
|
|
290
|
+
deleteKeysWithPattern
|
|
291
|
+
} from 'baileys-redis-auth'
|
|
292
|
+
import Redis from 'ioredis'
|
|
293
|
+
|
|
294
|
+
const redis = new Redis({ host: 'localhost', port: 6379 })
|
|
295
|
+
|
|
296
|
+
async function manageAllSessions() {
|
|
297
|
+
// List all Hash-based sessions
|
|
298
|
+
const hashSessions = await listHSetSessions({ redis })
|
|
299
|
+
console.log('Hash-based sessions:', hashSessions)
|
|
300
|
+
|
|
301
|
+
// List all key-value based sessions
|
|
302
|
+
const kvSessions = await listSessions({ redis })
|
|
303
|
+
console.log('Key-value based sessions:', kvSessions)
|
|
304
|
+
|
|
305
|
+
// Delete a specific Hash session
|
|
306
|
+
if (hashSessions.includes('old-session')) {
|
|
307
|
+
await deleteHSetKeys({ redis, sessionId: 'old-session' })
|
|
308
|
+
console.log('Deleted old-session')
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Delete a specific key-value session
|
|
312
|
+
if (kvSessions.includes('inactive-session')) {
|
|
313
|
+
await deleteKeysWithPattern({ redis, sessionId: 'inactive-session' })
|
|
314
|
+
console.log('Deleted inactive-session')
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
manageAllSessions().catch(console.error)
|
|
319
|
+
```
|
|
187
320
|
|
|
188
321
|
## Logout and Session Cleanup
|
|
189
322
|
|
|
@@ -192,18 +325,22 @@ import Redis, { RedisOptions } from 'ioredis'; // Or use the instance from useRe
|
|
|
192
325
|
### Proper Logout Implementation
|
|
193
326
|
|
|
194
327
|
```typescript
|
|
195
|
-
import {deleteKeysWithPattern, useRedisAuthState} from 'baileys-redis-auth'
|
|
196
|
-
import makeWASocket, {DisconnectReason} from '
|
|
197
|
-
import type {Boom} from '@hapi/boom'
|
|
328
|
+
import { deleteKeysWithPattern, useRedisAuthState } from 'baileys-redis-auth'
|
|
329
|
+
import makeWASocket, { DisconnectReason } from 'baileys'
|
|
330
|
+
import type { Boom } from '@hapi/boom'
|
|
198
331
|
|
|
199
|
-
const
|
|
200
|
-
const {state, saveCreds, redis} = await useRedisAuthState(
|
|
332
|
+
const sessionId = 'my-session'
|
|
333
|
+
const { state, saveCreds, redis } = await useRedisAuthState(
|
|
334
|
+
redisOptions,
|
|
335
|
+
sessionId,
|
|
336
|
+
console.log
|
|
337
|
+
)
|
|
201
338
|
|
|
202
|
-
const sock = makeWASocket({auth: state})
|
|
339
|
+
const sock = makeWASocket({ auth: state })
|
|
203
340
|
|
|
204
341
|
// Handle connection updates
|
|
205
342
|
sock.ev.on('connection.update', async (update) => {
|
|
206
|
-
const {connection, lastDisconnect} = update
|
|
343
|
+
const { connection, lastDisconnect } = update
|
|
207
344
|
|
|
208
345
|
if (connection === 'close') {
|
|
209
346
|
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
|
|
@@ -212,8 +349,8 @@ sock.ev.on('connection.update', async (update) => {
|
|
|
212
349
|
// Clear Redis session on logout
|
|
213
350
|
await deleteKeysWithPattern({
|
|
214
351
|
redis,
|
|
215
|
-
|
|
216
|
-
logger: console.log
|
|
352
|
+
sessionId: sessionId,
|
|
353
|
+
logger: console.log // Optional: pass logger for debugging
|
|
217
354
|
})
|
|
218
355
|
console.log('Session cleared')
|
|
219
356
|
}
|
|
@@ -231,12 +368,14 @@ For detailed logout implementation guide, see [LOGOUT_GUIDE.md](./LOGOUT_GUIDE.m
|
|
|
231
368
|
This project includes an example script to demonstrate the usage of `baileys-redis-auth`. To run it:
|
|
232
369
|
|
|
233
370
|
1. **Clone the repository (if you haven't already):**
|
|
371
|
+
|
|
234
372
|
```bash
|
|
235
373
|
git clone https://github.com/hbinduni/baileys-redis-auth.git
|
|
236
374
|
cd baileys-redis-auth
|
|
237
375
|
```
|
|
238
376
|
|
|
239
377
|
2. **Install dependencies:**
|
|
378
|
+
|
|
240
379
|
```bash
|
|
241
380
|
npm install
|
|
242
381
|
# or
|
|
@@ -248,12 +387,14 @@ This project includes an example script to demonstrate the usage of `baileys-red
|
|
|
248
387
|
3. **Ensure you have a Redis server running** and accessible on `localhost:6379` (or update the example script with your Redis configuration).
|
|
249
388
|
|
|
250
389
|
4. **Configure environment variables:**
|
|
390
|
+
|
|
251
391
|
```bash
|
|
252
392
|
cp .env.example .env
|
|
253
393
|
# Edit .env with your Redis configuration
|
|
254
394
|
```
|
|
255
395
|
|
|
256
396
|
5. **Run the example script:**
|
|
397
|
+
|
|
257
398
|
```bash
|
|
258
399
|
npm run example
|
|
259
400
|
# or
|
|
@@ -261,10 +402,12 @@ This project includes an example script to demonstrate the usage of `baileys-red
|
|
|
261
402
|
# or
|
|
262
403
|
# bun run example
|
|
263
404
|
```
|
|
264
|
-
|
|
405
|
+
|
|
406
|
+
This command executes `tsx example/example.ts`.
|
|
265
407
|
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.
|
|
266
408
|
|
|
267
409
|
**Interactive Commands:**
|
|
410
|
+
|
|
268
411
|
- `send <phone> <message>` - Send a WhatsApp message
|
|
269
412
|
- `logout` - Logout and clear session
|
|
270
413
|
- `help` - Show available commands
|
|
@@ -286,4 +429,7 @@ Please ensure your code adheres to the existing style and that any new functiona
|
|
|
286
429
|
## License
|
|
287
430
|
|
|
288
431
|
This project is licensed under the MIT License. Refer to the license information in the `package.json` for details.
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
|
|
289
435
|
```
|
package/lib/index.d.ts
CHANGED
|
@@ -1,42 +1,221 @@
|
|
|
1
|
-
import { type AuthenticationState } from '
|
|
2
|
-
import {
|
|
1
|
+
import { type AuthenticationState } from 'baileys';
|
|
2
|
+
import { Redis, type RedisOptions } from 'ioredis';
|
|
3
|
+
type RedisClient = Redis;
|
|
4
|
+
/**
|
|
5
|
+
* Options for deleting Hash-based authentication state
|
|
6
|
+
*/
|
|
3
7
|
interface IDeleteHSetKeyOptions {
|
|
8
|
+
/** Active Redis client instance */
|
|
4
9
|
redis: RedisClient;
|
|
5
|
-
|
|
10
|
+
/** The session identifier to delete */
|
|
11
|
+
sessionId: string;
|
|
12
|
+
/** Optional logging function for debugging */
|
|
6
13
|
logger?: (message: string, ...args: unknown[]) => void;
|
|
7
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Options for deleting key-value based authentication state
|
|
17
|
+
*/
|
|
8
18
|
interface IDeleteKeysOptions {
|
|
19
|
+
/** Active Redis client instance */
|
|
9
20
|
redis: RedisClient;
|
|
10
|
-
|
|
21
|
+
/** The session identifier to delete */
|
|
22
|
+
sessionId: string;
|
|
23
|
+
/** Optional logging function for debugging */
|
|
24
|
+
logger?: (message: string, ...args: unknown[]) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Options for listing sessions
|
|
28
|
+
*/
|
|
29
|
+
interface IListSessionsOptions {
|
|
30
|
+
/** Active Redis client instance */
|
|
31
|
+
redis: RedisClient;
|
|
32
|
+
/** Optional logging function for debugging */
|
|
11
33
|
logger?: (message: string, ...args: unknown[]) => void;
|
|
12
34
|
}
|
|
13
35
|
/**
|
|
14
36
|
* Redis-based authentication state storage using Hash (HSET) - Recommended
|
|
15
|
-
*
|
|
16
|
-
*
|
|
37
|
+
*
|
|
38
|
+
* Stores all authentication data in a single Redis Hash per session.
|
|
39
|
+
* This approach is more efficient than key-value storage for Redis memory and operations.
|
|
40
|
+
* All authentication state (credentials, keys, and signals) is stored under a single hash key.
|
|
41
|
+
*
|
|
42
|
+
* @param redisOptions - Configuration options for the Redis client connection
|
|
43
|
+
* @param sessionId - Session identifier for the Redis hash key (default: 'session'). The hash key will be `${sessionId}:auth`
|
|
44
|
+
* @param logger - Optional logging function for debugging and monitoring Redis operations
|
|
45
|
+
*
|
|
46
|
+
* @returns Promise that resolves to an object containing:
|
|
47
|
+
* - `state`: The Baileys AuthenticationState object with creds and keys methods
|
|
48
|
+
* - `saveCreds`: Function to manually save credentials to Redis
|
|
49
|
+
* - `redis`: The Redis client instance for manual operations
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const { state, saveCreds, redis } = await useRedisAuthStateWithHSet(
|
|
54
|
+
* { host: 'localhost', port: 6379 },
|
|
55
|
+
* 'my-whatsapp-session',
|
|
56
|
+
* console.log
|
|
57
|
+
* );
|
|
58
|
+
*
|
|
59
|
+
* const conn = makeWASocket({ auth: state });
|
|
60
|
+
* // Credentials are automatically saved on state changes
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @see {@link useRedisAuthState} for key-value based storage alternative
|
|
17
64
|
*/
|
|
18
|
-
export declare const useRedisAuthStateWithHSet: (redisOptions: RedisOptions,
|
|
65
|
+
export declare const useRedisAuthStateWithHSet: (redisOptions: RedisOptions, sessionId?: string, logger?: (message: string, ...args: unknown[]) => void) => Promise<{
|
|
19
66
|
state: AuthenticationState;
|
|
20
67
|
saveCreds: () => Promise<void>;
|
|
21
68
|
redis: RedisClient;
|
|
22
69
|
}>;
|
|
23
70
|
/**
|
|
24
|
-
* Deletes all authentication data for a specific
|
|
71
|
+
* Deletes all authentication data for a specific session using Hash (HSET)
|
|
72
|
+
*
|
|
73
|
+
* Removes the entire Redis hash containing all authentication state for the given session.
|
|
74
|
+
* This is the cleanup function for sessions created with `useRedisAuthStateWithHSet`.
|
|
75
|
+
*
|
|
76
|
+
* @param options - Configuration object
|
|
77
|
+
* @param options.redis - Active Redis client instance
|
|
78
|
+
* @param options.sessionId - The session identifier to delete (e.g., 'session', 'my-whatsapp-session')
|
|
79
|
+
* @param options.logger - Optional logging function for debugging
|
|
80
|
+
*
|
|
81
|
+
* @returns Promise that resolves when the deletion is complete
|
|
82
|
+
*
|
|
83
|
+
* @throws {Error} If Redis deletion operation fails
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const { redis } = await useRedisAuthStateWithHSet({ host: 'localhost' }, 'session-123');
|
|
88
|
+
*
|
|
89
|
+
* // Later, to logout and clean up:
|
|
90
|
+
* await deleteHSetKeys({
|
|
91
|
+
* redis,
|
|
92
|
+
* sessionId: 'session-123',
|
|
93
|
+
* logger: console.log
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @see {@link useRedisAuthStateWithHSet} for the corresponding storage function
|
|
25
98
|
*/
|
|
26
|
-
export declare const deleteHSetKeys: ({ redis,
|
|
99
|
+
export declare const deleteHSetKeys: ({ redis, sessionId, logger }: IDeleteHSetKeyOptions) => Promise<void>;
|
|
27
100
|
/**
|
|
28
101
|
* Redis-based authentication state storage using key-value pairs
|
|
29
|
-
*
|
|
30
|
-
*
|
|
102
|
+
*
|
|
103
|
+
* Stores each piece of authentication data as a separate Redis key with the pattern `${sessionId}:${key}`.
|
|
104
|
+
* This approach is less efficient than the Hash-based storage but offers more compatibility with
|
|
105
|
+
* existing systems and allows for more granular key management and expiration.
|
|
106
|
+
*
|
|
107
|
+
* @param redisOptions - Configuration options for the Redis client connection
|
|
108
|
+
* @param sessionId - Session identifier for Redis keys (default: 'session'). Each key will be `${sessionId}:${keyname}`
|
|
109
|
+
* @param logger - Optional logging function for debugging and monitoring Redis operations
|
|
110
|
+
*
|
|
111
|
+
* @returns Promise that resolves to an object containing:
|
|
112
|
+
* - `state`: The Baileys AuthenticationState object with creds and keys methods
|
|
113
|
+
* - `saveCreds`: Function to manually save credentials to Redis
|
|
114
|
+
* - `redis`: The Redis client instance for manual operations
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const { state, saveCreds, redis } = await useRedisAuthState(
|
|
119
|
+
* { host: 'localhost', port: 6379 },
|
|
120
|
+
* 'my-whatsapp-session',
|
|
121
|
+
* console.log
|
|
122
|
+
* );
|
|
123
|
+
*
|
|
124
|
+
* const conn = makeWASocket({ auth: state });
|
|
125
|
+
* // Credentials are automatically saved on state changes
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @see {@link useRedisAuthStateWithHSet} for the recommended Hash-based storage alternative
|
|
31
129
|
*/
|
|
32
|
-
export declare const useRedisAuthState: (redisOptions: RedisOptions,
|
|
130
|
+
export declare const useRedisAuthState: (redisOptions: RedisOptions, sessionId?: string, logger?: (message: string, ...args: unknown[]) => void) => Promise<{
|
|
33
131
|
state: AuthenticationState;
|
|
34
132
|
saveCreds: () => Promise<void>;
|
|
35
133
|
redis: RedisClient;
|
|
36
134
|
}>;
|
|
37
135
|
/**
|
|
38
|
-
* Deletes all authentication keys
|
|
39
|
-
*
|
|
136
|
+
* Deletes all authentication keys for a specific session using key-value approach
|
|
137
|
+
*
|
|
138
|
+
* Uses Redis SCAN command to safely iterate through keys without blocking the Redis server.
|
|
139
|
+
* This is the cleanup function for sessions created with `useRedisAuthState`.
|
|
140
|
+
* The SCAN operation is cursor-based and processes keys in batches of 100.
|
|
141
|
+
*
|
|
142
|
+
* @param options - Configuration object
|
|
143
|
+
* @param options.redis - Active Redis client instance
|
|
144
|
+
* @param options.sessionId - The session identifier to delete (e.g., 'session', 'my-whatsapp-session')
|
|
145
|
+
* @param options.logger - Optional logging function for debugging and monitoring deletion progress
|
|
146
|
+
*
|
|
147
|
+
* @returns Promise that resolves when all matching keys have been deleted
|
|
148
|
+
*
|
|
149
|
+
* @throws {Error} If Redis SCAN or UNLINK operations fail
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* const { redis } = await useRedisAuthState({ host: 'localhost' }, 'session-123');
|
|
154
|
+
*
|
|
155
|
+
* // Later, to logout and clean up all keys for this session:
|
|
156
|
+
* await deleteKeysWithPattern({
|
|
157
|
+
* redis,
|
|
158
|
+
* sessionId: 'session-123',
|
|
159
|
+
* logger: console.log
|
|
160
|
+
* });
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @see {@link useRedisAuthState} for the corresponding storage function
|
|
164
|
+
* @see {@link deleteHSetKeys} for Hash-based storage cleanup
|
|
165
|
+
*/
|
|
166
|
+
export declare const deleteKeysWithPattern: ({ redis, sessionId, logger }: IDeleteKeysOptions) => Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* Lists all session identifiers stored using Hash (HSET) approach
|
|
169
|
+
*
|
|
170
|
+
* Scans Redis for all hash keys with the pattern `*:auth` and extracts the session identifiers.
|
|
171
|
+
* This is useful for discovering all active sessions created with `useRedisAuthStateWithHSet`.
|
|
172
|
+
*
|
|
173
|
+
* @param options - Configuration object
|
|
174
|
+
* @param options.redis - Active Redis client instance
|
|
175
|
+
* @param options.logger - Optional logging function for debugging
|
|
176
|
+
*
|
|
177
|
+
* @returns Promise that resolves to an array of session identifiers
|
|
178
|
+
*
|
|
179
|
+
* @throws {Error} If Redis SCAN operation fails
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* const redis = new Redis({ host: 'localhost' });
|
|
184
|
+
*
|
|
185
|
+
* const sessions = await listHSetSessions({ redis, logger: console.log });
|
|
186
|
+
* console.log('Active sessions:', sessions);
|
|
187
|
+
* // Output: ['session-123', 'user-456', 'bot-789']
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @see {@link useRedisAuthStateWithHSet} for the corresponding storage function
|
|
191
|
+
* @see {@link listSessions} for key-value based session listing
|
|
192
|
+
*/
|
|
193
|
+
export declare const listHSetSessions: ({ redis, logger }: IListSessionsOptions) => Promise<string[]>;
|
|
194
|
+
/**
|
|
195
|
+
* Lists all session identifiers stored using key-value approach
|
|
196
|
+
*
|
|
197
|
+
* Scans Redis for all keys with the pattern `*:creds` and extracts unique session identifiers.
|
|
198
|
+
* This is useful for discovering all active sessions created with `useRedisAuthState`.
|
|
199
|
+
*
|
|
200
|
+
* @param options - Configuration object
|
|
201
|
+
* @param options.redis - Active Redis client instance
|
|
202
|
+
* @param options.logger - Optional logging function for debugging
|
|
203
|
+
*
|
|
204
|
+
* @returns Promise that resolves to an array of unique session identifiers
|
|
205
|
+
*
|
|
206
|
+
* @throws {Error} If Redis SCAN operation fails
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* const redis = new Redis({ host: 'localhost' });
|
|
211
|
+
*
|
|
212
|
+
* const sessions = await listSessions({ redis, logger: console.log });
|
|
213
|
+
* console.log('Active sessions:', sessions);
|
|
214
|
+
* // Output: ['session-123', 'user-456', 'bot-789']
|
|
215
|
+
* ```
|
|
216
|
+
*
|
|
217
|
+
* @see {@link useRedisAuthState} for the corresponding storage function
|
|
218
|
+
* @see {@link listHSetSessions} for Hash-based session listing
|
|
40
219
|
*/
|
|
41
|
-
export declare const
|
|
220
|
+
export declare const listSessions: ({ redis, logger }: IListSessionsOptions) => Promise<string[]>;
|
|
42
221
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -1,40 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.deleteKeysWithPattern = exports.useRedisAuthState = exports.deleteHSetKeys = exports.useRedisAuthStateWithHSet = void 0;
|
|
7
|
-
const baileys_1 = require("@whiskeysockets/baileys");
|
|
8
|
-
const ioredis_1 = __importDefault(require("ioredis"));
|
|
1
|
+
import { BufferJSON, initAuthCreds, proto, } from 'baileys';
|
|
2
|
+
import { Redis } from 'ioredis';
|
|
9
3
|
/**
|
|
10
4
|
* Sanitizes a string to make it safe for use as a Redis key
|
|
11
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* Replaces problematic characters that might cause issues in Redis keys:
|
|
7
|
+
* - Forward slashes (/) are replaced with double underscores (__)
|
|
8
|
+
* - Colons (:) are replaced with hyphens (-)
|
|
9
|
+
*
|
|
10
|
+
* @param file - The string to sanitize
|
|
11
|
+
* @returns The sanitized string safe for use as a Redis key component
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
12
14
|
*/
|
|
13
15
|
const fixFileName = (file) => file.replace(/\//g, '__').replace(/:/g, '-');
|
|
14
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Creates a namespaced Redis key by combining sessionId and key
|
|
18
|
+
*
|
|
19
|
+
* @param key - The key name
|
|
20
|
+
* @param sessionId - The session identifier
|
|
21
|
+
* @returns The combined key in the format `${sessionId}:${key}`
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
const createKey = (key, sessionId) => `${sessionId}:${key}`;
|
|
15
26
|
/**
|
|
16
27
|
* Redis-based authentication state storage using Hash (HSET) - Recommended
|
|
17
|
-
*
|
|
18
|
-
*
|
|
28
|
+
*
|
|
29
|
+
* Stores all authentication data in a single Redis Hash per session.
|
|
30
|
+
* This approach is more efficient than key-value storage for Redis memory and operations.
|
|
31
|
+
* All authentication state (credentials, keys, and signals) is stored under a single hash key.
|
|
32
|
+
*
|
|
33
|
+
* @param redisOptions - Configuration options for the Redis client connection
|
|
34
|
+
* @param sessionId - Session identifier for the Redis hash key (default: 'session'). The hash key will be `${sessionId}:auth`
|
|
35
|
+
* @param logger - Optional logging function for debugging and monitoring Redis operations
|
|
36
|
+
*
|
|
37
|
+
* @returns Promise that resolves to an object containing:
|
|
38
|
+
* - `state`: The Baileys AuthenticationState object with creds and keys methods
|
|
39
|
+
* - `saveCreds`: Function to manually save credentials to Redis
|
|
40
|
+
* - `redis`: The Redis client instance for manual operations
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const { state, saveCreds, redis } = await useRedisAuthStateWithHSet(
|
|
45
|
+
* { host: 'localhost', port: 6379 },
|
|
46
|
+
* 'my-whatsapp-session',
|
|
47
|
+
* console.log
|
|
48
|
+
* );
|
|
49
|
+
*
|
|
50
|
+
* const conn = makeWASocket({ auth: state });
|
|
51
|
+
* // Credentials are automatically saved on state changes
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @see {@link useRedisAuthState} for key-value based storage alternative
|
|
19
55
|
*/
|
|
20
|
-
const useRedisAuthStateWithHSet = async (redisOptions,
|
|
21
|
-
const redis = new
|
|
56
|
+
export const useRedisAuthStateWithHSet = async (redisOptions, sessionId = 'session', logger) => {
|
|
57
|
+
const redis = new Redis(redisOptions);
|
|
22
58
|
redis.on('connect', async () => {
|
|
23
|
-
const redisClientName = `baileys-auth-${
|
|
59
|
+
const redisClientName = `baileys-auth-${sessionId}`;
|
|
24
60
|
await redis.client('SETNAME', redisClientName);
|
|
25
|
-
logger
|
|
61
|
+
logger?.(`Redis client name set to ${redisClientName}`);
|
|
26
62
|
});
|
|
27
63
|
const writeData = async (key, data) => {
|
|
28
|
-
await redis.hset(createKey('auth',
|
|
64
|
+
await redis.hset(createKey('auth', sessionId), key, JSON.stringify(data, BufferJSON.replacer));
|
|
29
65
|
};
|
|
30
66
|
const readData = async (key) => {
|
|
31
|
-
const data = await redis.hget(createKey('auth',
|
|
32
|
-
return data ? JSON.parse(data,
|
|
67
|
+
const data = await redis.hget(createKey('auth', sessionId), key);
|
|
68
|
+
return data ? JSON.parse(data, BufferJSON.reviver) : null;
|
|
33
69
|
};
|
|
34
70
|
const removeData = async (key) => {
|
|
35
|
-
await redis.hdel(createKey('auth',
|
|
71
|
+
await redis.hdel(createKey('auth', sessionId), key);
|
|
36
72
|
};
|
|
37
|
-
const creds = (await readData('creds')) ||
|
|
73
|
+
const creds = (await readData('creds')) || initAuthCreds();
|
|
38
74
|
return {
|
|
39
75
|
state: {
|
|
40
76
|
creds,
|
|
@@ -45,7 +81,7 @@ const useRedisAuthStateWithHSet = async (redisOptions, prefix = 'session', logge
|
|
|
45
81
|
const key = `${type}-${fixFileName(id)}`;
|
|
46
82
|
const value = await readData(key);
|
|
47
83
|
if (value) {
|
|
48
|
-
data[id] = (type === 'app-state-sync-key' ?
|
|
84
|
+
data[id] = (type === 'app-state-sync-key' ? proto.Message.AppStateSyncKeyData.fromObject(value) : value);
|
|
49
85
|
}
|
|
50
86
|
}));
|
|
51
87
|
return data;
|
|
@@ -74,46 +110,94 @@ const useRedisAuthStateWithHSet = async (redisOptions, prefix = 'session', logge
|
|
|
74
110
|
redis,
|
|
75
111
|
};
|
|
76
112
|
};
|
|
77
|
-
exports.useRedisAuthStateWithHSet = useRedisAuthStateWithHSet;
|
|
78
113
|
/**
|
|
79
|
-
* Deletes all authentication data for a specific
|
|
114
|
+
* Deletes all authentication data for a specific session using Hash (HSET)
|
|
115
|
+
*
|
|
116
|
+
* Removes the entire Redis hash containing all authentication state for the given session.
|
|
117
|
+
* This is the cleanup function for sessions created with `useRedisAuthStateWithHSet`.
|
|
118
|
+
*
|
|
119
|
+
* @param options - Configuration object
|
|
120
|
+
* @param options.redis - Active Redis client instance
|
|
121
|
+
* @param options.sessionId - The session identifier to delete (e.g., 'session', 'my-whatsapp-session')
|
|
122
|
+
* @param options.logger - Optional logging function for debugging
|
|
123
|
+
*
|
|
124
|
+
* @returns Promise that resolves when the deletion is complete
|
|
125
|
+
*
|
|
126
|
+
* @throws {Error} If Redis deletion operation fails
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const { redis } = await useRedisAuthStateWithHSet({ host: 'localhost' }, 'session-123');
|
|
131
|
+
*
|
|
132
|
+
* // Later, to logout and clean up:
|
|
133
|
+
* await deleteHSetKeys({
|
|
134
|
+
* redis,
|
|
135
|
+
* sessionId: 'session-123',
|
|
136
|
+
* logger: console.log
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* @see {@link useRedisAuthStateWithHSet} for the corresponding storage function
|
|
80
141
|
*/
|
|
81
|
-
const deleteHSetKeys = async ({ redis,
|
|
142
|
+
export const deleteHSetKeys = async ({ redis, sessionId, logger }) => {
|
|
82
143
|
try {
|
|
83
|
-
logger
|
|
84
|
-
await redis.del(createKey('auth',
|
|
144
|
+
logger?.('Removing auth state for session:', sessionId);
|
|
145
|
+
await redis.del(createKey('auth', sessionId));
|
|
85
146
|
}
|
|
86
147
|
catch (err) {
|
|
87
148
|
const error = err;
|
|
88
|
-
logger
|
|
149
|
+
logger?.('Error deleting session:', error.message);
|
|
89
150
|
throw error;
|
|
90
151
|
}
|
|
91
152
|
};
|
|
92
|
-
exports.deleteHSetKeys = deleteHSetKeys;
|
|
93
153
|
/**
|
|
94
154
|
* Redis-based authentication state storage using key-value pairs
|
|
95
|
-
*
|
|
96
|
-
*
|
|
155
|
+
*
|
|
156
|
+
* Stores each piece of authentication data as a separate Redis key with the pattern `${sessionId}:${key}`.
|
|
157
|
+
* This approach is less efficient than the Hash-based storage but offers more compatibility with
|
|
158
|
+
* existing systems and allows for more granular key management and expiration.
|
|
159
|
+
*
|
|
160
|
+
* @param redisOptions - Configuration options for the Redis client connection
|
|
161
|
+
* @param sessionId - Session identifier for Redis keys (default: 'session'). Each key will be `${sessionId}:${keyname}`
|
|
162
|
+
* @param logger - Optional logging function for debugging and monitoring Redis operations
|
|
163
|
+
*
|
|
164
|
+
* @returns Promise that resolves to an object containing:
|
|
165
|
+
* - `state`: The Baileys AuthenticationState object with creds and keys methods
|
|
166
|
+
* - `saveCreds`: Function to manually save credentials to Redis
|
|
167
|
+
* - `redis`: The Redis client instance for manual operations
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* const { state, saveCreds, redis } = await useRedisAuthState(
|
|
172
|
+
* { host: 'localhost', port: 6379 },
|
|
173
|
+
* 'my-whatsapp-session',
|
|
174
|
+
* console.log
|
|
175
|
+
* );
|
|
176
|
+
*
|
|
177
|
+
* const conn = makeWASocket({ auth: state });
|
|
178
|
+
* // Credentials are automatically saved on state changes
|
|
179
|
+
* ```
|
|
180
|
+
*
|
|
181
|
+
* @see {@link useRedisAuthStateWithHSet} for the recommended Hash-based storage alternative
|
|
97
182
|
*/
|
|
98
|
-
const useRedisAuthState = async (redisOptions,
|
|
99
|
-
|
|
100
|
-
const redis = new ioredis_1.default(redisOptions);
|
|
183
|
+
export const useRedisAuthState = async (redisOptions, sessionId = 'session', logger) => {
|
|
184
|
+
const redis = new Redis(redisOptions);
|
|
101
185
|
redis.on('connect', async () => {
|
|
102
|
-
const redisClientName = `baileys-auth-${
|
|
186
|
+
const redisClientName = `baileys-auth-${sessionId}`;
|
|
103
187
|
await redis.client('SETNAME', redisClientName);
|
|
104
|
-
logger
|
|
188
|
+
logger?.(`Redis client name set to ${redisClientName}`);
|
|
105
189
|
});
|
|
106
190
|
const writeData = async (key, data) => {
|
|
107
|
-
await redis.set(createKey(key,
|
|
191
|
+
await redis.set(createKey(key, sessionId), JSON.stringify(data, BufferJSON.replacer));
|
|
108
192
|
};
|
|
109
193
|
const readData = async (key) => {
|
|
110
|
-
const data = await redis.get(createKey(key,
|
|
111
|
-
return data ? JSON.parse(data,
|
|
194
|
+
const data = await redis.get(createKey(key, sessionId));
|
|
195
|
+
return data ? JSON.parse(data, BufferJSON.reviver) : null;
|
|
112
196
|
};
|
|
113
197
|
const removeData = async (key) => {
|
|
114
|
-
await redis.del(createKey(key,
|
|
198
|
+
await redis.del(createKey(key, sessionId));
|
|
115
199
|
};
|
|
116
|
-
const creds = (
|
|
200
|
+
const creds = (await readData('creds')) ?? initAuthCreds();
|
|
117
201
|
return {
|
|
118
202
|
state: {
|
|
119
203
|
creds,
|
|
@@ -124,7 +208,7 @@ const useRedisAuthState = async (redisOptions, prefix = 'session', logger) => {
|
|
|
124
208
|
const key = `${type}-${fixFileName(id)}`;
|
|
125
209
|
const value = await readData(key);
|
|
126
210
|
if (value) {
|
|
127
|
-
data[id] = (type === 'app-state-sync-key' ?
|
|
211
|
+
data[id] = (type === 'app-state-sync-key' ? proto.Message.AppStateSyncKeyData.fromObject(value) : value);
|
|
128
212
|
}
|
|
129
213
|
}));
|
|
130
214
|
return data;
|
|
@@ -153,28 +237,157 @@ const useRedisAuthState = async (redisOptions, prefix = 'session', logger) => {
|
|
|
153
237
|
redis,
|
|
154
238
|
};
|
|
155
239
|
};
|
|
156
|
-
exports.useRedisAuthState = useRedisAuthState;
|
|
157
240
|
/**
|
|
158
|
-
* Deletes all authentication keys
|
|
159
|
-
*
|
|
241
|
+
* Deletes all authentication keys for a specific session using key-value approach
|
|
242
|
+
*
|
|
243
|
+
* Uses Redis SCAN command to safely iterate through keys without blocking the Redis server.
|
|
244
|
+
* This is the cleanup function for sessions created with `useRedisAuthState`.
|
|
245
|
+
* The SCAN operation is cursor-based and processes keys in batches of 100.
|
|
246
|
+
*
|
|
247
|
+
* @param options - Configuration object
|
|
248
|
+
* @param options.redis - Active Redis client instance
|
|
249
|
+
* @param options.sessionId - The session identifier to delete (e.g., 'session', 'my-whatsapp-session')
|
|
250
|
+
* @param options.logger - Optional logging function for debugging and monitoring deletion progress
|
|
251
|
+
*
|
|
252
|
+
* @returns Promise that resolves when all matching keys have been deleted
|
|
253
|
+
*
|
|
254
|
+
* @throws {Error} If Redis SCAN or UNLINK operations fail
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```typescript
|
|
258
|
+
* const { redis } = await useRedisAuthState({ host: 'localhost' }, 'session-123');
|
|
259
|
+
*
|
|
260
|
+
* // Later, to logout and clean up all keys for this session:
|
|
261
|
+
* await deleteKeysWithPattern({
|
|
262
|
+
* redis,
|
|
263
|
+
* sessionId: 'session-123',
|
|
264
|
+
* logger: console.log
|
|
265
|
+
* });
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* @see {@link useRedisAuthState} for the corresponding storage function
|
|
269
|
+
* @see {@link deleteHSetKeys} for Hash-based storage cleanup
|
|
160
270
|
*/
|
|
161
|
-
const deleteKeysWithPattern = async ({ redis,
|
|
271
|
+
export const deleteKeysWithPattern = async ({ redis, sessionId, logger }) => {
|
|
162
272
|
try {
|
|
163
|
-
|
|
273
|
+
const pattern = `${sessionId}:*`;
|
|
274
|
+
logger?.('Removing auth state for session:', sessionId);
|
|
164
275
|
let cursor = 0;
|
|
165
276
|
do {
|
|
166
277
|
const [nextCursor, keys] = await redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
|
|
167
278
|
cursor = Number.parseInt(nextCursor, 10);
|
|
168
279
|
if (keys.length > 0) {
|
|
169
280
|
await redis.unlink(...keys);
|
|
170
|
-
logger
|
|
281
|
+
logger?.(`Deleted ${keys.length} keys for session: ${sessionId}`);
|
|
282
|
+
}
|
|
283
|
+
} while (cursor !== 0);
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
const error = err;
|
|
287
|
+
logger?.('Error deleting session:', error.message);
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Lists all session identifiers stored using Hash (HSET) approach
|
|
293
|
+
*
|
|
294
|
+
* Scans Redis for all hash keys with the pattern `*:auth` and extracts the session identifiers.
|
|
295
|
+
* This is useful for discovering all active sessions created with `useRedisAuthStateWithHSet`.
|
|
296
|
+
*
|
|
297
|
+
* @param options - Configuration object
|
|
298
|
+
* @param options.redis - Active Redis client instance
|
|
299
|
+
* @param options.logger - Optional logging function for debugging
|
|
300
|
+
*
|
|
301
|
+
* @returns Promise that resolves to an array of session identifiers
|
|
302
|
+
*
|
|
303
|
+
* @throws {Error} If Redis SCAN operation fails
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const redis = new Redis({ host: 'localhost' });
|
|
308
|
+
*
|
|
309
|
+
* const sessions = await listHSetSessions({ redis, logger: console.log });
|
|
310
|
+
* console.log('Active sessions:', sessions);
|
|
311
|
+
* // Output: ['session-123', 'user-456', 'bot-789']
|
|
312
|
+
* ```
|
|
313
|
+
*
|
|
314
|
+
* @see {@link useRedisAuthStateWithHSet} for the corresponding storage function
|
|
315
|
+
* @see {@link listSessions} for key-value based session listing
|
|
316
|
+
*/
|
|
317
|
+
export const listHSetSessions = async ({ redis, logger }) => {
|
|
318
|
+
try {
|
|
319
|
+
const sessions = [];
|
|
320
|
+
let cursor = 0;
|
|
321
|
+
logger?.('Scanning for Hash-based sessions...');
|
|
322
|
+
do {
|
|
323
|
+
const [nextCursor, keys] = await redis.scan(cursor, 'MATCH', '*:auth', 'COUNT', 100);
|
|
324
|
+
cursor = Number.parseInt(nextCursor, 10);
|
|
325
|
+
for (const key of keys) {
|
|
326
|
+
// Extract sessionId from "sessionId:auth" pattern
|
|
327
|
+
const sessionId = key.replace(':auth', '');
|
|
328
|
+
if (sessionId) {
|
|
329
|
+
sessions.push(sessionId);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
} while (cursor !== 0);
|
|
333
|
+
logger?.(`Found ${sessions.length} Hash-based sessions`);
|
|
334
|
+
return sessions;
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
const error = err;
|
|
338
|
+
logger?.('Error listing sessions:', error.message);
|
|
339
|
+
throw error;
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* Lists all session identifiers stored using key-value approach
|
|
344
|
+
*
|
|
345
|
+
* Scans Redis for all keys with the pattern `*:creds` and extracts unique session identifiers.
|
|
346
|
+
* This is useful for discovering all active sessions created with `useRedisAuthState`.
|
|
347
|
+
*
|
|
348
|
+
* @param options - Configuration object
|
|
349
|
+
* @param options.redis - Active Redis client instance
|
|
350
|
+
* @param options.logger - Optional logging function for debugging
|
|
351
|
+
*
|
|
352
|
+
* @returns Promise that resolves to an array of unique session identifiers
|
|
353
|
+
*
|
|
354
|
+
* @throws {Error} If Redis SCAN operation fails
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```typescript
|
|
358
|
+
* const redis = new Redis({ host: 'localhost' });
|
|
359
|
+
*
|
|
360
|
+
* const sessions = await listSessions({ redis, logger: console.log });
|
|
361
|
+
* console.log('Active sessions:', sessions);
|
|
362
|
+
* // Output: ['session-123', 'user-456', 'bot-789']
|
|
363
|
+
* ```
|
|
364
|
+
*
|
|
365
|
+
* @see {@link useRedisAuthState} for the corresponding storage function
|
|
366
|
+
* @see {@link listHSetSessions} for Hash-based session listing
|
|
367
|
+
*/
|
|
368
|
+
export const listSessions = async ({ redis, logger }) => {
|
|
369
|
+
try {
|
|
370
|
+
const sessionsSet = new Set();
|
|
371
|
+
let cursor = 0;
|
|
372
|
+
logger?.('Scanning for key-value based sessions...');
|
|
373
|
+
do {
|
|
374
|
+
const [nextCursor, keys] = await redis.scan(cursor, 'MATCH', '*:creds', 'COUNT', 100);
|
|
375
|
+
cursor = Number.parseInt(nextCursor, 10);
|
|
376
|
+
for (const key of keys) {
|
|
377
|
+
// Extract sessionId from "sessionId:creds" pattern
|
|
378
|
+
const sessionId = key.replace(':creds', '');
|
|
379
|
+
if (sessionId) {
|
|
380
|
+
sessionsSet.add(sessionId);
|
|
381
|
+
}
|
|
171
382
|
}
|
|
172
383
|
} while (cursor !== 0);
|
|
384
|
+
const sessions = Array.from(sessionsSet);
|
|
385
|
+
logger?.(`Found ${sessions.length} key-value based sessions`);
|
|
386
|
+
return sessions;
|
|
173
387
|
}
|
|
174
388
|
catch (err) {
|
|
175
389
|
const error = err;
|
|
176
|
-
logger
|
|
390
|
+
logger?.('Error listing sessions:', error.message);
|
|
177
391
|
throw error;
|
|
178
392
|
}
|
|
179
393
|
};
|
|
180
|
-
exports.deleteKeysWithPattern = deleteKeysWithPattern;
|
package/package.json
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "baileys-redis-auth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Redis Auth for Baileys",
|
|
5
5
|
"author": "heriyanto binduni <hbinduni@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
7
8
|
"main": "lib/index.js",
|
|
9
|
+
"module": "lib/index.js",
|
|
8
10
|
"types": "lib/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./lib/index.js",
|
|
14
|
+
"types": "./lib/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
9
17
|
"homepage": "https://github.com/hbinduni/baileys-redis-auth",
|
|
10
18
|
"repository": {
|
|
11
|
-
"url": "https://github.com/hbinduni/baileys-redis-auth.git"
|
|
19
|
+
"url": "git+https://github.com/hbinduni/baileys-redis-auth.git"
|
|
12
20
|
},
|
|
13
21
|
"scripts": {
|
|
14
22
|
"clean": "rm -rf lib",
|
|
15
23
|
"build": "bun run clean && tsc -p tsconfig.json",
|
|
16
24
|
"prebuild": "bun run check:all",
|
|
17
|
-
"example": "
|
|
25
|
+
"example": "tsx example/example.ts",
|
|
18
26
|
"example:no-all": "bun run example -- --no-store --no-reply",
|
|
19
27
|
"typecheck": "bun x tsc --noEmit -p tsconfig.json",
|
|
20
28
|
"format": "biome format --write .",
|
|
@@ -36,21 +44,27 @@
|
|
|
36
44
|
"auth"
|
|
37
45
|
],
|
|
38
46
|
"devDependencies": {
|
|
39
|
-
"@adiwajshing/keyed-db": "^0.2.4",
|
|
40
47
|
"@biomejs/biome": "^1.9.4",
|
|
41
48
|
"@hapi/boom": "^10.0.1",
|
|
42
|
-
"@types/node": "^24.
|
|
49
|
+
"@types/node": "^24.10.4",
|
|
50
|
+
"baileys": "^7.0.0-rc.9",
|
|
43
51
|
"dotenv": "^17.2.3",
|
|
44
52
|
"node-cache": "^5.1.2",
|
|
45
|
-
"pino": "^9.
|
|
46
|
-
"pino-pretty": "^13.1.
|
|
53
|
+
"pino": "^9.14.0",
|
|
54
|
+
"pino-pretty": "^13.1.3",
|
|
47
55
|
"qrcode-terminal": "^0.12.0",
|
|
48
|
-
"
|
|
49
|
-
"tsconfig-paths": "^4.2.0",
|
|
56
|
+
"tsx": "^4.19.0",
|
|
50
57
|
"typescript": "^5.9.3"
|
|
51
58
|
},
|
|
52
59
|
"dependencies": {
|
|
53
|
-
"
|
|
54
|
-
|
|
60
|
+
"ioredis": "^5.8.2"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"baileys": ">=7.0.0-rc.9"
|
|
64
|
+
},
|
|
65
|
+
"peerDependenciesMeta": {
|
|
66
|
+
"baileys": {
|
|
67
|
+
"optional": false
|
|
68
|
+
}
|
|
55
69
|
}
|
|
56
70
|
}
|