@vielhuber/wahelper 1.6.5 → 1.6.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielhuber/wahelper",
3
- "version": "1.6.5",
3
+ "version": "1.6.7",
4
4
  "description": "Lightweight whatsapp integration layer.",
5
5
  "main": "wahelper.js",
6
6
  "files": [
@@ -508,6 +508,35 @@ export default class wahelperDaemon {
508
508
  }
509
509
  }
510
510
 
511
+ async markChatsRead(updates) {
512
+ // baileys fires chats.update with `unreadCount: 0` when an EXISTING chat
513
+ // is opened on the phone. unlike messages.update (status=4 read receipt),
514
+ // this also covers GROUPS, which usually ship no read receipts — without
515
+ // it their incoming messages would stay `read = 0` forever even after the
516
+ // user has clearly seen them (e.g. reacted with an emoji).
517
+ if (!Array.isArray(updates) || updates.length === 0) {
518
+ return;
519
+ }
520
+ let chats = updates.filter(c => c?.unreadCount === 0);
521
+ if (chats.length === 0) {
522
+ return;
523
+ }
524
+ while (this.dbLock) {
525
+ await new Promise(resolve => setTimeout(resolve, 100));
526
+ }
527
+ this.dbLock = true;
528
+ try {
529
+ if (this.dbIsOpen === false) {
530
+ this.initDatabase();
531
+ }
532
+ this.applyReadFlags([], chats);
533
+ } catch (error) {
534
+ this.log('⛔ markChatsRead failed: ' + error.message);
535
+ } finally {
536
+ this.dbLock = false;
537
+ }
538
+ }
539
+
511
540
  async sendMessageToUser(number = null, message = null, attachments = null) {
512
541
  if (!this.connected || !this.sock) {
513
542
  throw new Error('not_connected');
@@ -624,6 +653,14 @@ export default class wahelperDaemon {
624
653
  }
625
654
  });
626
655
 
656
+ this.sock.ev.on('chats.update', async updates => {
657
+ try {
658
+ await this.markChatsRead(updates);
659
+ } catch (error) {
660
+ this.log('⛔ chats.update handler failed: ' + error.message);
661
+ }
662
+ });
663
+
627
664
  this.sock.ev.on('creds.update', saveCreds);
628
665
 
629
666
  this.sock.ev.on('connection.update', async update => {
package/wahelper.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env -S NODE_NO_WARNINGS=1 node
2
2
 
3
3
  import http from 'http';
4
+ import os from 'os';
5
+ import path from 'path';
4
6
  import { fileURLToPath } from 'url';
5
7
  import { dirname } from 'path';
6
8
  import fs from 'fs';
@@ -206,22 +208,49 @@ export default class wahelper {
206
208
  async viewMessage(id = null) {
207
209
  // lookup directly from database — no connection to daemon needed
208
210
  try {
209
- let message =
211
+ let row =
210
212
  this.db
211
213
  .prepare(
212
214
  `
213
- SELECT id, \`from\`, \`to\`, content, media_filename, timestamp, \`read\`
214
- FROM messages
215
- WHERE id = ?
216
- LIMIT 1
217
- `
215
+ SELECT id, \`from\`, \`to\`, content, media_data, media_filename, timestamp, \`read\`
216
+ FROM messages
217
+ WHERE id = ?
218
+ LIMIT 1
219
+ `
218
220
  )
219
221
  .get(id) || null;
220
- if (message === null) {
222
+ if (row === null) {
221
223
  console.log('Message not found: ' + id);
222
224
  this.write({ success: false, message: 'message_not_found', data: null }, true);
223
225
  return { content: [{ type: 'text', text: 'Message not found: ' + id }], structuredContent: null };
224
226
  }
227
+ // media: write base64 payload to disk and return path — mirrors
228
+ // mailhelper.view_mail so downstream tools (pdfreader, excel, …)
229
+ // can read attachments by file path without a separate decode
230
+ let mediaPath = null;
231
+ if (row.media_data && row.media_filename) {
232
+ let outBase = path.join(os.tmpdir(), 'wahelper-output');
233
+ let slot = crypto
234
+ .createHash('md5')
235
+ .update(this.formatNumber(this.args.device) + '|' + row.id)
236
+ .digest('hex')
237
+ .slice(0, 16);
238
+ let outDir = path.join(outBase, slot);
239
+ fs.mkdirSync(outDir, { recursive: true });
240
+ let safeName = String(row.media_filename).replace(/[^A-Za-z0-9._-]+/g, '_') || 'attachment';
241
+ mediaPath = path.join(outDir, safeName);
242
+ fs.writeFileSync(mediaPath, Buffer.from(row.media_data, 'base64'));
243
+ }
244
+ let message = {
245
+ id: row.id,
246
+ from: row.from,
247
+ to: row.to,
248
+ content: row.content,
249
+ media_filename: row.media_filename,
250
+ media_path: mediaPath,
251
+ timestamp: row.timestamp,
252
+ read: row.read
253
+ };
225
254
  console.log('Fetched message ' + id + ' from database.');
226
255
  this.write({ success: true, message: 'message_fetched', data: message }, true);
227
256
  return {