Files
nanoclaw/src/db.ts
gavrielc 22bd3d7c58 Store and display sender's WhatsApp name
Use pushName from baileys to get the sender's display name instead
of just the phone number. Falls back to phone number if no name.

Includes migration to add sender_name column to existing databases.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 19:32:18 +02:00

92 lines
3.0 KiB
TypeScript

import Database from 'better-sqlite3';
import fs from 'fs';
import path from 'path';
import { proto } from '@whiskeysockets/baileys';
import { NewMessage } from './types.js';
import { STORE_DIR } from './config.js';
let db: Database.Database;
export function initDatabase(): void {
const dbPath = path.join(STORE_DIR, 'messages.db');
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
db = new Database(dbPath);
db.exec(`
CREATE TABLE IF NOT EXISTS chats (
jid TEXT PRIMARY KEY,
name TEXT,
last_message_time TEXT
);
CREATE TABLE IF NOT EXISTS messages (
id TEXT,
chat_jid TEXT,
sender TEXT,
sender_name TEXT,
content TEXT,
timestamp TEXT,
is_from_me INTEGER,
PRIMARY KEY (id, chat_jid),
FOREIGN KEY (chat_jid) REFERENCES chats(jid)
);
CREATE INDEX IF NOT EXISTS idx_timestamp ON messages(timestamp);
`);
// Add sender_name column if it doesn't exist (migration for existing DBs)
try {
db.exec(`ALTER TABLE messages ADD COLUMN sender_name TEXT`);
} catch { /* column already exists */ }
}
export function storeMessage(msg: proto.IWebMessageInfo, chatJid: string, isFromMe: boolean, pushName?: string): void {
if (!msg.key) return;
const content =
msg.message?.conversation ||
msg.message?.extendedTextMessage?.text ||
msg.message?.imageMessage?.caption ||
msg.message?.videoMessage?.caption ||
'';
const timestamp = new Date(Number(msg.messageTimestamp) * 1000).toISOString();
const sender = msg.key.participant || msg.key.remoteJid || '';
const senderName = pushName || sender.split('@')[0];
const msgId = msg.key.id || '';
db.prepare(`INSERT OR REPLACE INTO chats (jid, name, last_message_time) VALUES (?, ?, ?)`)
.run(chatJid, chatJid, timestamp);
db.prepare(`INSERT OR REPLACE INTO messages (id, chat_jid, sender, sender_name, content, timestamp, is_from_me) VALUES (?, ?, ?, ?, ?, ?, ?)`)
.run(msgId, chatJid, sender, senderName, content, timestamp, isFromMe ? 1 : 0);
}
export function getNewMessages(jids: string[], lastTimestamp: string): { messages: NewMessage[]; newTimestamp: string } {
if (jids.length === 0) return { messages: [], newTimestamp: lastTimestamp };
const placeholders = jids.map(() => '?').join(',');
const sql = `
SELECT id, chat_jid, sender, sender_name, content, timestamp
FROM messages
WHERE timestamp > ? AND chat_jid IN (${placeholders})
ORDER BY timestamp
`;
const rows = db.prepare(sql).all(lastTimestamp, ...jids) as NewMessage[];
let newTimestamp = lastTimestamp;
for (const row of rows) {
if (row.timestamp > newTimestamp) newTimestamp = row.timestamp;
}
return { messages: rows, newTimestamp };
}
export function getMessagesSince(chatJid: string, sinceTimestamp: string): NewMessage[] {
const sql = `
SELECT id, chat_jid, sender, sender_name, content, timestamp
FROM messages
WHERE chat_jid = ? AND timestamp > ?
ORDER BY timestamp
`;
return db.prepare(sql).all(chatJid, sinceTimestamp) as NewMessage[];
}