@zervonex/baileys 3.0.2 → 3.0.4
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/README.md +38 -8
- package/WAProto/WAProtoCompile.js +1 -0
- package/WAProto/fetcher.js +17 -33
- package/WAProto/index.js +34 -26
- package/WAProto/parser.js +333 -312
- package/lib/Builders/AIRich.js +14 -14
- package/lib/Builders/base.js +3 -3
- package/lib/Builders/builders.js +460 -448
- package/lib/Defaults/index.js +1 -0
- package/lib/Socket/messages-recv.js +1 -1
- package/lib/Socket/messages-send.js +1 -1
- package/lib/Socket/newsletter.js +1 -0
- package/lib/Socket/socket.js +4 -3
- package/lib/Socket/zervonex-handler.js +1 -1
- package/lib/Utils/browser-utils.js +8 -4
- package/lib/Utils/chat-utils.js +1 -1
- package/lib/Utils/messages.js +91 -40
- package/lib/Utils/use-multi-file-auth-state.js +50 -157
- package/lib/Utils/validate-connection.js +19 -28
- package/lib/WABinary/generic-utils.js +43 -19
- package/lib/index.js +1 -1
- package/package.json +56 -91
package/README.md
CHANGED
|
@@ -42,11 +42,13 @@
|
|
|
42
42
|
<img src="https://img.shields.io/badge/Join-WhatsApp%20Channel-25D366?logo=whatsapp&logoColor=white" alt="WhatsApp Channel" />
|
|
43
43
|
</a>
|
|
44
44
|
</p>
|
|
45
|
-
|
|
46
45
|
*Modern, feature-rich, and developer-friendly WhatsApp automation library*
|
|
47
46
|
|
|
48
47
|
*Formerly known as @nexustechpro/baileys*
|
|
49
48
|
|
|
49
|
+
> ⚠️ This is an independent fork of [@whiskeysockets/baileys](https://github.com/WhiskeySockets/Baileys).
|
|
50
|
+
> It is not affiliated with WhatsApp, Meta, or the original Baileys maintainers.
|
|
51
|
+
|
|
50
52
|
</div>
|
|
51
53
|
|
|
52
54
|
---
|
|
@@ -71,6 +73,7 @@
|
|
|
71
73
|
- [AI Rich Messages](#ai-rich-messages)
|
|
72
74
|
- [Status & Stories](#personal-status--story-statusbroadcast)
|
|
73
75
|
- [Sticker Pack](#sticker-pack)
|
|
76
|
+
- [Premium Stickers](#premium-stickers)
|
|
74
77
|
- [Shorthand Wrappers](#shorthand-wrappers)
|
|
75
78
|
- [Message Modifications](#️-message-modifications)
|
|
76
79
|
- [Media Download](#-media-download)
|
|
@@ -117,19 +120,13 @@ yarn add @zervonex/baileys
|
|
|
117
120
|
|
|
118
121
|
**Drop-in replacement for `@whiskeysockets/baileys`** — add this to `package.json`:
|
|
119
122
|
```json
|
|
120
|
-
{
|
|
121
|
-
"dependencies": {
|
|
122
|
-
"@whiskeysockets/baileys": "npm:@zervonex/baileys"
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// OR
|
|
127
123
|
|
|
128
124
|
{
|
|
129
125
|
"dependencies": {
|
|
130
126
|
"@zervonex/baileys": "latest"
|
|
131
127
|
}
|
|
132
128
|
}
|
|
129
|
+
|
|
133
130
|
```
|
|
134
131
|
|
|
135
132
|
**Import:**
|
|
@@ -341,6 +338,9 @@ const sock = makeWASocket({
|
|
|
341
338
|
|
|
342
339
|
// Custom message retrieval for retry/poll decryption
|
|
343
340
|
getMessage: async (key) => store.loadMessage(key.remoteJid, key.id),
|
|
341
|
+
|
|
342
|
+
// Opt out of auto-following the official zervonex newsletter on connect
|
|
343
|
+
autoFollowNewsletter: false, // default: true
|
|
344
344
|
})
|
|
345
345
|
```
|
|
346
346
|
---
|
|
@@ -443,6 +443,18 @@ await clearSession()
|
|
|
443
443
|
|
|
444
444
|
`clearSession()` wipes every key belonging to that `sessionId` — creds, prekeys, sessions, sender keys, everything — using each backend's native namespace-scoped bulk delete (a real `deleteMany`/`DELETE WHERE`/`SCAN`+delete under the hood, not a per-key loop). It only affects this session; other sessions sharing the same backend are untouched. There's no equivalent method on `useMultiFileAuthState` — delete the session folder instead.
|
|
445
445
|
|
|
446
|
+
#### Checking auth without loading full state
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
import { hasKeyvAuth } from '@zervonex/baileys'
|
|
450
|
+
|
|
451
|
+
// Check if a session has valid auth (lightweight — no full state load)
|
|
452
|
+
const valid = await hasKeyvAuth('bot1', backend)
|
|
453
|
+
// true if creds exist and contain noiseKey + signedIdentityKey
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
`hasKeyvAuth()` queries the backend using the correct Keyv namespace — the same way `useKeyvAuthState` does internally — so it always returns the right answer regardless of your backend. Useful for checking session ownership before deciding whether to restore a connection, without the overhead of initializing a full auth state.
|
|
457
|
+
|
|
446
458
|
#### Options
|
|
447
459
|
|
|
448
460
|
| Option | Type | Default | Description |
|
|
@@ -1364,6 +1376,23 @@ await sock.stickerPackMessage(jid, {
|
|
|
1364
1376
|
}, { quoted: message })
|
|
1365
1377
|
```
|
|
1366
1378
|
|
|
1379
|
+
### Premium Stickers
|
|
1380
|
+
|
|
1381
|
+
Pass `premium` on a single sticker:
|
|
1382
|
+
```js
|
|
1383
|
+
await sock.sendMessage(jid, { sticker: buffer, premium: 1 })
|
|
1384
|
+
```
|
|
1385
|
+
|
|
1386
|
+
Per-sticker in a pack:
|
|
1387
|
+
```js
|
|
1388
|
+
await sock.sendMessage(jid, { stickerPack: { stickers: [{ data: buffer, emojis: ['🔥'], premium: 1 }] } })
|
|
1389
|
+
```
|
|
1390
|
+
|
|
1391
|
+
Whole pack as premium:
|
|
1392
|
+
```js
|
|
1393
|
+
await sock.sendMessage(jid, { stickerPack: { premium: 1, stickers: [...] } })
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1367
1396
|
**Per-sticker options:**
|
|
1368
1397
|
|
|
1369
1398
|
| Field | Type | Default | Description |
|
|
@@ -2962,6 +2991,7 @@ import {
|
|
|
2962
2991
|
makeWASocket,
|
|
2963
2992
|
useMultiFileAuthState,
|
|
2964
2993
|
useKeyvAuthState,
|
|
2994
|
+
hasKeyvAuth,
|
|
2965
2995
|
makeCacheableSignalKeyStore,
|
|
2966
2996
|
Browsers,
|
|
2967
2997
|
DisconnectReason,
|
|
@@ -255,6 +255,7 @@ function makeProto(tablePath) {
|
|
|
255
255
|
node.toObject = o => o ?? {}
|
|
256
256
|
node.verify = () => null
|
|
257
257
|
node.name = full.split('.').pop()
|
|
258
|
+
node.fields = Object.fromEntries(TABLE[full].order.map(f => [f.name, { type: f.s ?? f.k, id: f.id, repeated: f.rep ?? false }]))
|
|
258
259
|
}
|
|
259
260
|
for (const [full, values] of Object.entries(e)) {
|
|
260
261
|
const node = nodeFor(full.replace(/^proto\./, '').split('.'))
|
package/WAProto/fetcher.js
CHANGED
|
@@ -1,69 +1,53 @@
|
|
|
1
1
|
import { fetch, Agent } from 'undici'
|
|
2
2
|
import { createHash } from 'crypto'
|
|
3
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs'
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync, createWriteStream, unlinkSync } from 'fs'
|
|
4
|
+
import { pipeline } from 'stream/promises'
|
|
4
5
|
import { join, dirname } from 'path'
|
|
5
6
|
import { fileURLToPath } from 'url'
|
|
6
7
|
|
|
7
8
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
8
9
|
const CACHE_FILE = join(__dirname, '.cache.json')
|
|
9
10
|
const PROTO_FILE = join(__dirname, 'WAProto.proto')
|
|
10
|
-
|
|
11
|
+
const BUNDLE_TMP = join(__dirname, 'WAProto.bundle.tmp')
|
|
11
12
|
const GITHUB_RAW = 'https://raw.githubusercontent.com/nexustechpro2/baileys/wa-cache'
|
|
12
13
|
const CACHE_TTL = 24 * 60 * 60 * 1000
|
|
13
|
-
|
|
14
|
-
const agent = new Agent({ connect: { family: 4 } })
|
|
14
|
+
const agent = new Agent({ connect: { family: 4, timeout: 60000 } })
|
|
15
15
|
|
|
16
16
|
const isCacheValid = (cache) => cache.version && cache.timestamp && (Date.now() - cache.timestamp) < CACHE_TTL
|
|
17
17
|
const readCache = () => { try { return existsSync(CACHE_FILE) ? JSON.parse(readFileSync(CACHE_FILE, 'utf8')) : {} } catch { return {} } }
|
|
18
18
|
const writeCache = (data) => writeFileSync(CACHE_FILE, JSON.stringify({ ...data, timestamp: Date.now() }, null, 2), 'utf8')
|
|
19
|
+
const removeTmp = () => { try { if (existsSync(BUNDLE_TMP)) unlinkSync(BUNDLE_TMP) } catch { } }
|
|
19
20
|
|
|
20
21
|
async function fetchFromGitHub(file) {
|
|
21
22
|
const res = await fetch(`${GITHUB_RAW}/${file}`, { method: 'GET', dispatcher: agent })
|
|
22
23
|
if (!res.ok) throw new Error(`[WAProto] GitHub fetch failed: ${res.status} for ${file}`)
|
|
23
|
-
|
|
24
|
+
if (file.endsWith('.json')) return res.json()
|
|
25
|
+
const hash = createHash('sha256')
|
|
26
|
+
const writer = createWriteStream(BUNDLE_TMP)
|
|
27
|
+
await pipeline(res.body, async function* (source) { for await (const chunk of source) { hash.update(chunk); yield chunk } }, writer)
|
|
28
|
+
return hash.digest('hex')
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
async function fetchClientRevision() {
|
|
27
32
|
const data = await fetchFromGitHub('wa-version.json')
|
|
28
|
-
if (!data?.version) throw new Error('[WAProto]
|
|
33
|
+
if (!data?.version) throw new Error('[WAProto] wa-version.json missing version field')
|
|
29
34
|
return String(data.version)
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
async function fetchCombinedBundle() {
|
|
33
|
-
return fetchFromGitHub('WAProto.bundle.js')
|
|
34
|
-
}
|
|
35
|
-
|
|
36
37
|
export async function fetchProtoBundle() {
|
|
37
38
|
const cache = readCache()
|
|
38
39
|
if (isCacheValid(cache) && existsSync(PROTO_FILE)) return { changed: false, bundle: null, version: cache.version }
|
|
39
|
-
|
|
40
40
|
const version = await fetchClientRevision()
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return { changed: false, bundle: null, version }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let bundle = await fetchCombinedBundle()
|
|
48
|
-
const hash = createHash('sha256').update(bundle).digest('hex')
|
|
49
|
-
|
|
50
|
-
if (cache.hash === hash) {
|
|
51
|
-
writeCache({ version, hash })
|
|
52
|
-
return { changed: false, bundle: null, version }
|
|
53
|
-
}
|
|
54
|
-
|
|
41
|
+
if (cache.version === version && existsSync(PROTO_FILE)) { writeCache({ ...cache, version }); return { changed: false, bundle: null, version } }
|
|
42
|
+
const hash = await fetchFromGitHub('WAProto.bundle.js')
|
|
43
|
+
if (cache.hash === hash) { writeCache({ version, hash }); removeTmp(); return { changed: false, bundle: null, version } }
|
|
55
44
|
writeCache({ version, hash })
|
|
56
|
-
|
|
57
|
-
bundle = null
|
|
58
|
-
return result
|
|
45
|
+
return { changed: true, bundlePath: BUNDLE_TMP, version }
|
|
59
46
|
}
|
|
60
47
|
|
|
61
48
|
export async function getWAVersion() {
|
|
62
49
|
const cache = readCache()
|
|
63
50
|
if (isCacheValid(cache) && cache.version) return [2, 3000, parseInt(cache.version)]
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (!data?.version) throw new Error('[WAProto] GitHub wa-version.json missing version field')
|
|
67
|
-
|
|
68
|
-
return [2, 3000, parseInt(data.version)]
|
|
51
|
+
const version = await fetchClientRevision()
|
|
52
|
+
return [2, 3000, parseInt(version)]
|
|
69
53
|
}
|
package/WAProto/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, unlinkSync, readFileSync } from 'fs'
|
|
2
2
|
import { join, dirname } from 'path'
|
|
3
3
|
import { fileURLToPath } from 'url'
|
|
4
|
+
import { Worker, isMainThread, workerData, parentPort } from 'worker_threads'
|
|
4
5
|
import logger from '../lib/Utils/logger.js'
|
|
5
6
|
import { fetchProtoBundle } from './fetcher.js'
|
|
6
7
|
import { generateTable, _reloadProto } from './WAProtoCompile.js'
|
|
@@ -9,37 +10,33 @@ import { parseBundle } from './parser.js'
|
|
|
9
10
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
10
11
|
const PROTO_FILE = join(__dirname, 'WAProto.proto')
|
|
11
12
|
const TABLE_FILE = join(__dirname, 'WAProto.json')
|
|
13
|
+
const SELF = new URL(import.meta.url)
|
|
12
14
|
|
|
13
15
|
const log = msg => logger.info(msg)
|
|
14
16
|
const err = msg => logger.error(msg)
|
|
17
|
+
const del = (...files) => { for (const f of files) { try { if (existsSync(f)) unlinkSync(f) } catch { } } }
|
|
18
|
+
const isJsonValid = () => { try { const { m, t } = JSON.parse(readFileSync(TABLE_FILE, 'utf8')); return Array.isArray(m) && m.length > 0 && typeof t === 'object' && Object.keys(t).length > 0 } catch { return false } }
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
function runInWorker(data) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const w = new Worker(SELF, { workerData: data })
|
|
23
|
+
w.once('message', msg => { w.terminate(); msg.ok ? resolve() : reject(new Error(msg.error)) })
|
|
24
|
+
w.once('error', reject)
|
|
25
|
+
})
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
const del = (...files) => { for (const f of files) { try { if (existsSync(f)) unlinkSync(f) } catch { } } }
|
|
24
|
-
|
|
25
28
|
async function regenerateFromProto() {
|
|
26
29
|
log('Regenerating WAProto.json from existing WAProto.proto...')
|
|
27
|
-
await
|
|
30
|
+
await runInWorker({ bundlePath: null, version: null, protoPath: PROTO_FILE, tablePath: TABLE_FILE })
|
|
28
31
|
_reloadProto()
|
|
29
32
|
log('Regenerated successfully')
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
async function refetch() {
|
|
33
36
|
log('Fetching proto bundle from GitHub...')
|
|
34
|
-
const { bundle, version } = await fetchProtoBundle()
|
|
35
|
-
if (!bundle) throw new Error('fetchProtoBundle returned no bundle')
|
|
36
|
-
|
|
37
|
-
const { writeFileSync } = await import('fs')
|
|
38
|
-
const tmp = PROTO_FILE + '.tmp'
|
|
39
|
-
writeFileSync(tmp, protoText, 'utf8')
|
|
40
|
-
const { renameSync } = await import('fs')
|
|
41
|
-
renameSync(tmp, PROTO_FILE)
|
|
42
|
-
await generateTable(PROTO_FILE, TABLE_FILE)
|
|
37
|
+
const { bundle, bundlePath, version } = await fetchProtoBundle()
|
|
38
|
+
if (!bundle && !bundlePath) throw new Error('fetchProtoBundle returned no bundle')
|
|
39
|
+
await runInWorker({ bundlePath: bundlePath ?? null, bundle: bundle ?? null, version, protoPath: PROTO_FILE, tablePath: TABLE_FILE })
|
|
43
40
|
_reloadProto()
|
|
44
41
|
log(`Fetched and compiled — WA version ${version}`)
|
|
45
42
|
}
|
|
@@ -59,7 +56,6 @@ async function boot() {
|
|
|
59
56
|
}
|
|
60
57
|
return
|
|
61
58
|
}
|
|
62
|
-
|
|
63
59
|
if (hasProto && !hasJson) {
|
|
64
60
|
log('WAProto.json missing — generating from existing proto...')
|
|
65
61
|
try { await regenerateFromProto(); return } catch (e) {
|
|
@@ -69,19 +65,31 @@ async function boot() {
|
|
|
69
65
|
}
|
|
70
66
|
return
|
|
71
67
|
}
|
|
72
|
-
|
|
73
|
-
if (hasJson && !hasProto) {
|
|
74
|
-
err('WAProto.proto missing but WAProto.json exists — cannot trust JSON, refetching...')
|
|
75
|
-
del(TABLE_FILE)
|
|
76
|
-
await refetch()
|
|
77
|
-
return
|
|
78
|
-
}
|
|
68
|
+
if (hasJson && !hasProto) { err('WAProto.proto missing but WAProto.json exists — cannot trust JSON, refetching...'); del(TABLE_FILE); await refetch(); return }
|
|
79
69
|
|
|
80
70
|
log('No proto files found — fetching from GitHub...')
|
|
81
71
|
await refetch()
|
|
82
72
|
}
|
|
83
73
|
|
|
84
|
-
|
|
74
|
+
if (!isMainThread) {
|
|
75
|
+
const { bundlePath, bundle, version, protoPath, tablePath } = workerData
|
|
76
|
+
try {
|
|
77
|
+
if (bundlePath || bundle) {
|
|
78
|
+
const src = bundlePath ? readFileSync(bundlePath, 'utf8') : bundle
|
|
79
|
+
if (bundlePath) unlinkSync(bundlePath)
|
|
80
|
+
const { writeFileSync, renameSync } = await import('fs')
|
|
81
|
+
const tmp = protoPath + '.tmp'
|
|
82
|
+
writeFileSync(tmp, parseBundle(src, version), 'utf8')
|
|
83
|
+
renameSync(tmp, protoPath)
|
|
84
|
+
}
|
|
85
|
+
await generateTable(protoPath, tablePath)
|
|
86
|
+
parentPort.postMessage({ ok: true })
|
|
87
|
+
} catch (e) {
|
|
88
|
+
parentPort.postMessage({ ok: false, error: e.message })
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
await boot()
|
|
92
|
+
}
|
|
85
93
|
|
|
86
94
|
export { proto, codec, generateTable, _reloadProto } from './WAProtoCompile.js'
|
|
87
95
|
export { getWAVersion, fetchProtoBundle } from './fetcher.js'
|