import express, { Router, Request, Response, NextFunction } from 'express'; import * as nucleoClient from '../nucleoClient'; // Assuming OPEN_WA_URL is set in the environment. // For local development, dotenv would typically be used in the main app entry point (e.g., index.ts) // require('dotenv').config(); // Potentially, but better if handled by the main application loader const router = Router(); // Retrieve OpenWA URL from environment variables // This is done once when the module is loaded. const openWaUrl = process.env.OPEN_WA_URL; // Middleware to check if openWaUrl is configured // This runs for every request to this router router.use((req: Request, res: Response, next: NextFunction) => { if (!openWaUrl) { console.error('[routes/nucleoActions] Service OPEN_WA_URL not configured'); return res.status(500).json({ error: 'Service OPEN_WA_URL not configured. Please set the environment variable.' }); } // Pass openWaUrl to subsequent handlers via res.locals if preferred, // or they can access the `openWaUrl` constant from the module scope. // For simplicity, handlers will use the module-scoped `openWaUrl`. next(); }); // Route implementations // POST /send-text router.post('/send-text', async (req: Request, res: Response) => { try { const { to, content } = req.body; if (!to || !content) { return res.status(400).json({ error: 'Missing "to" or "content" in request body' }); } // openWaUrl is checked by middleware and available in module scope const result = await nucleoClient.sendTextMessage(openWaUrl!, to, content); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /send-text:', error.message); // Check if the error message is already a JSON string from nucleoClient's error handling try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { // If not, send the plain error message res.status(500).json({ error: error.message || 'Failed to send text message' }); } } }); // POST /send-image router.post('/send-image', async (req: Request, res: Response) => { try { const { to, path, caption } = req.body; if (!to || !path) { return res.status(400).json({ error: 'Missing "to" or "path" in request body' }); } const result = await nucleoClient.sendImageMessage(openWaUrl!, to, path, caption); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /send-image:', error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to send image message' }); } } }); // POST /send-file router.post('/send-file', async (req: Request, res: Response) => { try { const { to, path, filename, caption } = req.body; if (!to || !path) { return res.status(400).json({ error: 'Missing "to" or "path" in request body' }); } const result = await nucleoClient.sendFileMessage(openWaUrl!, to, path, filename, caption); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /send-file:', error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to send file message' }); } } }); // GET /chats/:chatId router.get('/chats/:chatId', async (req: Request, res: Response) => { try { const { chatId } = req.params; if (!chatId) { return res.status(400).json({ error: 'Missing "chatId" in request params' }); } const result = await nucleoClient.getChatById(openWaUrl!, chatId); res.json(result); } catch (error: any) { console.error(`[routes/nucleoActions] Error in /chats/${req.params.chatId}:`, error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to retrieve chat' }); } } }); // POST /groups router.post('/groups', async (req: Request, res: Response) => { try { const { groupName, contactIds } = req.body; if (!groupName || !contactIds || !Array.isArray(contactIds) || contactIds.length === 0) { return res.status(400).json({ error: 'Missing "groupName" or "contactIds" (must be a non-empty array) in request body' }); } const result = await nucleoClient.createGroup(openWaUrl!, groupName, contactIds); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /groups:', error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to create group' }); } } }); // GET /contacts/:contactId router.get('/contacts/:contactId', async (req: Request, res: Response) => { try { const { contactId } = req.params; if (!contactId) { return res.status(400).json({ error: 'Missing "contactId" in request params' }); } const result = await nucleoClient.getContact(openWaUrl!, contactId); res.json(result); } catch (error: any) { console.error(`[routes/nucleoActions] Error in /contacts/${req.params.contactId}:`, error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to retrieve contact' }); } } }); // GET /blocklist router.get('/blocklist', async (req: Request, res: Response) => { try { const result = await nucleoClient.getBlocklist(openWaUrl!); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /blocklist:', error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to retrieve blocklist' }); } } }); // POST /blocklist/block router.post('/blocklist/block', async (req: Request, res: Response) => { try { const { contactId } = req.body; if (!contactId) { return res.status(400).json({ error: 'Missing "contactId" in request body' }); } const result = await nucleoClient.blockContact(openWaUrl!, contactId); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /blocklist/block:', error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to block contact' }); } } }); // POST /blocklist/unblock router.post('/blocklist/unblock', async (req: Request, res: Response) => { try { const { contactId } = req.body; if (!contactId) { return res.status(400).json({ error: 'Missing "contactId" in request body' }); } const result = await nucleoClient.unblockContact(openWaUrl!, contactId); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /blocklist/unblock:', error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to unblock contact' }); } } }); // GET /chats router.get('/chats', async (req: Request, res: Response) => { try { const result = await nucleoClient.getAllChats(openWaUrl!); res.json(result); } catch (error: any) { console.error('[routes/nucleoActions] Error in /chats:', error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to retrieve all chats' }); } } }); // GET /chats/:chatId/messages router.get('/chats/:chatId/messages', async (req: Request, res: Response) => { try { const { chatId } = req.params; if (!chatId) { return res.status(400).json({ error: 'Missing "chatId" in request params' }); } const { limit, includeMe, includeNotifications } = req.query; let numLimit: number | undefined = undefined; if (limit) { numLimit = parseInt(limit as string, 10); if (isNaN(numLimit)) { return res.status(400).json({ error: 'Invalid "limit" query parameter, must be a number.' }); } } const boolIncludeMe: boolean | undefined = includeMe ? (includeMe as string).toLowerCase() === 'true' : undefined; const boolIncludeNotifications: boolean | undefined = includeNotifications ? (includeNotifications as string).toLowerCase() === 'true' : undefined; const result = await nucleoClient.getChatMessages( openWaUrl!, chatId, numLimit, boolIncludeMe, boolIncludeNotifications ); res.json(result); } catch (error: any) { console.error(`[routes/nucleoActions] Error in /chats/${req.params.chatId}/messages:`, error.message); try { const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{'))); return res.status(parsedError.status || 500).json({ error: parsedError }); } catch (e) { res.status(500).json({ error: error.message || 'Failed to retrieve chat messages' }); } } }); export default router;