lyxe-baileys 1.0.2 → 1.1.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- <img src="https://raw.githubusercontent.com/noxXza/data/refs/heads/main/lyxe-baileys.png" width="400" alt="Lyxe Baileys Banner" />
3
+ <img src="https://i.ibb.co.com/fz44Z9Nz/images.jpg" width="400" alt="Lyxe Baileys Banner" />
4
4
  <br><br>
5
5
 
6
6
  <h1>lyxe-baileys</h1>
@@ -113,6 +113,98 @@ Baru di sini? Ini seluruh library dalam satu pandangan. Tiap baris menaut ke bag
113
113
 
114
114
  ---
115
115
 
116
+ ## 🚀 Fitur Eksklusif Lyxe Baileys
117
+
118
+ ### 1. 🛡️ Smart Anti-Ban & Humanizer
119
+ Hindari pemblokiran akun dengan jeda acak manusiawi dan simulasi presence:
120
+ ```javascript
121
+ import { smartDelay } from 'lyxe-baileys'
122
+
123
+ // Jeda acak (misal 1000 - 2500ms)
124
+ await sock.smartDelay(1000, 2500)
125
+
126
+ // Simulasi mengetik otomatis sebelum pesan terkirim
127
+ await sock.simulateTyping(jid, 2000)
128
+
129
+ // Atau langsung kirim dengan opsi simulateTyping
130
+ await sock.sendMessage(jid, { text: 'Halo! Ada yang bisa dibantu?' }, { simulateTyping: true })
131
+ ```
132
+
133
+ ### 2. 👁️ View-Once & Anti-Delete Retriever
134
+ Bongkar media pesan 1x lihat (foto/video/audio) atau pulihkan pesan yang ditarik:
135
+ ```javascript
136
+ // Download pesan View Once secara instan
137
+ const { buffer, mediaType, caption } = await sock.downloadViewOnce(m)
138
+ console.log(`Media ${mediaType} berhasil diunduh! Ukuran: ${buffer.length} bytes`)
139
+
140
+ // Tangkap pesan yang dihapus pengirim dari store
141
+ const original = sock.extractRevokedMessage(store, revocationMsg)
142
+ if (original) {
143
+ console.log('Pesan yang ditarik:', original.message)
144
+ }
145
+ ```
146
+
147
+ ### 3. 📢 WhatsApp Status / Story Supercharger
148
+ Otomatis baca story, beri reaksi emoji, buat status mention, atau unggah voice note ke story:
149
+ ```javascript
150
+ // Otomatis tandai status sudah dibaca dengan jeda alami
151
+ await sock.readStatus(statusMessage, 1500)
152
+
153
+ // Beri reaksi emoji ke story kontak
154
+ await sock.reactStatus(statusMessage, '❤️')
155
+
156
+ // Buat status teks/media dengan mention kontak tertentu
157
+ await sock.sendStatusMention('Halo semua!', ['628123456789@s.whatsapp.net'])
158
+
159
+ // Unggah Voice Note (VN) ke Status WhatsApp
160
+ await sock.sendVoiceStatus(audioBuffer, { backgroundColor: '#7F5AF0' })
161
+ ```
162
+
163
+ ### 4. 🎙️ Media & Audio Helpers
164
+ Kirim Voice Note (PTT) asli dengan animasi waveform, stiker, dan media HD:
165
+ ```javascript
166
+ // Kirim rekaman suara (Voice Note PTT) lengkap dengan waveform
167
+ await sock.sendVoiceNote(jid, './suara.mp3', quoted)
168
+
169
+ // Kirim stiker instan
170
+ await sock.sendImageAsSticker(jid, stickerBuffer, quoted)
171
+
172
+ // Kirim foto/video kualitas HD resmi
173
+ await sock.sendHDMedia(jid, { image: { url: './foto.jpg' }, caption: 'Kualitas HD' })
174
+ ```
175
+
176
+ ### 5. 🤖 AI Streaming Message
177
+ Tampilkan pesan bertahap dengan animasi ketik langsung seperti ChatGPT/Gemini di WhatsApp:
178
+ ```javascript
179
+ // Mengalirkan teks bertahap (AsyncIterable, generator, array, atau string)
180
+ await sock.streamMessage(jid, aiTextStream, {
181
+ throttleMs: 350,
182
+ initialPlaceholder: '⏳ Sedang merangkai jawaban...',
183
+ quoted: m
184
+ })
185
+ ```
186
+
187
+ ### 6. 📱 Multi-Session Manager
188
+ Kelola banyak nomor bot WhatsApp sekaligus dalam satu script:
189
+ ```javascript
190
+ import makeWASocket, { LyxeSessionManager, useMultiFileAuthState } from 'lyxe-baileys'
191
+
192
+ const manager = new LyxeSessionManager({
193
+ createSocketFn: makeWASocket
194
+ })
195
+
196
+ // Buat dan jalankan sesi bot 1
197
+ const { state, saveCreds } = await useMultiFileAuthState('./session-bot1')
198
+ const sock1 = await manager.createSession('bot-1', { auth: state })
199
+
200
+ // Tangkap pesan dari semua sesi sekaligus
201
+ manager.on('messages.upsert', ({ sessionId, upsert, sock }) => {
202
+ console.log(`Pesan masuk di ${sessionId}`)
203
+ })
204
+ ```
205
+
206
+ ---
207
+
116
208
  ## 📚 Daftar Isi
117
209
 
118
210
  - [Ringkasan](#-ringkasan)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lyxe-baileys",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Custom WhatsApp Multi-Device library by lyxe (forked from luna-baileys by noxXza)",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -0,0 +1,72 @@
1
+ import { delay } from '../Utils/generics.js';
2
+
3
+ /**
4
+ * Mengirim pesan dengan efek streaming (seperti animasi mengetik AI ChatGPT/Gemini).
5
+ * Pesan dikirim sekali lalu di-edit bertahap seiring potongan teks baru tiba.
6
+ *
7
+ * @param {any} sock Socket Baileys
8
+ * @param {string} jid Target chat
9
+ * @param {AsyncIterable<string>|string[]|Iterable<string>} stream Iterable teks/chunk
10
+ * @param {object} [options={}] Opsi
11
+ * @param {number} [options.throttleMs=350] Interval minimum antar edit agar tidak terkena rate-limit WA
12
+ * @param {string} [options.initialPlaceholder='⏳ Sedang berpikir...'] Teks awal saat proses mulai
13
+ * @param {any} [options.quoted] Pesan rujukan (quoted message)
14
+ * @returns {Promise<any>} Objek pesan terakhir yang dikirim
15
+ */
16
+ export const streamMessage = async (sock, jid, stream, options = {}) => {
17
+ const throttleMs = options.throttleMs || 350;
18
+ const placeholder = options.initialPlaceholder || '⏳ Sedang berpikir...';
19
+
20
+ // Kirim pesan pertama
21
+ const sent = await sock.sendMessage(jid, { text: placeholder }, { quoted: options.quoted });
22
+ if (!sent?.key) return sent;
23
+
24
+ let accumulatedText = '';
25
+ let lastEditTime = Date.now();
26
+
27
+ const doEdit = async (text) => {
28
+ try {
29
+ await sock.sendMessage(jid, {
30
+ text: text,
31
+ edit: sent.key
32
+ });
33
+ lastEditTime = Date.now();
34
+ } catch {
35
+ // Abaikan error transien saat streaming edit
36
+ }
37
+ };
38
+
39
+ if (stream && typeof stream[Symbol.asyncIterator] === 'function') {
40
+ for await (const chunk of stream) {
41
+ accumulatedText += chunk;
42
+ const now = Date.now();
43
+ if (now - lastEditTime >= throttleMs) {
44
+ await doEdit(accumulatedText);
45
+ }
46
+ }
47
+ } else if (stream && typeof stream[Symbol.iterator] === 'function') {
48
+ for (const chunk of stream) {
49
+ accumulatedText += chunk;
50
+ const now = Date.now();
51
+ if (now - lastEditTime >= throttleMs) {
52
+ await doEdit(accumulatedText);
53
+ await delay(throttleMs);
54
+ }
55
+ }
56
+ } else if (typeof stream === 'string') {
57
+ // Jika diberikan full string, simulasikan streaming dengan memecah per kata
58
+ const words = stream.split(' ');
59
+ for (let i = 0; i < words.length; i += 3) {
60
+ accumulatedText = words.slice(0, i + 3).join(' ');
61
+ await doEdit(accumulatedText);
62
+ await delay(throttleMs);
63
+ }
64
+ }
65
+
66
+ // Pastikan teks akhir terkirim utuh
67
+ if (accumulatedText && accumulatedText !== placeholder) {
68
+ await doEdit(accumulatedText);
69
+ }
70
+
71
+ return sent;
72
+ };
@@ -0,0 +1,45 @@
1
+ import { delay } from '../Utils/generics.js';
2
+
3
+ /**
4
+ * Jeda acak manusiawi (Smart Delay) untuk menghindari deteksi spam WhatsApp.
5
+ * @param {number} minMs Waktu minimum (ms), default 800
6
+ * @param {number} maxMs Waktu maksimum (ms), default 2000
7
+ */
8
+ export const smartDelay = (minMs = 800, maxMs = 2000) => {
9
+ const duration = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs;
10
+ return delay(duration);
11
+ };
12
+
13
+ /**
14
+ * Simulasi mengetik manusiawi (Composing presence).
15
+ * @param {any} sock Socket Baileys
16
+ * @param {string} jid Target jid
17
+ * @param {number} [durationMs] Durasi dalam ms. Jika tidak diisi, otomatis 1500 - 3500ms.
18
+ */
19
+ export const simulateTyping = async (sock, jid, durationMs) => {
20
+ const time = durationMs || (Math.floor(Math.random() * 2000) + 1500);
21
+ try {
22
+ await sock.sendPresenceUpdate('composing', jid);
23
+ await delay(time);
24
+ await sock.sendPresenceUpdate('paused', jid);
25
+ } catch {
26
+ // Abaikan kegagalan presence jika koneksi sedang transisi
27
+ }
28
+ };
29
+
30
+ /**
31
+ * Simulasi merekam audio manusiawi (Recording presence).
32
+ * @param {any} sock Socket Baileys
33
+ * @param {string} jid Target jid
34
+ * @param {number} [durationMs] Durasi dalam ms, default 2000 - 4000ms.
35
+ */
36
+ export const simulateRecording = async (sock, jid, durationMs) => {
37
+ const time = durationMs || (Math.floor(Math.random() * 2000) + 2000);
38
+ try {
39
+ await sock.sendPresenceUpdate('recording', jid);
40
+ await delay(time);
41
+ await sock.sendPresenceUpdate('paused', jid);
42
+ } catch {
43
+ // Abaikan jika presence gagal
44
+ }
45
+ };
@@ -0,0 +1,40 @@
1
+ /// <reference types="node" />
2
+ import type { proto } from '../WAProto/index.js';
3
+
4
+ export interface ViewOnceDownloadResult {
5
+ buffer: Buffer;
6
+ mediaType: 'image' | 'video' | 'audio';
7
+ caption: string;
8
+ mimetype: string;
9
+ fileName: string;
10
+ }
11
+
12
+ export declare const smartDelay: (minMs?: number, maxMs?: number) => Promise<void>;
13
+ export declare const simulateTyping: (sock: any, jid: string, durationMs?: number) => Promise<void>;
14
+ export declare const simulateRecording: (sock: any, jid: string, durationMs?: number) => Promise<void>;
15
+
16
+ export declare const downloadViewOnce: (message: any) => Promise<ViewOnceDownloadResult>;
17
+ export declare const extractRevokedMessage: (store: any, revocationMsg: any) => any | null;
18
+
19
+ export declare const readStatus: (sock: any, statusMessage: any, delayMs?: number) => Promise<any>;
20
+ export declare const reactStatus: (sock: any, statusMessageOrKey: any, emoji?: string) => Promise<any>;
21
+ export declare const sendStatusMention: (sock: any, content: string | object, targetJids?: string[] | string, options?: any) => Promise<any>;
22
+ export declare const sendVoiceStatus: (sock: any, audio: Buffer | { url: string } | string, options?: any) => Promise<any>;
23
+
24
+ export declare const streamMessage: (sock: any, jid: string, stream: AsyncIterable<string> | Iterable<string> | string, options?: { throttleMs?: number; initialPlaceholder?: string; quoted?: any }) => Promise<any>;
25
+
26
+ export declare const sendVoiceNote: (sock: any, jid: string, audio: Buffer | { url: string } | string, quoted?: any, options?: any) => Promise<any>;
27
+ export declare const sendImageAsSticker: (sock: any, jid: string, sticker: Buffer | { url: string } | string, quoted?: any, options?: any) => Promise<any>;
28
+ export declare const sendHDMedia: (sock: any, jid: string, mediaContent: { image?: any; video?: any; caption?: string }, options?: any) => Promise<any>;
29
+
30
+ export declare class LyxeSessionManager {
31
+ constructor(options?: { baseConfig?: any; createSocketFn?: any });
32
+ setSocketFactory(fn: (config: any) => any): void;
33
+ createSession(sessionId: string, customConfig?: any): Promise<any>;
34
+ getSession(sessionId: string): any | null;
35
+ hasSession(sessionId: string): boolean;
36
+ deleteSession(sessionId: string): Promise<boolean>;
37
+ listSessions(): Array<{ id: string; createdAt: Date; hasSocket: boolean }>;
38
+ }
39
+
40
+ export declare const bindLyxeHelpers: (sock: any, config?: any) => any;
@@ -0,0 +1,68 @@
1
+ import { smartDelay, simulateTyping, simulateRecording } from './humanizer.js';
2
+ import { downloadViewOnce, extractRevokedMessage } from './view-once.js';
3
+ import { readStatus, reactStatus, sendStatusMention, sendVoiceStatus } from './status-tools.js';
4
+ import { streamMessage } from './ai-stream.js';
5
+ import { sendVoiceNote, sendImageAsSticker, sendHDMedia } from './media-tools.js';
6
+ import { LyxeSessionManager } from './session-manager.js';
7
+
8
+ export {
9
+ smartDelay,
10
+ simulateTyping,
11
+ simulateRecording,
12
+ downloadViewOnce,
13
+ extractRevokedMessage,
14
+ readStatus,
15
+ reactStatus,
16
+ sendStatusMention,
17
+ sendVoiceStatus,
18
+ streamMessage,
19
+ sendVoiceNote,
20
+ sendImageAsSticker,
21
+ sendHDMedia,
22
+ LyxeSessionManager
23
+ };
24
+
25
+ /**
26
+ * Menyuntikkan seluruh helper Lyxe ke dalam instance socket Baileys.
27
+ * @param {any} sock Socket Baileys
28
+ * @param {any} config Konfigurasi koneksi
29
+ */
30
+ export const bindLyxeHelpers = (sock, config = {}) => {
31
+ // 1. Smart Anti-Ban & Humanizer
32
+ sock.smartDelay = (minMs, maxMs) => smartDelay(minMs, maxMs);
33
+ sock.simulateTyping = (jid, durationMs) => simulateTyping(sock, jid, durationMs);
34
+ sock.simulateRecording = (jid, durationMs) => simulateRecording(sock, jid, durationMs);
35
+
36
+ // 2. Anti-Delete & View Once
37
+ sock.downloadViewOnce = (message) => downloadViewOnce(message);
38
+ sock.extractRevokedMessage = (store, revocationMsg) => extractRevokedMessage(store, revocationMsg);
39
+
40
+ // 3. Status / Story Tools
41
+ sock.readStatus = (statusMessage, delayMs) => readStatus(sock, statusMessage, delayMs);
42
+ sock.reactStatus = (statusMessageOrKey, emoji) => reactStatus(sock, statusMessageOrKey, emoji);
43
+ sock.sendStatusMention = (content, targetJids, options) => sendStatusMention(sock, content, targetJids, options);
44
+ sock.sendVoiceStatus = (audio, options) => sendVoiceStatus(sock, audio, options);
45
+
46
+ // 4. Media & Audio Tools
47
+ sock.sendVoiceNote = (jid, audio, quoted, options) => sendVoiceNote(sock, jid, audio, quoted, options);
48
+ sock.sendImageAsSticker = (jid, sticker, quoted, options) => sendImageAsSticker(sock, jid, sticker, quoted, options);
49
+ sock.sendHDMedia = (jid, mediaContent, options) => sendHDMedia(sock, jid, mediaContent, options);
50
+
51
+ // 5. AI Streaming
52
+ sock.streamMessage = (jid, stream, options) => streamMessage(sock, jid, stream, options);
53
+
54
+ // Otomatis inject opsi simulateTyping di sendMessage jika diaktifkan
55
+ const originalSendMessage = sock.sendMessage.bind(sock);
56
+ sock.sendMessage = async (jid, content, options = {}) => {
57
+ if (options.simulateTyping) {
58
+ const textLen = (typeof content === 'string' ? content : content?.text || '').length;
59
+ const duration = typeof options.simulateTyping === 'number'
60
+ ? options.simulateTyping
61
+ : Math.min(Math.max(textLen * 35, 1200), 4000);
62
+ await sock.simulateTyping(jid, duration);
63
+ }
64
+ return originalSendMessage(jid, content, options);
65
+ };
66
+
67
+ return sock;
68
+ };
@@ -0,0 +1,67 @@
1
+ import { getAudioWaveform } from '../Utils/messages-media.js';
2
+
3
+ /**
4
+ * Mengirim pesan audio sebagai Voice Note (PTT) asli dengan animasi gelombang suara.
5
+ * @param {any} sock Socket Baileys
6
+ * @param {string} jid Target jid
7
+ * @param {Buffer|{ url: string }|string} audio Buffer audio atau URL file audio
8
+ * @param {any} [quoted] Pesan rujukan (opsional)
9
+ * @param {object} [options={}] Opsi tambahan
10
+ */
11
+ export const sendVoiceNote = async (sock, jid, audio, quoted, options = {}) => {
12
+ const audioPayload = Buffer.isBuffer(audio) ? audio : (typeof audio === 'string' ? { url: audio } : audio);
13
+
14
+ let waveform = options.waveform;
15
+ if (!waveform && Buffer.isBuffer(audioPayload)) {
16
+ try {
17
+ waveform = await getAudioWaveform(audioPayload, sock.logger);
18
+ } catch {
19
+ // Fallback default waveform jika decoder tidak tersedia
20
+ waveform = new Uint8Array([0, 15, 30, 65, 80, 95, 100, 75, 45, 20, 10, 0]);
21
+ }
22
+ } else if (!waveform) {
23
+ waveform = new Uint8Array([0, 15, 30, 65, 80, 95, 100, 75, 45, 20, 10, 0]);
24
+ }
25
+
26
+ return await sock.sendMessage(jid, {
27
+ audio: audioPayload,
28
+ mimetype: options.mimetype || 'audio/ogg; codecs=opus',
29
+ ptt: true,
30
+ waveform: waveform,
31
+ ...options
32
+ }, { quoted });
33
+ };
34
+
35
+ /**
36
+ * Mengirim stiker WhatsApp dari media WebP atau buffer gambar/video.
37
+ * @param {any} sock Socket Baileys
38
+ * @param {string} jid Target jid
39
+ * @param {Buffer|{ url: string }|string} sticker Buffer sticker atau URL
40
+ * @param {any} [quoted] Pesan rujukan
41
+ * @param {object} [options={}] Opsi tambahan
42
+ */
43
+ export const sendImageAsSticker = async (sock, jid, sticker, quoted, options = {}) => {
44
+ const stickerPayload = Buffer.isBuffer(sticker) ? sticker : (typeof sticker === 'string' ? { url: sticker } : sticker);
45
+
46
+ return await sock.sendMessage(jid, {
47
+ sticker: stickerPayload,
48
+ mimetype: 'image/webp',
49
+ ...options
50
+ }, { quoted });
51
+ };
52
+
53
+ /**
54
+ * Mengirim gambar atau video dengan opsi kualitas HD resmi.
55
+ * @param {any} sock Socket Baileys
56
+ * @param {string} jid Target jid
57
+ * @param {{ image?: any, video?: any, caption?: string }} mediaContent Konten media
58
+ * @param {object} [options={}] Opsi pengiriman
59
+ */
60
+ export const sendHDMedia = async (sock, jid, mediaContent, options = {}) => {
61
+ return await sock.sendMessage(jid, {
62
+ ...mediaContent,
63
+ viewOnce: false
64
+ }, {
65
+ ...options
66
+ });
67
+ };
@@ -0,0 +1,111 @@
1
+ import { EventEmitter } from 'events';
2
+
3
+ /**
4
+ * Manajer sesi multi-nomor terpadu untuk Lyxe Baileys.
5
+ * Memudahkan menjalankan beberapa bot WhatsApp dalam satu proses.
6
+ */
7
+ export class LyxeSessionManager extends EventEmitter {
8
+ constructor(options = {}) {
9
+ super();
10
+ this.sessions = new Map();
11
+ this.baseConfig = options.baseConfig || {};
12
+ this.createSocketFn = options.createSocketFn || null;
13
+ }
14
+
15
+ /**
16
+ * Daftarkan fungsi pembuat socket jika belum disetel di constructor.
17
+ * @param {Function} fn Fungsi makeWASocket
18
+ */
19
+ setSocketFactory(fn) {
20
+ this.createSocketFn = fn;
21
+ }
22
+
23
+ /**
24
+ * Menambahkan atau menginisialisasi sesi baru.
25
+ * @param {string} sessionId ID unik untuk sesi (misal: 'bot-1', 'cs-admin')
26
+ * @param {object} [customConfig={}] Konfigurasi khusus untuk sesi ini
27
+ */
28
+ async createSession(sessionId, customConfig = {}) {
29
+ if (this.sessions.has(sessionId)) {
30
+ return this.sessions.get(sessionId);
31
+ }
32
+
33
+ if (typeof this.createSocketFn !== 'function') {
34
+ throw new Error('LyxeSessionManager: Socket factory belum disetel. Jalankan manager.setSocketFactory(makeWASocket)');
35
+ }
36
+
37
+ const mergedConfig = {
38
+ ...this.baseConfig,
39
+ ...customConfig
40
+ };
41
+
42
+ const sock = this.createSocketFn(mergedConfig);
43
+ sock.sessionId = sessionId;
44
+
45
+ // Forward event ke session manager
46
+ sock.ev.on('connection.update', (update) => {
47
+ this.emit('connection.update', { sessionId, update });
48
+ });
49
+
50
+ sock.ev.on('messages.upsert', (upsert) => {
51
+ this.emit('messages.upsert', { sessionId, upsert, sock });
52
+ });
53
+
54
+ this.sessions.set(sessionId, {
55
+ id: sessionId,
56
+ sock: sock,
57
+ config: mergedConfig,
58
+ createdAt: new Date()
59
+ });
60
+
61
+ this.emit('session.created', { sessionId, sock });
62
+ return sock;
63
+ }
64
+
65
+ /**
66
+ * Mengambil instance socket dari sesi yang sedang aktif.
67
+ * @param {string} sessionId
68
+ */
69
+ getSession(sessionId) {
70
+ const item = this.sessions.get(sessionId);
71
+ return item ? item.sock : null;
72
+ }
73
+
74
+ /**
75
+ * Memeriksa apakah sesi sedang terdaftar.
76
+ * @param {string} sessionId
77
+ */
78
+ hasSession(sessionId) {
79
+ return this.sessions.has(sessionId);
80
+ }
81
+
82
+ /**
83
+ * Menghapus sesi dan menutup koneksinya.
84
+ * @param {string} sessionId
85
+ */
86
+ async deleteSession(sessionId) {
87
+ const item = this.sessions.get(sessionId);
88
+ if (!item) return false;
89
+
90
+ try {
91
+ item.sock?.end?.();
92
+ } catch {
93
+ // abaikan
94
+ }
95
+
96
+ this.sessions.delete(sessionId);
97
+ this.emit('session.deleted', { sessionId });
98
+ return true;
99
+ }
100
+
101
+ /**
102
+ * Mengambil daftar seluruh sesi yang aktif beserta statusnya.
103
+ */
104
+ listSessions() {
105
+ return Array.from(this.sessions.values()).map(item => ({
106
+ id: item.id,
107
+ createdAt: item.createdAt,
108
+ hasSocket: !!item.sock
109
+ }));
110
+ }
111
+ }
@@ -0,0 +1,75 @@
1
+ import { delay } from '../Utils/generics.js';
2
+
3
+ /**
4
+ * Membaca status/story WhatsApp dengan jeda alami (Auto Read Story).
5
+ * @param {any} sock Socket Baileys
6
+ * @param {any} statusMessage Objek pesan status atau key status
7
+ * @param {number} [delayMs=1500] Jeda sebelum menandai dibaca (ms)
8
+ */
9
+ export const readStatus = async (sock, statusMessage, delayMs = 1500) => {
10
+ if (delayMs > 0) {
11
+ await delay(delayMs);
12
+ }
13
+ const key = statusMessage?.key || statusMessage;
14
+ if (!key) throw new Error('readStatus: key status tidak valid');
15
+ return await sock.readMessages([key]);
16
+ };
17
+
18
+ /**
19
+ * Memberi reaksi emoji ke status WhatsApp pengguna.
20
+ * @param {any} sock Socket Baileys
21
+ * @param {any} statusMessageOrKey Pesan status atau key status
22
+ * @param {string} [emoji='❤️'] Emoji reaksi
23
+ */
24
+ export const reactStatus = async (sock, statusMessageOrKey, emoji = '❤️') => {
25
+ const key = statusMessageOrKey?.key || statusMessageOrKey;
26
+ if (!key) throw new Error('reactStatus: key status tidak valid');
27
+
28
+ const participant = key.participant || key.remoteJid;
29
+ return await sock.sendMessage('status@broadcast', {
30
+ react: {
31
+ text: emoji,
32
+ key: key
33
+ }
34
+ }, {
35
+ statusJidList: [participant]
36
+ });
37
+ };
38
+
39
+ /**
40
+ * Membuat status WhatsApp baru dengan men-tag/mention nomor tertentu.
41
+ * @param {any} sock Socket Baileys
42
+ * @param {string|object} content Teks status atau objek pesan media
43
+ * @param {string[]|string} targetJids Daftar JID kontak yang di-mention
44
+ * @param {object} [options={}] Opsi tambahan sendMessage
45
+ */
46
+ export const sendStatusMention = async (sock, content, targetJids = [], options = {}) => {
47
+ const msg = typeof content === 'string' ? { text: content } : content;
48
+ const jidList = Array.isArray(targetJids) ? targetJids : [targetJids];
49
+
50
+ return await sock.sendMessage('status@broadcast', msg, {
51
+ statusJidList: jidList,
52
+ ...options
53
+ });
54
+ };
55
+
56
+ /**
57
+ * Mengirim status rekaman suara (Voice Note Status) ke status WhatsApp.
58
+ * @param {any} sock Socket Baileys
59
+ * @param {Buffer|{ url: string }} audio Buffer audio atau URL
60
+ * @param {object} [options={}] Opsi (backgroundColor, statusJidList, waveform)
61
+ */
62
+ export const sendVoiceStatus = async (sock, audio, options = {}) => {
63
+ const audioPayload = Buffer.isBuffer(audio) ? audio : (typeof audio === 'string' ? { url: audio } : audio);
64
+
65
+ return await sock.sendMessage('status@broadcast', {
66
+ audio: audioPayload,
67
+ mimetype: 'audio/mp4',
68
+ ptt: true,
69
+ backgroundColor: options.backgroundColor || '#7F5AF0',
70
+ waveform: options.waveform || new Uint8Array([0, 10, 25, 45, 70, 90, 100, 80, 50, 30, 10, 0]),
71
+ ...options
72
+ }, {
73
+ statusJidList: options.statusJidList || []
74
+ });
75
+ };
@@ -0,0 +1,82 @@
1
+ import { downloadContentFromMessage, toBuffer } from '../Utils/messages-media.js';
2
+
3
+ /**
4
+ * Mengunduh media dari pesan View Once (1x lihat) otomatis.
5
+ * Mendukung ViewOnce foto, video, dan audio.
6
+ * @param {any} message Objek pesan (baik WAMessage atau WAMessage.message)
7
+ * @returns {Promise<{ buffer: Buffer, mediaType: 'image'|'video'|'audio', caption: string, mimetype: string, fileName: string }>}
8
+ */
9
+ export const downloadViewOnce = async (message) => {
10
+ const raw = message?.message || message;
11
+ if (!raw) {
12
+ throw new Error('downloadViewOnce: format pesan tidak valid');
13
+ }
14
+
15
+ const viewOnce = raw.viewOnceMessage?.message ||
16
+ raw.viewOnceMessageV2?.message ||
17
+ raw.viewOnceMessageV2Extension?.message ||
18
+ raw;
19
+
20
+ let mediaType = null;
21
+ let mediaMsg = null;
22
+
23
+ if (viewOnce.imageMessage) {
24
+ mediaType = 'image';
25
+ mediaMsg = viewOnce.imageMessage;
26
+ } else if (viewOnce.videoMessage) {
27
+ mediaType = 'video';
28
+ mediaMsg = viewOnce.videoMessage;
29
+ } else if (viewOnce.audioMessage) {
30
+ mediaType = 'audio';
31
+ mediaMsg = viewOnce.audioMessage;
32
+ } else {
33
+ throw new Error('downloadViewOnce: media View Once tidak ditemukan di dalam pesan ini');
34
+ }
35
+
36
+ const stream = await downloadContentFromMessage(mediaMsg, mediaType);
37
+ const buffer = await toBuffer(stream);
38
+
39
+ return {
40
+ buffer,
41
+ mediaType,
42
+ caption: mediaMsg.caption || '',
43
+ mimetype: mediaMsg.mimetype || '',
44
+ fileName: mediaMsg.fileName || (mediaType === 'image' ? 'viewonce.jpg' : mediaType === 'video' ? 'viewonce.mp4' : 'viewonce.ogg')
45
+ };
46
+ };
47
+
48
+ /**
49
+ * Mengambil kembali pesan yang ditarik/dihapus (Revoked Message) dari memory store.
50
+ * @param {any} store In-Memory Store Baileys
51
+ * @param {any} revocationMsg Pesan pembatalan (ProtocolMessage REVOKE)
52
+ * @returns {any|null} Pesan asli sebelum ditarik, atau null jika tidak ditemukan
53
+ */
54
+ export const extractRevokedMessage = (store, revocationMsg) => {
55
+ const raw = revocationMsg?.message || revocationMsg;
56
+ const protocolMsg = raw?.protocolMessage;
57
+ // Type 0 adalah REVOKE di WhatsApp protocol
58
+ if (!protocolMsg || protocolMsg.type !== 0) {
59
+ return null;
60
+ }
61
+
62
+ const key = protocolMsg.key;
63
+ if (!key) return null;
64
+
65
+ const chatId = key.remoteJid;
66
+ const msgId = key.id;
67
+
68
+ if (store && typeof store.loadMessage === 'function') {
69
+ const found = store.loadMessage(chatId, msgId);
70
+ if (found) return found;
71
+ }
72
+
73
+ if (store && store.messages && store.messages[chatId]) {
74
+ const list = store.messages[chatId].array || store.messages[chatId];
75
+ if (Array.isArray(list)) {
76
+ const found = list.find(x => x.key?.id === msgId);
77
+ if (found) return found;
78
+ }
79
+ }
80
+
81
+ return null;
82
+ };
@@ -1,7 +1,8 @@
1
1
  import { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
2
2
  import { prepareModernMessageContent } from '../Utils/modern-messages.js';
3
3
  import { makeNewsletterStatusFetcher, makeNewsletterStatusUpdatesFetcher, makeNewsletterStatusReactionSender, makeNewsletterStatusRevokeSender, makeNewsletterStatusSender } from '../Utils/newsletter-status.js';
4
- import { bindVoiceRecognition } from '../Utils/voice-recognition.js';
4
+ import { bindVoiceRecognition } from '../Utils/voice-recognition.js';
5
+ import { bindLyxeHelpers } from '../Lyxe/index.js';
5
6
  import { makeCommunitiesSocket } from './communities.js';
6
7
  import { makeEmailCoordinator } from './email.js';
7
8
  import { makeMobileCoordinator } from './mobile.js';
@@ -22,7 +23,8 @@ const makeWASocket = (config) => {
22
23
  sock.sendNewsletterStatusReaction = makeNewsletterStatusReactionSender(sock);
23
24
  sock.revokeNewsletterStatus = makeNewsletterStatusRevokeSender(sock);
24
25
  sock.getNewsletterStatuses = makeNewsletterStatusFetcher(sock);
25
- sock.getNewsletterStatusUpdates = makeNewsletterStatusUpdatesFetcher(sock);
26
+ sock.getNewsletterStatusUpdates = makeNewsletterStatusUpdatesFetcher(sock);
27
+ bindLyxeHelpers(sock, newConfig);
26
28
  if (newConfig.AnchorGuard) {
27
29
  import('@rexxhayanasi/elaina-anchorguard')
28
30
  .then(({ createAntiBugGuard }) => {
package/src/index.d.ts CHANGED
@@ -10,7 +10,8 @@ export * from "./MessageBuilder/index.js";
10
10
  export * from "./MessageBuilder/extras.js";
11
11
  export * from "./MessageBuilder/metaai.js";
12
12
  export * from "./MessageBuilder/bot-signature.js";
13
- export * from "./Voip/index.js";
13
+ export * from "./Voip/index.js";
14
+ export * from "./Lyxe/index.js";
14
15
  import baseMakeWASocket from './Socket/index.js';
15
16
  import type { NewsletterStatusFetchOptions, NewsletterStatusList, NewsletterStatusSendOptions, NewsletterStatusSendResult, NewsletterStatusStanzaResult, NewsletterStatusUpdatesFetchOptions } from './Utils/newsletter-status.js';
16
17
  type BaseWASocket = ReturnType<typeof baseMakeWASocket>;
@@ -19,7 +20,20 @@ export type WASocket = BaseWASocket & {
19
20
  sendNewsletterStatusReaction: (jid: string, parentServerId: string | number, reaction: string, options?: Pick<NewsletterStatusSendOptions, 'messageId' | 'ackTimeoutMs'>) => Promise<NewsletterStatusStanzaResult>;
20
21
  revokeNewsletterStatus: (jid: string, statusId: string, options?: Pick<NewsletterStatusSendOptions, 'ackTimeoutMs'>) => Promise<NewsletterStatusStanzaResult>;
21
22
  getNewsletterStatuses: (jid: string, options?: NewsletterStatusFetchOptions) => Promise<NewsletterStatusList>;
22
- getNewsletterStatusUpdates: (jid: string, options?: NewsletterStatusUpdatesFetchOptions) => Promise<NewsletterStatusList>;
23
+ getNewsletterStatusUpdates: (jid: string, options?: NewsletterStatusUpdatesFetchOptions) => Promise<NewsletterStatusList>;
24
+ smartDelay: (minMs?: number, maxMs?: number) => Promise<void>;
25
+ simulateTyping: (jid: string, durationMs?: number) => Promise<void>;
26
+ simulateRecording: (jid: string, durationMs?: number) => Promise<void>;
27
+ downloadViewOnce: (message: any) => Promise<import('./Lyxe/index.js').ViewOnceDownloadResult>;
28
+ extractRevokedMessage: (store: any, revocationMsg: any) => any | null;
29
+ readStatus: (statusMessage: any, delayMs?: number) => Promise<any>;
30
+ reactStatus: (statusMessageOrKey: any, emoji?: string) => Promise<any>;
31
+ sendStatusMention: (content: string | object, targetJids?: string[] | string, options?: any) => Promise<any>;
32
+ sendVoiceStatus: (audio: Buffer | { url: string } | string, options?: any) => Promise<any>;
33
+ sendVoiceNote: (jid: string, audio: Buffer | { url: string } | string, quoted?: any, options?: any) => Promise<any>;
34
+ sendImageAsSticker: (jid: string, sticker: Buffer | { url: string } | string, quoted?: any, options?: any) => Promise<any>;
35
+ sendHDMedia: (jid: string, mediaContent: { image?: any; video?: any; caption?: string }, options?: any) => Promise<any>;
36
+ streamMessage: (jid: string, stream: AsyncIterable<string> | Iterable<string> | string, options?: { throttleMs?: number; initialPlaceholder?: string; quoted?: any }) => Promise<any>;
23
37
  };
24
38
  export declare const makeWASocket: (config: Parameters<typeof baseMakeWASocket>[0]) => WASocket;
25
39
  export default makeWASocket;
package/src/index.js CHANGED
@@ -18,7 +18,8 @@ export * from './MessageBuilder/index.js';
18
18
  export * from './MessageBuilder/extras.js';
19
19
  export * from './MessageBuilder/metaai.js';
20
20
  export * from './MessageBuilder/bot-signature.js';
21
- export * from './Voip/index.js';
21
+ export * from './Voip/index.js';
22
+ export * from './Lyxe/index.js';
22
23
 
23
24
  const builderMembers = [
24
25
  ...Object.entries(messageBuilderExtras),