@zervonex/baileys 3.0.3 → 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 CHANGED
@@ -73,6 +73,7 @@
73
73
  - [AI Rich Messages](#ai-rich-messages)
74
74
  - [Status & Stories](#personal-status--story-statusbroadcast)
75
75
  - [Sticker Pack](#sticker-pack)
76
+ - [Premium Stickers](#premium-stickers)
76
77
  - [Shorthand Wrappers](#shorthand-wrappers)
77
78
  - [Message Modifications](#️-message-modifications)
78
79
  - [Media Download](#-media-download)
@@ -442,6 +443,18 @@ await clearSession()
442
443
 
443
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.
444
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
+
445
458
  #### Options
446
459
 
447
460
  | Option | Type | Default | Description |
@@ -1363,6 +1376,23 @@ await sock.stickerPackMessage(jid, {
1363
1376
  }, { quoted: message })
1364
1377
  ```
1365
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
+
1366
1396
  **Per-sticker options:**
1367
1397
 
1368
1398
  | Field | Type | Default | Description |
@@ -2961,6 +2991,7 @@ import {
2961
2991
  makeWASocket,
2962
2992
  useMultiFileAuthState,
2963
2993
  useKeyvAuthState,
2994
+ hasKeyvAuth,
2964
2995
  makeCacheableSignalKeyStore,
2965
2996
  Browsers,
2966
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('.'))
@@ -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
- return file.endsWith('.json') ? res.json() : res.text()
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] GitHub wa-version.json missing version field')
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
- if (cache.version === version && existsSync(PROTO_FILE)) {
43
- writeCache({ ...cache, version })
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
- const result = { changed: true, bundle, version }
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
- const data = await fetchFromGitHub('wa-version.json')
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
- const isJsonValid = () => {
17
- try {
18
- const { m, t } = JSON.parse(readFileSync(TABLE_FILE, 'utf8'))
19
- return Array.isArray(m) && m.length > 0 && typeof t === 'object' && Object.keys(t).length > 0
20
- } catch { return false }
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 generateTable(PROTO_FILE, TABLE_FILE)
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
- const protoText = parseBundle(bundle, version)
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
- await boot()
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'