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.
- package/WAProto/WAProto.proto +0 -2
- package/lib/Socket/index.js +1 -4
- package/lib/Utils/automation-tools.js +4 -32
- package/lib/Utils/consented-media.js +25 -11
- package/lib/Utils/messages.js +1 -1
- package/lib/Utils/status-tools.js +1 -8
- package/lib/Utils/sync-action-utils.js +0 -1
- package/lib/index.d.ts +0 -12
- package/lib/index.js +0 -4
- package/package.json +2 -3
- package/test/archive-repair.test.cjs +31 -0
- package/test/revision.test.cjs +0 -1
- package/AUTOMATIZACION.txt +0 -142
- package/lib/Utils/status-archive.js +0 -175
- package/lib/Utils/status-contacts.js +0 -57
- package/lib/Utils/view-once.js +0 -48
- package/maintenance/automatizacion-check.txt +0 -1248
- package/maintenance/automatizacion-protobuf.txt +0 -10
- package/test/automation-v2.test.cjs +0 -169
package/WAProto/WAProto.proto
CHANGED
|
@@ -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;
|
package/lib/Socket/index.js
CHANGED
|
@@ -8,9 +8,6 @@ const makeWASocket = (config = {}) => {
|
|
|
8
8
|
...Defaults_1.DEFAULT_CONNECTION_CONFIG,
|
|
9
9
|
...config
|
|
10
10
|
});
|
|
11
|
-
|
|
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 || '',
|
|
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(() =>
|
|
98
|
+
const job = state.tail.then(() => saveNormalMedia(conn, raw, options));
|
|
99
99
|
state.tail = job.catch(() => {}).finally(() => { state.pending--; });
|
|
100
|
-
return job
|
|
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
|
|
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 (
|
|
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
|
|
74
|
+
return task;
|
|
62
75
|
}
|
|
76
|
+
exports.getViewOnceContent = getViewOnceContent;
|
|
63
77
|
exports.prepareConsentedViewOnce = prepareConsentedViewOnce;
|
|
64
78
|
exports.downloadConsentedViewOnce = downloadConsentedViewOnce;
|
|
65
79
|
exports.saveConsentedViewOnce = saveConsentedViewOnce;
|
package/lib/Utils/messages.js
CHANGED
|
@@ -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 <
|
|
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 =>
|
|
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()
|
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.
|
|
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
|
+
});
|
package/test/revision.test.cjs
CHANGED
|
@@ -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);
|
package/AUTOMATIZACION.txt
DELETED
|
@@ -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.
|