kage-baileys 1.1.9 → 1.1.10

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.
@@ -2290,8 +2290,6 @@ message Message {
2290
2290
  optional DeviceSentMessage deviceSentMessage = 31;
2291
2291
  optional MessageContextInfo messageContextInfo = 35;
2292
2292
  optional ListMessage listMessage = 36;
2293
- // Kage: preserve the actual wire envelope on receive. Local download/re-upload
2294
- // helpers live in lib/Utils/view-once.js; no custom protobuf tags are required.
2295
2293
  optional FutureProofMessage viewOnceMessage = 37;
2296
2294
  optional OrderMessage orderMessage = 38;
2297
2295
  optional ListResponseMessage listResponseMessage = 39;
@@ -8,9 +8,6 @@ const makeWASocket = (config = {}) => {
8
8
  ...Defaults_1.DEFAULT_CONNECTION_CONFIG,
9
9
  ...config
10
10
  });
11
- // Unified socket helpers: normal media, view-once re-upload and contact status archives.
12
- // Automation stays OFF unless explicitly enabled with kageTools / owner options.
13
- const tools = require('../Utils/automation-tools').installKageTools(socket, config.kageTools || {});
14
- return tools;
11
+ return require('../Utils/automation-tools').installKageTools(socket, config.kageTools || {});
15
12
  };
16
13
  exports.default = makeWASocket;
@@ -42,7 +42,7 @@ async function downloadNormalMedia(conn, raw, options = {}) {
42
42
  chunks.push(data);
43
43
  }
44
44
  if (!size) throw new Error('EMPTY_MEDIA: WhatsApp no entregó datos.');
45
- return { buffer: Buffer.concat(chunks, size), type: media.type, mimetype: media.value.mimetype || 'application/octet-stream', caption: media.value.caption || '', ptt: !!media.value.ptt, gifPlayback: !!media.value.gifPlayback, fileName: media.value.fileName || '', bytes: size };
45
+ return { buffer: Buffer.concat(chunks, size), type: media.type, mimetype: media.value.mimetype || 'application/octet-stream', caption: media.value.caption || '', bytes: size };
46
46
  })();
47
47
  try {
48
48
  return await Promise.race([job, new Promise((_, reject) => { timer = setTimeout(() => reject(new Error('MEDIA_TIMEOUT: tiempo de espera agotado.')), timeoutMs); })]);
@@ -95,9 +95,9 @@ function handleAutoMedia(raw, conn, settings = {}, options = {}) {
95
95
  state.seen.set(id, now);
96
96
  while (state.seen.size > 500) state.seen.delete(state.seen.keys().next().value);
97
97
  state.pending++;
98
- const job = state.tail.then(() => settings.autoDownloadChats?.includes(raw.key.remoteJid) ? saveNormalMedia(conn, raw, options) : null);
98
+ const job = state.tail.then(() => saveNormalMedia(conn, raw, options));
99
99
  state.tail = job.catch(() => {}).finally(() => { state.pending--; });
100
- return job.catch(error => { state.seen.delete(id); throw error; });
100
+ return job;
101
101
  }
102
102
  async function sendAIResponse(conn, jid, text, options = {}) {
103
103
  if (typeof text !== 'string' || !text.trim()) throw new TypeError('AI response text must be nonempty.');
@@ -113,17 +113,6 @@ function installKageTools(conn, options = {}) {
113
113
  Object.defineProperty(conn, '__kageToolsInstalled', { value: true });
114
114
  const status = require('./status-tools');
115
115
  const country = require('./country-info');
116
- const view = require('./view-once');
117
- const archives = require('./status-archive');
118
- conn.statusContactsOnly = options.contactsOnly !== false;
119
- require('./status-contacts').installStatusContacts(conn);
120
- conn.getViewOnceContent = view.getViewOnceContent;
121
- conn.normalizeViewOnceMessage = view.normalizeViewOnceMessage;
122
- conn.downloadViewOnceMessage = (raw, opts) => view.downloadViewOnceMessage(conn, raw, opts);
123
- conn.resendViewOnceMessage = (raw, opts) => view.resendViewOnceMessage(conn, raw, opts);
124
- conn.handleAutoViewOnce = (raw, settings, opts) => require('./consented-media').handleAutoViewOnce(raw, conn, settings, opts);
125
- conn.exportReceivedStatuses = (author, opts) => archives.exportStatusZip(conn, author, opts);
126
- conn.saveReceivedStatus = (entry, opts) => archives.saveStatus(conn, entry, opts);
127
116
  conn.getReceivedStatuses = (includeUnavailable = false) => status.listStatuses(conn, includeUnavailable);
128
117
  conn.reactToReceivedStatus = (entry, emoji) => status.reactToStatus(conn, entry, emoji);
129
118
  conn.getCountryForJid = jid => country.getCountryForJid(conn, jid);
@@ -136,7 +125,7 @@ function installKageTools(conn, options = {}) {
136
125
  conn.enableStatusTracking = (settings = {}) => {
137
126
  if (stop) return stop;
138
127
  let active = true;
139
- const scopedSettings = new Proxy(settings, { get(target, key) { return ['statusReaction', 'statusSave'].includes(key) ? active && target[key] : target[key]; } });
128
+ const scopedSettings = new Proxy(settings, { get(target, key) { return key === 'statusReaction' ? active && target[key] : target[key]; } });
140
129
  const upsert = event => { for (const raw of event?.messages || []) status.handleStatus(raw, conn, scopedSettings).catch(e => conn.logger?.warn?.({ error: e.message }, 'status tracking')); };
141
130
  const deleted = event => { for (const key of event?.keys || []) status.markStatusDeleted(conn, key); };
142
131
  const updated = items => { for (const item of items || []) if (item.key?.remoteJid === 'status@broadcast' && item.update?.message === null) status.markStatusDeleted(conn, item.key); };
@@ -156,23 +145,6 @@ function installKageTools(conn, options = {}) {
156
145
  };
157
146
  return stop;
158
147
  };
159
- let stopAutomation;
160
- conn.enableMediaAutomation = (settings = {}) => {
161
- if (stopAutomation) return stopAutomation;
162
- const get = () => typeof settings === 'function' ? settings() : settings;
163
- const incoming = event => {
164
- if (event?.type && event.type !== 'notify') return;
165
- for (const raw of event?.messages || []) {
166
- handleAutoMedia(raw, conn, get()).catch(error => conn.logger?.warn?.({ error: error.message }, 'auto media'));
167
- require('./consented-media').handleAutoViewOnce(raw, conn, get()).catch(error => conn.logger?.warn?.({ error: error.message }, 'auto view once'));
168
- }
169
- };
170
- const closed = update => { if (update.connection === 'close') stopAutomation?.(); };
171
- conn.ev.on('messages.upsert', incoming); conn.ev.on('connection.update', closed);
172
- stopAutomation = () => { conn.ev.off('messages.upsert', incoming); conn.ev.off('connection.update', closed); stopAutomation = undefined; };
173
- return stopAutomation;
174
- };
175
- if (options.mediaAutomation) conn.enableMediaAutomation(options.mediaSettings || {});
176
148
  if (options.statusTracking) conn.enableStatusTracking(options.statusSettings || {});
177
149
  return conn;
178
150
  }
@@ -2,6 +2,25 @@
2
2
  const normal = require('./automation-tools');
3
3
  const queues = new WeakMap();
4
4
  const jid = value => String(value || '').replace(/:\d+@/, '@');
5
+ function getViewOnceContent(raw) {
6
+ let message = raw?.message;
7
+ let viewOnce = false;
8
+ const seen = new Set();
9
+ for (let depth = 0; depth < 12 && message && typeof message === 'object'; depth++) {
10
+ if (seen.has(message)) return null;
11
+ seen.add(message);
12
+ const wrapper = ['ephemeralMessage', 'documentWithCaptionMessage', 'viewOnceMessage', 'viewOnceMessageV2', 'viewOnceMessageV2Extension'].find(key => message[key]?.message);
13
+ if (wrapper) {
14
+ viewOnce ||= wrapper.startsWith('viewOnce');
15
+ message = message[wrapper].message;
16
+ continue;
17
+ }
18
+ const type = ['imageMessage', 'videoMessage', 'audioMessage', 'documentMessage', 'stickerMessage'].find(key => message[key] && typeof message[key] === 'object');
19
+ if (!type) return null;
20
+ return { type, value: message[type], message, viewOnce: viewOnce || message[type].viewOnce === true };
21
+ }
22
+ return null;
23
+ }
5
24
  function prepareConsentedViewOnce(conn, raw, options = {}) {
6
25
  const chat = raw?.key?.remoteJid;
7
26
  if (!/^\d+@(s\.whatsapp\.net|lid)$/.test(chat || '')) throw new Error('CONSENT_PRIVATE_ONLY: solo medios propios/autorizados en privados.');
@@ -30,15 +49,12 @@ async function saveConsentedViewOnce(conn, raw, options = {}) {
30
49
  }
31
50
  function handleAutoViewOnce(raw, conn, settings = {}, options = {}) {
32
51
  const chat = raw?.key?.remoteJid;
33
- const automatic = settings.autoViewOnceChats?.includes(chat) === true;
34
52
  const consentJid = settings.autoViewOnceConsent?.[chat];
35
- if ((!automatic && !consentJid) || !raw?.key?.id || raw.key.fromMe || chat === 'status@broadcast') return Promise.resolve(null);
53
+ if (!consentJid || !raw?.key?.id) return Promise.resolve(null);
54
+ if (Array.isArray(settings.autoViewOnceChats) && !settings.autoViewOnceChats.includes(chat)) return Promise.resolve(null);
36
55
  const timestamp = Number(raw.messageTimestamp?.toNumber?.() ?? raw.messageTimestamp ?? 0) * 1000;
37
56
  if (!timestamp || Date.now() - timestamp > 300000 || timestamp > Date.now() + 60000) return Promise.resolve(null);
38
- try {
39
- if (automatic) require('./view-once').normalizeViewOnceMessage(raw);
40
- else prepareConsentedViewOnce(conn, raw, { consentJid });
41
- }
57
+ try { prepareConsentedViewOnce(conn, raw, { consentJid }); }
42
58
  catch { return Promise.resolve(null); }
43
59
  let state = queues.get(conn);
44
60
  if (!state) { state = { tail: Promise.resolve(), pending: 0, seen: new Map() }; queues.set(conn, state); }
@@ -50,16 +66,14 @@ function handleAutoViewOnce(raw, conn, settings = {}, options = {}) {
50
66
  state.pending++; state.seen.set(id, now);
51
67
  while (state.seen.size > 500) state.seen.delete(state.seen.keys().next().value);
52
68
  const task = state.tail.then(() => {
53
- if (automatic) {
54
- if (!settings.autoViewOnceChats?.includes(chat)) return null;
55
- return require('./view-once').resendViewOnceMessage(conn, raw, { ...options, shouldSend: () => settings.autoViewOnceChats?.includes(chat) === true });
56
- }
57
69
  if (settings.autoViewOnceConsent?.[chat] !== consentJid) return null;
70
+ if (Array.isArray(settings.autoViewOnceChats) && !settings.autoViewOnceChats.includes(chat)) return null;
58
71
  return saveConsentedViewOnce(conn, raw, { ...options, consentJid });
59
72
  });
60
73
  state.tail = task.catch(() => {}).finally(() => { state.pending--; });
61
- return task.catch(error => { state.seen.delete(id); throw error; });
74
+ return task;
62
75
  }
76
+ exports.getViewOnceContent = getViewOnceContent;
63
77
  exports.prepareConsentedViewOnce = prepareConsentedViewOnce;
64
78
  exports.downloadConsentedViewOnce = downloadConsentedViewOnce;
65
79
  exports.saveConsentedViewOnce = saveConsentedViewOnce;
@@ -780,7 +780,7 @@ const normalizeMessageContent = (content) => {
780
780
  return undefined;
781
781
  }
782
782
  // set max iterations to prevent an infinite loop
783
- for (let i = 0; i < 16; i++) {
783
+ for (let i = 0; i < 5; i++) {
784
784
  const inner = getFutureProofMessage(content);
785
785
  if (!inner) {
786
786
  break;
@@ -112,7 +112,6 @@ function captureStatus(raw, conn) {
112
112
  const author = normalizeJid(sourceKey?.participant || (broadcast ? raw.participant : '') ||
113
113
  contexts.find(c => c.remoteJid === 'status@broadcast')?.participant || '')
114
114
  if (sourceKey) sourceKey = { ...sourceKey, participant: author || sourceKey.participant }
115
- if (conn.statusContactsOnly && !require('./status-contacts').isStatusContact(conn, author)) return null
116
115
  const sender = normalizeJid(raw.key.participant || (broadcast ? raw.participant : raw.key.remoteJid))
117
116
  const now = Date.now()
118
117
  const seconds = ntime(raw.messageTimestamp)
@@ -159,7 +158,7 @@ function captureStatus(raw, conn) {
159
158
  state.entries.set(identity, entry); prune(state); persist(state)
160
159
  return entry
161
160
  }
162
- function listStatuses(conn, includeUnavailable = false) { const state = stateFor(conn); prune(state); return [...state.entries.values()].filter(e => (!conn.statusContactsOnly || require('./status-contacts').isStatusContact(conn, e.author)) && (includeUnavailable || !['deleted', 'expired'].includes(e.availability))).sort((a, b) => a.receivedAt - b.receivedAt) }
161
+ function listStatuses(conn, includeUnavailable = false) { const state = stateFor(conn); prune(state); return [...state.entries.values()].filter(e => includeUnavailable || !['deleted', 'expired'].includes(e.availability)).sort((a, b) => a.receivedAt - b.receivedAt) }
163
162
  function findStatus(conn, selector = '') {
164
163
  const id = /^\d+$/.test(selector) ? `E${selector}` : String(selector).toUpperCase()
165
164
  return listStatuses(conn, true).find(entry => entry.id === id || entry.sourceKey?.id === selector)
@@ -173,7 +172,6 @@ async function reactToStatus(conn, entry, emoji, options = {}) {
173
172
  if (!isStatusEmoji(emoji)) throw new Error('Escribe un solo emoji, por ejemplo ❤️, 👍🏽 o 👨‍👩‍👧‍👦.')
174
173
  if (!entry || ['deleted', 'expired'].includes(entry.availability) || entry.expiresAt <= Date.now()) throw new Error('Ese estado ya no está disponible en la caché.')
175
174
  if (!entry.sourceKey?.id || !/@(s\.whatsapp\.net|lid)$/.test(entry.author)) throw new Error('La notificación no incluye la clave y el autor originales; no es posible reaccionar con seguridad.')
176
- if (conn.statusContactsOnly && !require('./status-contacts').isStatusContact(conn, entry.author)) throw new Error('Solo se permiten estados de contactos guardados del bot.')
177
175
  const self = normalizeJid(conn.user?.jid || conn.user?.id)
178
176
  if (entry.author === self || entry.author === normalizeJid(conn.user?.lid) || entry.sourceKey.fromMe) throw new Error('No se reacciona a los estados de la propia cuenta.')
179
177
  const state = stateFor(conn)
@@ -189,12 +187,7 @@ async function reactToStatus(conn, entry, emoji, options = {}) {
189
187
  }
190
188
  async function handleStatus(raw, conn, settings = {}) {
191
189
  if (raw?.key?.remoteJid !== 'status@broadcast') return false
192
- const content = statusContent(raw.message)
193
- const revocation = content.message?.protocolMessage
194
- if (revocation && (revocation.type === 0 || revocation.type === 'REVOKE')) { captureStatus(raw, conn); return true }
195
- if (conn.statusContactsOnly && !await require('./status-contacts').resolveStatusContact(conn, raw)) return true
196
190
  const entry = captureStatus(raw, conn)
197
- if (entry && settings.statusSave && !raw.key.fromMe) require('./status-archive').queueStatusSave(conn, entry, settings)
198
191
  if (!entry || !settings.statusReaction || raw.key.fromMe || entry.reactedAt) return true
199
192
  const state = stateFor(conn)
200
193
  state.scheduled ||= new Set()
@@ -21,7 +21,6 @@ var _indexjs3 = require('../WABinary/index.js');
21
21
  {
22
22
  id,
23
23
  name: action.fullName || action.firstName || action.username || undefined,
24
- isMyContact: !!(action.fullName || action.firstName),
25
24
  lid: lidJid || undefined,
26
25
  phoneNumber
27
26
  }
package/lib/index.d.ts CHANGED
@@ -170,7 +170,6 @@ export declare const downloadExternalPatch: any;
170
170
  export declare const downloadHistory: any;
171
171
  export declare const downloadMediaMessage: any;
172
172
  export declare const downloadNormalMedia: any;
173
- export declare const downloadViewOnceMessage: any;
174
173
  export declare const emitSyncActionResults: any;
175
174
  export declare const encodeBase64EncodedStringForUpload: any;
176
175
  export declare const encodeBigEndian: any;
@@ -183,7 +182,6 @@ export declare const encodeWAMessage: any;
183
182
  export declare const encryptMediaRetryRequest: any;
184
183
  export declare const encryptedStream: any;
185
184
  export declare const executeWMexQuery: any;
186
- export declare const exportStatusZip: any;
187
185
  export declare const extensionForMediaMessage: any;
188
186
  export declare const extractCommunityMetadata: any;
189
187
  export declare const extractDeviceJids: any;
@@ -271,7 +269,6 @@ export declare const hkdfInfoKey: any;
271
269
  export declare const hmacSign: any;
272
270
  export declare const initAuthCreds: any;
273
271
  export declare const installKageTools: any;
274
- export declare const installStatusContacts: any;
275
272
  export declare const isJidBot: any;
276
273
  export declare const isJidBroadcast: any;
277
274
  export declare const isJidGroup: any;
@@ -281,7 +278,6 @@ export declare const isJidStatusBroadcast: any;
281
278
  export declare const isJidUser: any;
282
279
  export declare const isLidUser: any;
283
280
  export declare const isRealMessage: any;
284
- export declare const isStatusContact: any;
285
281
  export declare const isStatusEmoji: any;
286
282
  export declare const isWABusinessPlatform: any;
287
283
  export declare const jidDecode: any;
@@ -299,10 +295,8 @@ export declare const makeStickerPack: any;
299
295
  export declare const markStatusDeleted: any;
300
296
  export declare const md5: any;
301
297
  export declare const mediaMessageSHA256B64: any;
302
- export declare const mediaSendContent: any;
303
298
  export declare const newLTHashState: any;
304
299
  export declare const normalizeMessageContent: any;
305
- export declare const normalizeViewOnceMessage: any;
306
300
  export declare const parseAndInjectE2ESessions: any;
307
301
  export declare const prepareConsentedViewOnce: any;
308
302
  export declare const prepareDisappearingMessageSettingContent: any;
@@ -313,22 +307,17 @@ export declare const processContactAction: any;
313
307
  export declare const processHistoryMessage: any;
314
308
  export declare const processSyncAction: any;
315
309
  export declare const promiseTimeout: any;
316
- export declare const queueStatusSave: any;
317
310
  export declare const reactToStatus: any;
318
311
  export declare const readAndEmitEventStream: any;
319
312
  export declare const reduceBinaryNodeToDictionary: any;
320
- export declare const resendViewOnceMessage: any;
321
- export declare const resolveStatusContact: any;
322
313
  export declare const saveConsentedViewOnce: any;
323
314
  export declare const saveNormalMedia: any;
324
- export declare const saveStatus: any;
325
315
  export declare const sendAIResponse: any;
326
316
  export declare const sha256: any;
327
317
  export declare const shouldIncludeReportingToken: any;
328
318
  export declare const shouldIncrementChatUnread: any;
329
319
  export declare const signedKeyPair: any;
330
320
  export declare const statusContent: any;
331
- export declare const stopStatusSaves: any;
332
321
  export declare const toBuffer: any;
333
322
  export declare const toJid: any;
334
323
  export declare const toNumber: any;
@@ -348,7 +337,6 @@ export declare const useMultiFileAuthState: any;
348
337
  export declare const version: any;
349
338
  export declare const vid2jpg: any;
350
339
  export declare const waitStatusReactions: any;
351
- export declare const waitStatusSaves: any;
352
340
  export declare const writeRandomPadMax16: any;
353
341
  export declare const xmppPreKey: any;
354
342
  export declare const xmppSignedPreKey: any;
package/lib/index.js CHANGED
@@ -102,7 +102,3 @@ __exportStar(require("./Utils/country-info.js"), exports);
102
102
  __exportStar(require("./Utils/automation-tools.js"), exports);
103
103
 
104
104
  __exportStar(require("./Utils/consented-media.js"), exports);
105
-
106
- __exportStar(require('./Utils/view-once.js'), exports);
107
- __exportStar(require('./Utils/status-contacts.js'), exports);
108
- __exportStar(require('./Utils/status-archive.js'), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kage-baileys",
3
- "version": "1.1.9",
3
+ "version": "1.1.10",
4
4
  "description": "Kage Baileys una libreria de WhatsApp.",
5
5
  "keywords": [
6
6
  "kage-baileys",
@@ -32,8 +32,7 @@
32
32
  "maintenance/**/*",
33
33
  "MANTENIMIENTO.txt",
34
34
  "test/**/*",
35
- "CAMBIOS-Y-USO.txt",
36
- "AUTOMATIZACION.txt"
35
+ "CAMBIOS-Y-USO.txt"
37
36
  ],
38
37
  "scripts": {
39
38
  "gen:protobuf": "node scripts/generate-protobuf.cjs",
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+ const test = require('node:test');
3
+ const assert = require('node:assert/strict');
4
+ const api = require('../lib');
5
+ for (const type of ['imageMessage', 'videoMessage', 'audioMessage', 'documentMessage', 'stickerMessage']) {
6
+ for (const wrapper of ['viewOnceMessage', 'viewOnceMessageV2', 'viewOnceMessageV2Extension']) {
7
+ test(`metadata compatibility ${wrapper}/${type} preserves original content`, () => {
8
+ const raw = { message: { ephemeralMessage: { message: { [wrapper]: { message: { [type]: { viewOnce: true, directPath: '/test' } } } } } } };
9
+ const snapshot = JSON.stringify(raw);
10
+ const media = api.getViewOnceContent(raw);
11
+ assert.equal(media.type, type);
12
+ assert.equal(media.viewOnce, true);
13
+ assert.equal(media.value, raw.message.ephemeralMessage.message[wrapper].message[type]);
14
+ assert.equal(JSON.stringify(raw), snapshot);
15
+ });
16
+ }
17
+ }
18
+ test('normal metadata is not marked as view once', () => {
19
+ assert.equal(api.getViewOnceContent({ message: { imageMessage: {} } }).viewOnce, false);
20
+ });
21
+ test('empty and circular metadata returns safely without fabrication', () => {
22
+ for (const raw of [null, undefined, {}, { message: {} }, { message: { viewOnceMessage: { message: {} } } }]) assert.equal(api.getViewOnceContent(raw), null);
23
+ const message = {};
24
+ message.ephemeralMessage = { message };
25
+ assert.equal(api.getViewOnceContent({ message }), null);
26
+ });
27
+ test('disabled switch blocks a pre-authorized download', async () => {
28
+ const chat = '51987654321@s.whatsapp.net';
29
+ const raw = { key: { id: 'off', remoteJid: chat }, messageTimestamp: Math.floor(Date.now() / 1000), message: { viewOnceMessage: { message: { imageMessage: {} } } } };
30
+ assert.equal(await api.handleAutoViewOnce(raw, {}, { autoViewOnceChats: [], autoViewOnceConsent: { [chat]: chat } }, { downloader: async () => { throw new Error('must not download'); } }), null);
31
+ });
@@ -119,7 +119,6 @@ test('random reaction uses configured emoji pool and deduplicates delivery', asy
119
119
  });
120
120
  test('socket bindings install and detach status listeners without duplicates', async () => {
121
121
  const c = socket(); api.installKageTools(c); api.installKageTools(c);
122
- c.ev.emit('contacts.upsert', [{ id: '51987654321@s.whatsapp.net', name: 'Contacto guardado' }]);
123
122
  const stop = c.enableStatusTracking(); assert.equal(c.enableStatusTracking(),stop); assert.equal(c.ev.listenerCount('messages.upsert'),1);
124
123
  c.ev.emit('messages.upsert',{messages:[raw()]}); await new Promise(r=>setImmediate(r)); assert.equal(c.getReceivedStatuses().length,1);
125
124
  stop(); assert.equal(c.ev.listenerCount('messages.upsert'),0); assert.equal(c.ev.listenerCount('messages.update'),0);
@@ -1,142 +0,0 @@
1
- AUTOMATIZACIÓN CHIAKI + KAGE BAILEYS — INSTRUCCIONES
2
-
3
- INSTALACIÓN
4
- 1. Haz una copia de seguridad de tu proyecto, sesiones y base de datos.
5
- 2. Extrae Chiaki-corregido.zip en la carpeta del bot. Conserva tus sesiones y datos propios.
6
- 3. Usa Node.js 22.12.0 o superior. Ejecuta npm install y después npm start.
7
- 4. Si estás reemplazando una instalación previa y npm conserva la librería antigua,
8
- ejecuta npm install --force antes de reiniciar.
9
- 5. Chiaki ya incluye vendor/kage-baileys-1.1.8-automatizacion.tgz. No necesitas
10
- publicar Kage en npm ni instalar el otro ZIP aparte para utilizar Chiaki.
11
- Los tres alias de Baileys de package.json apuntan al mismo paquete modificado.
12
- 6. El paquete original vendor/kage-baileys-1.1.8-revision.tgz se conserva por
13
- integridad del archivo aportado, pero package.json NO lo utiliza.
14
-
15
- AJUSTES CENTRALIZADOS
16
- La implementación está en lib/options.js. plugins/_options.js solo registra
17
- su exportación; no hay dos implementaciones de los interruptores.
18
- Los antiguos comandos .autodescarga / .autoviewonce solo orientan al propietario.
19
-
20
- .on autodescarga Archiva medios normales recibidos en este chat.
21
- .off autodescarga Desactiva esa descarga en este chat.
22
- .on autoviewonce Descarga y envía una copia normal en este chat.
23
- .off autoviewonce Detiene ese reenvío automático en este chat.
24
- .on guardarestados Guarda estados de contactos y envía copias a este privado.
25
- .off guardarestados Deja de guardar/enviar automáticamente estados nuevos.
26
- .on statuszip Cuando guardarestados está activo, entrega un ZIP por contacto.
27
- .off statuszip Vuelve a entregar cada estado por separado.
28
- .on statusreaction random ❤️ 🔥 👍 💜
29
- Selecciona un emoji de la lista por estado.
30
- .on statusreaction ❤️ Usa un emoji fijo.
31
- .off statusreaction Desactiva únicamente las reacciones automáticas.
32
-
33
- Solo el propietario del bot puede cambiar estas opciones. autodescarga y
34
- autoviewonce son por chat, también se pueden habilitar por el dueño en un grupo.
35
- guardarestados/statuszip se activan en el privado del propietario: las copias
36
- no se envían a grupos. La configuración se persiste en la base de datos por cuenta.
37
- Todo está desactivado inicialmente salvo ajustes previamente guardados.
38
- La activación es una vez; no hace falta ejecutar un comando por cada medio recibido.
39
- Usa el guardado y el reenvío únicamente con permiso de las personas remitentes.
40
-
41
- AUTOVIEWONCE
42
- Se atienden imageMessage, videoMessage y audioMessage; también se reconocen
43
- los demás tipos de medios soportados por Baileys si llegan en un envoltorio válido.
44
- Se reconocen viewOnceMessage, viewOnceMessageV2, viewOnceMessageV2Extension,
45
- ephemeralMessage y la marca viewOnce directamente en el medio.
46
- Primero se descarga y descifra el archivo entregado por WhatsApp. Después se
47
- suben los bytes como un medio NUEVO, no como forward/copyNForward y sin viewOnce.
48
- Se mantiene el texto, MIME, tipo de audio/PTT y GIF cuando están disponibles.
49
- El mensaje original no se modifica. Se ignoran los envíos del propio bot y se
50
- controlan duplicados y colas para evitar reenvíos en bucle.
51
- Solo se procesa recepción en vivo (notify), no lotes históricos append.
52
- Cambiar el interruptor a off durante la descarga evita el envío posterior.
53
-
54
- ESTADOS
55
- .estados Cuenta los estados recibidos disponibles por contacto.
56
- .estados todos Lista IDs, tipo y reacción del bot por estado.
57
- .estados historial Muestra caducidad y eliminaciones notificadas.
58
- .estadoinfo E1 Muestra información, color original y reacción registrada.
59
- .verestado E1 Envía el contenido de ese estado.
60
- .descargarestado E1 Descarga individual y metadatos.
61
- .estadoszip E1 ZIP de los estados disponibles del autor de E1.
62
- .estadoszip 51987654321 ZIP de un contacto por su número conocido.
63
- .estadoszip 123456789@lid ZIP por LID recibido. No se inventan números para LID.
64
- .reaccionestado E1 🔥 Reacción manual. No activa la reacción automática.
65
- .estadoemoji random ❤️ 🔥 Cambia la lista de emojis sin cambiar el interruptor on/off.
66
-
67
- Solo se aceptan contactos guardados que consten en la sincronización de la cuenta
68
- (nombre de agenda o marca isMyContact/isSaved). Un pushName, un notify o pertenecer
69
- a un grupo NO prueba que alguien esté guardado. Si todavía no se sincronizaron
70
- los contactos, la lista puede estar vacía. Los mapeos PN/LID usan datos reales.
71
-
72
- Con guardarestados se guardan los archivos localmente y se envían al privado en
73
- que el propietario activó el ajuste. Con statuszip se agrupan las recepciones
74
- consecutivas de cada contacto durante unos 3 segundos, con un máximo de 10 segundos
75
- por ráfaga; el ZIP incluye los estados recibidos disponibles de ese contacto.
76
- Los ZIP pueden contener imágenes, videos, audios y texto, más informacion.json.
77
- Los estados de texto se entregan como texto/TXT: NO se promete una imagen del
78
- estado. Sus colores ARGB y fuente se conservan en informacion.json cuando llegan.
79
-
80
- Cada estado muestra la reacción ENVIADA POR EL BOT o ninguna registrada. No se
81
- promete conocer las reacciones de otros usuarios que WhatsApp no entregue.
82
- La lista aleatoria admite hasta 50 emojis separados por espacios. Se utiliza
83
- UN emoji por estado: no se envía una ráfaga de reacciones al mismo estado.
84
-
85
- VIGENCIA Y ALMACENAMIENTO
86
- received significa recibido y dentro de la ventana calculada de 24 horas, sin
87
- borrado notificado. NO es una consulta remota que certifique que sigue publicado.
88
- deleted significa que llegó un aviso de eliminación; expired indica caducidad.
89
- Se reciben revocaciones y eventos messages.delete/messages.update.
90
- La caché guarda hasta 500 entradas y conserva metadatos retirados hasta 48 horas.
91
- Las copias locales ya archivadas permanecen aunque el estado original caduque
92
- o sea eliminado: son archivos del servidor, NO estados todavía publicados.
93
- .estados limpiar vacía la caché, NO borra las copias locales guardadas.
94
-
95
- Medios normales: downloads/normal.
96
- Estados guardados: downloads/status/<identificador de cuenta>.
97
- Metadatos de estados: data/status/<identificador de cuenta>.json.
98
- Permisos locales restringidos: directorios 0700 y archivos 0600.
99
- Límite por medio: 32 MiB. Cuota de archivo: 512 MiB por directorio/cuenta de estados.
100
- ZIP: hasta 64 MiB de archivos y 100 elementos; el manifiesto indica omisiones.
101
- Colas acotadas: hasta 20 descargas/guardados pendientes. Debes limpiar tus copias
102
- cuando ya no las necesites. No se elimina ni cambia el estado original del contacto.
103
-
104
- MÉTODOS NUEVOS EN KAGE
105
- La integración se instala al crear el socket en lib/Socket/index.js.
106
- conn.getViewOnceContent(raw)
107
- conn.normalizeViewOnceMessage(raw)
108
- conn.downloadViewOnceMessage(raw, opciones)
109
- conn.resendViewOnceMessage(raw, opciones)
110
- conn.handleAutoViewOnce(raw, settings, opciones)
111
- conn.enableMediaAutomation(settings) -> función para detener listeners
112
- conn.saveReceivedStatus(entry, opciones)
113
- conn.exportReceivedStatuses(author, opciones)
114
- Los helpers también están disponibles en el export público de la librería.
115
-
116
- En una aplicación independiente puedes crear el socket con:
117
- const settings = { autoViewOnceChats: ['51987654321@s.whatsapp.net'] }
118
- const sock = makeWASocket({ auth, kageTools: {
119
- mediaAutomation: true, mediaSettings: settings, contactsOnly: true,
120
- statusTracking: true, statusSettings: { statusSave: false, statusReaction: false }
121
- } })
122
- No actives otro listener independiente en Chiaki: handler.js ya integra estos helpers
123
- con su configuración y evita un segundo procesamiento de los mismos eventos.
124
- Los listeners auxiliares se retiran al cerrar la conexión.
125
-
126
- WAPROTO
127
- El esquema aportado ya incluye los tres envoltorios y los campos viewOnce.
128
- No se inventaron números de campo ni métodos dentro de protobuf. La normalización
129
- es una utilidad local, no un cambio del protocolo de WhatsApp. Se regeneraron
130
- WAProto/index.js e index.d.ts desde WAProto.proto y las declaraciones públicas.
131
- Se mantienen los campos y la compatibilidad binaria del esquema aportado.
132
-
133
- PRUEBAS Y LÍMITES
134
- Kage: npm run check — análisis de sintaxis y pruebas unitarias/de integración local.
135
- Chiaki: npm run check y npm test.
136
- Los informes de esta revisión están dentro de validation/ y maintenance/.
137
- Las pruebas usan datos sintéticos, streams de descarga simulados y sockets de prueba.
138
- NO se ha conectado esta revisión a una cuenta real ni se ha comprobado la entrega
139
- por los servidores de WhatsApp. No se puede garantizar que funcione "sí o sí"
140
- con cualquier versión, cuenta o cambio futuro del servicio.
141
- No recupera archivos consumidos, borrados, caducados o claves que WhatsApp no entregue.
142
- El servidor de WhatsApp puede rechazar descargas, envíos o reacciones.