@@ -35,6 +35,9 @@ const tempDir = path.join(os.tmpdir(), 'silva-cache');
3535const port = process . env . PORT || 25680 ;
3636const pluginsDir = path . join ( __dirname , 'plugins' ) ;
3737
38+ // ✅ Message Cache for Anti-Delete
39+ const messageCache = new Map ( ) ;
40+
3841// ✅ Message Logger Setup
3942const logDir = path . join ( __dirname , 'logs' ) ;
4043if ( ! fs . existsSync ( logDir ) ) fs . mkdirSync ( logDir ) ;
@@ -64,11 +67,20 @@ const globalContextInfo = {
6467 isForwarded : true ,
6568 forwardedNewsletterMessageInfo : {
6669 newsletterJid : '120363200367779016@newsletter' ,
67- newsletterName : '◢◤ Silva Tech Inc ◢◤' ,
70+ newsletterName : '◢◤ Silva Tech Nexus ◢◤' ,
6871 serverMessageId : 144
6972 }
7073} ;
7174
75+ // ✅ Safe Get User JID
76+ function safeGetUserJid ( sock ) {
77+ try {
78+ return sock . user ?. id || null ;
79+ } catch {
80+ return null ;
81+ }
82+ }
83+
7284// ✅ Ensure Temp Directory Exists
7385if ( ! fs . existsSync ( tempDir ) ) fs . mkdirSync ( tempDir , { recursive : true } ) ;
7486setInterval ( ( ) => {
@@ -334,7 +346,69 @@ async function connectToWhatsApp() {
334346
335347 sock . ev . on ( 'creds.update' , saveCreds ) ;
336348
337- // Anti-delete handler
349+ // ✅ Cache messages for anti-delete
350+ sock . ev . on ( 'messages.upsert' , ( { messages } ) => {
351+ if ( ! Array . isArray ( messages ) ) return ;
352+
353+ for ( const m of messages ) {
354+ if ( ! m . message || ! m . key . id ) continue ;
355+
356+ const cacheKey = `${ m . key . remoteJid } -${ m . key . id } ` ;
357+ messageCache . set ( cacheKey , {
358+ message : m . message ,
359+ timestamp : Date . now ( )
360+ } ) ;
361+ }
362+
363+ // Clean old cache entries (older than 1 hour)
364+ const now = Date . now ( ) ;
365+ for ( const [ key , value ] of messageCache . entries ( ) ) {
366+ if ( now - value . timestamp > 60 * 60 * 1000 ) { // 1 hour
367+ messageCache . delete ( key ) ;
368+ }
369+ }
370+ } ) ;
371+
372+ // ✅ Anti-delete handler (messages.update)
373+ sock . ev . on ( "messages.update" , async ( updates ) => {
374+ for ( const { key, update } of updates ) {
375+ if ( key . remoteJid === "status@broadcast" ) continue ;
376+ if ( update ?. message === null && ! key . fromMe ) {
377+ const cacheKey = `${ key . remoteJid } -${ key . id } ` ;
378+ const original = messageCache . get ( cacheKey ) ;
379+ const owner = safeGetUserJid ( sock ) ;
380+
381+ if ( ! original ?. message || ! owner ) continue ;
382+
383+ sock . sendMessage ( owner , {
384+ text : `🚨 *Anti-Delete* — Message recovered from ${ key . participant || key . remoteJid } ` ,
385+ contextInfo : globalContextInfo
386+ } ) . catch ( ( ) => { } ) ;
387+
388+ const msgObj = original . message ;
389+ const mType = Object . keys ( msgObj ) [ 0 ] ;
390+
391+ try {
392+ if ( [ "conversation" , "extendedTextMessage" ] . includes ( mType ) ) {
393+ const text = msgObj . conversation || msgObj . extendedTextMessage ?. text ;
394+ await sock . sendMessage ( owner , { text, contextInfo : globalContextInfo } ) ;
395+ } else if ( [ "imageMessage" , "videoMessage" , "audioMessage" , "stickerMessage" , "documentMessage" ] . includes ( mType ) ) {
396+ const stream = await downloadContentFromMessage ( msgObj [ mType ] , mType . replace ( "Message" , "" ) ) ;
397+ let buffer = Buffer . from ( [ ] ) ;
398+ for await ( const chunk of stream ) buffer = Buffer . concat ( [ buffer , chunk ] ) ;
399+ const field = mType . replace ( "Message" , "" ) ;
400+ const payload = { [ field ] : buffer , contextInfo : globalContextInfo } ;
401+ if ( msgObj [ mType ] ?. caption ) payload . caption = msgObj [ mType ] . caption ;
402+ await sock . sendMessage ( owner , payload ) ;
403+ }
404+ } catch ( err ) {
405+ logMessage ( "DEBUG" , `Recovery failed: ${ err . message } ` ) ;
406+ }
407+ }
408+ }
409+ } ) ;
410+
411+ // Anti-delete handler (messages.delete - existing)
338412 sock . ev . on ( 'messages.delete' , async ( item ) => {
339413 try {
340414 logMessage ( 'DEBUG' , 'messages.delete triggered' ) ;
0 commit comments