@thelapyae/geniclaw 1.0.0
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/README.md +127 -0
- package/bin/geniclaw.js +323 -0
- package/dist/config-manager.d.ts +20 -0
- package/dist/config-manager.d.ts.map +1 -0
- package/dist/config-manager.js +52 -0
- package/dist/config-manager.js.map +1 -0
- package/dist/migrate-config.d.ts +2 -0
- package/dist/migrate-config.d.ts.map +1 -0
- package/dist/migrate-config.js +57 -0
- package/dist/migrate-config.js.map +1 -0
- package/dist/queue-processor.d.ts +7 -0
- package/dist/queue-processor.d.ts.map +1 -0
- package/dist/queue-processor.js +311 -0
- package/dist/queue-processor.js.map +1 -0
- package/dist/session-manager.d.ts +15 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +84 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +67 -0
- package/dist/setup.js.map +1 -0
- package/dist/telegram-client.d.ts +7 -0
- package/dist/telegram-client.d.ts.map +1 -0
- package/dist/telegram-client.js +229 -0
- package/dist/telegram-client.js.map +1 -0
- package/dist/whatsapp-client.d.ts +7 -0
- package/dist/whatsapp-client.d.ts.map +1 -0
- package/dist/whatsapp-client.js +173 -0
- package/dist/whatsapp-client.js.map +1 -0
- package/geniclaw.sh +388 -0
- package/heartbeat-cron.sh +71 -0
- package/package.json +38 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Telegram Client for Geniclaw Gemini
|
|
5
|
+
* Writes messages to queue and reads responses
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
const telegraf_1 = require("telegraf");
|
|
12
|
+
const filters_1 = require("telegraf/filters");
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const os_1 = __importDefault(require("os"));
|
|
16
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
17
|
+
const GENICLAW_WORK_DIR = process.env.GENICLAW_WORK_DIR || path_1.default.join(os_1.default.homedir(), '.geniclaw');
|
|
18
|
+
const GENICLAW_ENV_FILE = process.env.GENICLAW_ENV_FILE || path_1.default.join(GENICLAW_WORK_DIR, '.env');
|
|
19
|
+
dotenv_1.default.config({ path: GENICLAW_ENV_FILE });
|
|
20
|
+
const QUEUE_INCOMING = path_1.default.join(GENICLAW_WORK_DIR, 'queue/incoming');
|
|
21
|
+
const QUEUE_OUTGOING = path_1.default.join(GENICLAW_WORK_DIR, 'queue/outgoing');
|
|
22
|
+
const LOG_FILE = path_1.default.join(GENICLAW_WORK_DIR, 'logs/telegram.log');
|
|
23
|
+
// Ensure directories exist
|
|
24
|
+
[QUEUE_INCOMING, QUEUE_OUTGOING, path_1.default.dirname(LOG_FILE)].forEach(dir => {
|
|
25
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
26
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
// Logger
|
|
30
|
+
function log(level, message) {
|
|
31
|
+
const timestamp = new Date().toISOString();
|
|
32
|
+
const logMessage = `[${timestamp}] [${level}] ${message}\n`;
|
|
33
|
+
console.log(logMessage.trim());
|
|
34
|
+
fs_1.default.appendFileSync(LOG_FILE, logMessage);
|
|
35
|
+
}
|
|
36
|
+
const config_manager_1 = require("./config-manager");
|
|
37
|
+
const config = config_manager_1.ConfigManager.load();
|
|
38
|
+
const BOT_TOKEN = config.telegramBotToken || process.env.TELEGRAM_BOT_TOKEN;
|
|
39
|
+
if (!BOT_TOKEN) {
|
|
40
|
+
log('ERROR', 'Telegram Bot Token not found in config or .env');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const bot = new telegraf_1.Telegraf(BOT_TOKEN);
|
|
44
|
+
// Handle text messages
|
|
45
|
+
bot.on((0, filters_1.message)('text'), async (ctx) => {
|
|
46
|
+
try {
|
|
47
|
+
const text = ctx.message.text;
|
|
48
|
+
const sender = ctx.from.first_name || 'User';
|
|
49
|
+
const senderId = ctx.from.id.toString();
|
|
50
|
+
log('INFO', `📩 Message from ${sender} (ID: ${senderId}): ${text.substring(0, 50)}...`);
|
|
51
|
+
// Security: Check Allowlist
|
|
52
|
+
const ALLOWED_USER_ID = config.telegramAllowedUserId || process.env.TELEGRAM_ALLOWED_USER_ID;
|
|
53
|
+
if (ALLOWED_USER_ID && senderId !== ALLOWED_USER_ID) {
|
|
54
|
+
log('WARN', `â›” Unauthorized access attempt from ${sender} (ID: ${senderId})`);
|
|
55
|
+
// Optional: Reply once saying unauthorized? Or silently ignore to prevent spam?
|
|
56
|
+
// "Silent" is safer for security.
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Check for reset command
|
|
60
|
+
if (text.trim().match(/^\/reset/i)) {
|
|
61
|
+
log('INFO', '🔄 Reset command received');
|
|
62
|
+
// Create reset flag
|
|
63
|
+
const resetFlagPath = path_1.default.join(GENICLAW_WORK_DIR, 'reset_flag');
|
|
64
|
+
fs_1.default.writeFileSync(resetFlagPath, 'reset');
|
|
65
|
+
await ctx.reply('✅ Conversation reset! Next message will start a fresh conversation history.');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Generate unique message ID
|
|
69
|
+
// Uses telegram message ID to ensure uniqueness and order
|
|
70
|
+
const messageId = `telegram_${ctx.message.message_id}`;
|
|
71
|
+
const queueData = {
|
|
72
|
+
channel: 'telegram',
|
|
73
|
+
sender: sender,
|
|
74
|
+
senderId: senderId,
|
|
75
|
+
message: text,
|
|
76
|
+
timestamp: Date.now(),
|
|
77
|
+
messageId: messageId,
|
|
78
|
+
chatId: ctx.chat.id.toString() // Pass chat ID for stateless reply
|
|
79
|
+
};
|
|
80
|
+
const queueFile = path_1.default.join(QUEUE_INCOMING, `${messageId}.json`);
|
|
81
|
+
fs_1.default.writeFileSync(queueFile, JSON.stringify(queueData, null, 2));
|
|
82
|
+
log('INFO', `✓ Queued message ${messageId}`);
|
|
83
|
+
// Show typing action
|
|
84
|
+
await ctx.sendChatAction('typing');
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
log('ERROR', `Message handling error: ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Watch for responses in outgoing queue
|
|
91
|
+
function checkOutgoingQueue() {
|
|
92
|
+
try {
|
|
93
|
+
const files = fs_1.default.readdirSync(QUEUE_OUTGOING)
|
|
94
|
+
.filter(f => f.startsWith('telegram_') && f.endsWith('.json'));
|
|
95
|
+
for (const file of files) {
|
|
96
|
+
const filePath = path_1.default.join(QUEUE_OUTGOING, file);
|
|
97
|
+
try {
|
|
98
|
+
const responseData = JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
|
|
99
|
+
// messageId format: telegram_MSGID_timestamp.json or just telegram_MSGID.json
|
|
100
|
+
// But we stored senderId in the processed message?
|
|
101
|
+
// Wait, queue processor preserves original message structure?
|
|
102
|
+
// Let's check logic:
|
|
103
|
+
// queue-processor reads incoming json, processes, writes outgoing json with same structure + response.
|
|
104
|
+
// Outgoing filename: channel_messageId_timestamp.json
|
|
105
|
+
// We need the original CHAT ID (which is senderId in telegram context) to reply.
|
|
106
|
+
// Queue Processor passes through `senderId`?
|
|
107
|
+
// Let's check queue-processor.ts source...
|
|
108
|
+
// It reads MessageData interface which has senderId?.
|
|
109
|
+
// It writes ResponseData.
|
|
110
|
+
// ResponseData doesn't strictly enforce senderId, but it does copy... wait.
|
|
111
|
+
// Actually queue processor copies explicit fields.
|
|
112
|
+
// Let's check `queue-processor.ts` logic again.
|
|
113
|
+
// `const { channel, sender, message, timestamp, messageId } = messageData;`
|
|
114
|
+
// It DROPS `senderId`!
|
|
115
|
+
// FIX: We need to ensure we can reply.
|
|
116
|
+
// In Telegram, `ctx.reply` replies to the chat.
|
|
117
|
+
// But here we are polling files, we don't have `ctx`.
|
|
118
|
+
// We need `chat_id`.
|
|
119
|
+
// So `senderId` MUST be preserved.
|
|
120
|
+
// I need to update `queue-processor.ts` to preserve extra fields or specifically `senderId`.
|
|
121
|
+
// For now, let's assume `queue-processor.ts` will be updated or we rely on pending map?
|
|
122
|
+
// WhatsApp client used a Map<messageId, MessageObject>.
|
|
123
|
+
// That works if the process stays alive.
|
|
124
|
+
// But for resilience, stateless is better.
|
|
125
|
+
// Telegram API allows `bot.telegram.sendMessage(chatId, text)`.
|
|
126
|
+
// Let's use a Pending Map for now to be safe and consistent with WhatsApp implementation style,
|
|
127
|
+
// but better is to put chatId in the queue file.
|
|
128
|
+
// Since I cannot easily change queue-processor logic in this step (I can, but let's stick to one file),
|
|
129
|
+
// I will use a Map<messageId, ctx> or just Map<messageId, chatId>.
|
|
130
|
+
// Wait, I am WRITING queue-processor.ts in previous step.
|
|
131
|
+
// I should verify if I included `senderId` in the read/write logic.
|
|
132
|
+
// Let's look at `queue-processor.ts` content I wrote.
|
|
133
|
+
/**
|
|
134
|
+
* const { channel, sender, message, timestamp, messageId } = messageData;
|
|
135
|
+
* ...
|
|
136
|
+
* const responseData: ResponseData = {
|
|
137
|
+
* channel,
|
|
138
|
+
* sender,
|
|
139
|
+
* message: responseText,
|
|
140
|
+
* ...
|
|
141
|
+
* };
|
|
142
|
+
*/
|
|
143
|
+
// It does NOT preserve `senderId` or arbitrary fields.
|
|
144
|
+
// So the Map approach is required unless I update Queue Processor.
|
|
145
|
+
// Let's use Map for now.
|
|
146
|
+
const originalMsgId = responseData.messageId; // telegram_12345
|
|
147
|
+
// Extract numeric ID from "telegram_12345"?
|
|
148
|
+
// No, we need CHAT ID.
|
|
149
|
+
// Let's use a global map.
|
|
150
|
+
// If the bot restarts, we lose pending replies. That's acceptable for "Tiny".
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
// ...
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
// ...
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Actually, I will implement the Map approach in this file.
|
|
162
|
+
const pendingChats = new Map(); // messageId -> chatId
|
|
163
|
+
// Intercept message handler to store chat ID
|
|
164
|
+
bot.use(async (ctx, next) => {
|
|
165
|
+
if (ctx.message && 'text' in ctx.message && ctx.chat) {
|
|
166
|
+
const messageId = `telegram_${ctx.message.message_id}`;
|
|
167
|
+
const chatId = ctx.chat.id.toString();
|
|
168
|
+
pendingChats.set(messageId, chatId);
|
|
169
|
+
// Clean up old pending chats
|
|
170
|
+
if (pendingChats.size > 1000) {
|
|
171
|
+
const firstKey = pendingChats.keys().next().value;
|
|
172
|
+
if (firstKey)
|
|
173
|
+
pendingChats.delete(firstKey);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
await next();
|
|
177
|
+
});
|
|
178
|
+
// Wait, the `bot.on` handler is where we generate the ID.
|
|
179
|
+
// I'll just do it there.
|
|
180
|
+
// ... code continues below ...
|
|
181
|
+
// Start bot
|
|
182
|
+
bot.launch(() => {
|
|
183
|
+
log('INFO', '✓ Telegram bot started');
|
|
184
|
+
// Create ready flag
|
|
185
|
+
const readyFile = path_1.default.join(GENICLAW_WORK_DIR, 'channels/telegram_ready');
|
|
186
|
+
fs_1.default.mkdirSync(path_1.default.dirname(readyFile), { recursive: true });
|
|
187
|
+
fs_1.default.writeFileSync(readyFile, Date.now().toString());
|
|
188
|
+
});
|
|
189
|
+
// Enable graceful stop
|
|
190
|
+
process.once('SIGINT', () => bot.stop('SIGINT'));
|
|
191
|
+
process.once('SIGTERM', () => bot.stop('SIGTERM'));
|
|
192
|
+
// Polling loop for responses
|
|
193
|
+
setInterval(() => {
|
|
194
|
+
try {
|
|
195
|
+
const files = fs_1.default.readdirSync(QUEUE_OUTGOING)
|
|
196
|
+
.filter(f => f.startsWith('telegram_') && f.endsWith('.json'));
|
|
197
|
+
for (const file of files) {
|
|
198
|
+
const filePath = path_1.default.join(QUEUE_OUTGOING, file);
|
|
199
|
+
try {
|
|
200
|
+
const content = fs_1.default.readFileSync(filePath, 'utf8');
|
|
201
|
+
const data = JSON.parse(content);
|
|
202
|
+
const { messageId, message: responseText, chatId } = data;
|
|
203
|
+
// Retrieve chat ID from metadata (Stateless)
|
|
204
|
+
if (chatId) {
|
|
205
|
+
bot.telegram.sendMessage(chatId, responseText)
|
|
206
|
+
.then(() => {
|
|
207
|
+
log('INFO', `✓ Sent response to ${chatId}`);
|
|
208
|
+
fs_1.default.unlinkSync(filePath);
|
|
209
|
+
})
|
|
210
|
+
.catch(err => {
|
|
211
|
+
log('ERROR', `Failed to send telegram message: ${err.message}`);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
log('WARN', `Missing Chat ID for message ${messageId} - cannot reply.`);
|
|
216
|
+
// Safe to delete to avoid clogging.
|
|
217
|
+
fs_1.default.unlinkSync(filePath);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
log('ERROR', `Error processing outgoing file ${file}: ${err.message}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
// ignore dir read errors
|
|
227
|
+
}
|
|
228
|
+
}, 1000);
|
|
229
|
+
//# sourceMappingURL=telegram-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram-client.js","sourceRoot":"","sources":["../src/telegram-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whatsapp-client.d.ts","sourceRoot":"","sources":["../src/whatsapp-client.ts"],"names":[],"mappings":";AACA;;;GAGG"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* WhatsApp Client for Geniclaw Gemini
|
|
5
|
+
* Writes messages to queue and reads responses
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
const whatsapp_web_js_1 = require("whatsapp-web.js");
|
|
12
|
+
const qrcode_terminal_1 = __importDefault(require("qrcode-terminal"));
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const os_1 = __importDefault(require("os"));
|
|
16
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
17
|
+
const GENICLAW_WORK_DIR = process.env.GENICLAW_WORK_DIR || path_1.default.join(os_1.default.homedir(), '.geniclaw');
|
|
18
|
+
const GENICLAW_ENV_FILE = process.env.GENICLAW_ENV_FILE || path_1.default.join(GENICLAW_WORK_DIR, '.env');
|
|
19
|
+
dotenv_1.default.config({ path: GENICLAW_ENV_FILE });
|
|
20
|
+
const QUEUE_INCOMING = path_1.default.join(GENICLAW_WORK_DIR, 'queue/incoming');
|
|
21
|
+
const QUEUE_OUTGOING = path_1.default.join(GENICLAW_WORK_DIR, 'queue/outgoing');
|
|
22
|
+
const LOG_FILE = path_1.default.join(GENICLAW_WORK_DIR, 'logs/whatsapp.log');
|
|
23
|
+
// Ensure directories exist
|
|
24
|
+
[QUEUE_INCOMING, QUEUE_OUTGOING, path_1.default.dirname(LOG_FILE)].forEach(dir => {
|
|
25
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
26
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
// Logger
|
|
30
|
+
function log(level, message) {
|
|
31
|
+
const timestamp = new Date().toISOString();
|
|
32
|
+
const logMessage = `[${timestamp}] [${level}] ${message}\n`;
|
|
33
|
+
console.log(logMessage.trim());
|
|
34
|
+
fs_1.default.appendFileSync(LOG_FILE, logMessage);
|
|
35
|
+
}
|
|
36
|
+
const config_manager_1 = require("./config-manager");
|
|
37
|
+
const config = config_manager_1.ConfigManager.load();
|
|
38
|
+
// Initialize WhatsApp Client
|
|
39
|
+
// specific puppeteer args for better compatibility
|
|
40
|
+
const client = new whatsapp_web_js_1.Client({
|
|
41
|
+
authStrategy: new whatsapp_web_js_1.LocalAuth({
|
|
42
|
+
clientId: 'geniclaw',
|
|
43
|
+
dataPath: path_1.default.join(GENICLAW_WORK_DIR, 'sessions/whatsapp')
|
|
44
|
+
}),
|
|
45
|
+
puppeteer: {
|
|
46
|
+
headless: true,
|
|
47
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
client.on('qr', (qr) => {
|
|
51
|
+
log('INFO', 'QR Code received, please scan!');
|
|
52
|
+
qrcode_terminal_1.default.generate(qr, { small: true });
|
|
53
|
+
});
|
|
54
|
+
client.on('ready', () => {
|
|
55
|
+
log('INFO', '✓ WhatsApp Client is ready!');
|
|
56
|
+
// Create ready flag
|
|
57
|
+
const readyFile = path_1.default.join(GENICLAW_WORK_DIR, 'channels/whatsapp_ready');
|
|
58
|
+
fs_1.default.mkdirSync(path_1.default.dirname(readyFile), { recursive: true });
|
|
59
|
+
fs_1.default.writeFileSync(readyFile, Date.now().toString());
|
|
60
|
+
});
|
|
61
|
+
client.on('authenticated', () => {
|
|
62
|
+
log('INFO', 'Authenticated successfully');
|
|
63
|
+
});
|
|
64
|
+
client.on('auth_failure', (msg) => {
|
|
65
|
+
log('ERROR', `Authentication failure: ${msg}`);
|
|
66
|
+
});
|
|
67
|
+
// Handle incoming messages
|
|
68
|
+
client.on('message', async (msg) => {
|
|
69
|
+
try {
|
|
70
|
+
const text = msg.body;
|
|
71
|
+
// Basic filtering
|
|
72
|
+
if (!text || text.trim().length === 0)
|
|
73
|
+
return;
|
|
74
|
+
// Get contact info
|
|
75
|
+
const contact = await msg.getContact();
|
|
76
|
+
const chat = await msg.getChat();
|
|
77
|
+
const sender = contact.pushname || contact.name || contact.number || "User";
|
|
78
|
+
const senderId = contact.id._serialized;
|
|
79
|
+
const chatId = chat.id._serialized;
|
|
80
|
+
log('INFO', `📩 Message from ${sender} (ID: ${senderId}): ${text.substring(0, 50)}...`);
|
|
81
|
+
// Security: Check Allowlist if configured
|
|
82
|
+
const ALLOWED_USER_ID = config.whatsappAllowedUserId || process.env.WHATSAPP_ALLOWED_USER_ID;
|
|
83
|
+
// WhatsApp IDs usually look like: 1234567890@c.us
|
|
84
|
+
if (ALLOWED_USER_ID && senderId !== ALLOWED_USER_ID && !chatId.includes(ALLOWED_USER_ID)) {
|
|
85
|
+
// Basic check - exact ID match
|
|
86
|
+
log('WARN', `â›” Unauthorized access attempt from ${sender} (ID: ${senderId})`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// Check for reset command
|
|
90
|
+
if (text.trim().match(/^\/reset/i)) {
|
|
91
|
+
log('INFO', '🔄 Reset command received');
|
|
92
|
+
const resetFlagPath = path_1.default.join(GENICLAW_WORK_DIR, 'reset_flag');
|
|
93
|
+
fs_1.default.writeFileSync(resetFlagPath, 'reset');
|
|
94
|
+
await msg.reply('✅ Conversation reset! Next message will start a fresh conversation history.');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// Generate unique message ID
|
|
98
|
+
// WhatsApp IDs are long strings, safe to use directly or prefix
|
|
99
|
+
const messageId = `whatsapp_${msg.id.id}`;
|
|
100
|
+
const queueData = {
|
|
101
|
+
channel: 'whatsapp',
|
|
102
|
+
sender: sender,
|
|
103
|
+
senderId: senderId,
|
|
104
|
+
message: text,
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
messageId: messageId,
|
|
107
|
+
chatId: chatId
|
|
108
|
+
};
|
|
109
|
+
const queueFile = path_1.default.join(QUEUE_INCOMING, `${messageId}.json`);
|
|
110
|
+
fs_1.default.writeFileSync(queueFile, JSON.stringify(queueData, null, 2));
|
|
111
|
+
log('INFO', `✓ Queued message ${messageId}`);
|
|
112
|
+
// Mark as seen/read (optional, but good UX)
|
|
113
|
+
// await chat.sendSeen();
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
log('ERROR', `Message handling error: ${error.message}`);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// Initialize client
|
|
120
|
+
client.initialize();
|
|
121
|
+
// Enable graceful stop
|
|
122
|
+
const stopClient = async () => {
|
|
123
|
+
log('INFO', 'Stopping WhatsApp client...');
|
|
124
|
+
try {
|
|
125
|
+
await client.destroy();
|
|
126
|
+
log('INFO', 'Client stopped');
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
log('ERROR', `Error stopping client: ${e.message}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
process.once('SIGINT', stopClient);
|
|
135
|
+
process.once('SIGTERM', stopClient);
|
|
136
|
+
// Polling loop for responses
|
|
137
|
+
setInterval(() => {
|
|
138
|
+
try {
|
|
139
|
+
const files = fs_1.default.readdirSync(QUEUE_OUTGOING)
|
|
140
|
+
.filter(f => f.startsWith('whatsapp_') && f.endsWith('.json'));
|
|
141
|
+
for (const file of files) {
|
|
142
|
+
const filePath = path_1.default.join(QUEUE_OUTGOING, file);
|
|
143
|
+
try {
|
|
144
|
+
const content = fs_1.default.readFileSync(filePath, 'utf8');
|
|
145
|
+
const data = JSON.parse(content);
|
|
146
|
+
const { messageId, message: responseText, chatId } = data;
|
|
147
|
+
// Retrieve chat ID from metadata (Stateless)
|
|
148
|
+
if (chatId) {
|
|
149
|
+
client.sendMessage(chatId, responseText)
|
|
150
|
+
.then(() => {
|
|
151
|
+
log('INFO', `✓ Sent response to ${chatId}`);
|
|
152
|
+
fs_1.default.unlinkSync(filePath);
|
|
153
|
+
})
|
|
154
|
+
.catch(err => {
|
|
155
|
+
log('ERROR', `Failed to send whatsapp message: ${err.message}`);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
log('WARN', `Missing Chat ID for message ${messageId} - cannot reply.`);
|
|
160
|
+
// Safe to delete to avoid clogging.
|
|
161
|
+
fs_1.default.unlinkSync(filePath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
log('ERROR', `Error processing outgoing file ${file}: ${err.message}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
// ignore dir read errors
|
|
171
|
+
}
|
|
172
|
+
}, 1000);
|
|
173
|
+
//# sourceMappingURL=whatsapp-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whatsapp-client.js","sourceRoot":"","sources":["../src/whatsapp-client.ts"],"names":[],"mappings":";;AACA;;;GAGG;;;;;AAEH,qDAA6D;AAC7D,sEAAqC;AACrC,4CAAoB;AACpB,gDAAwB;AACxB,4CAAoB;AACpB,oDAA4B;AAE5B,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAChG,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;AAChG,gBAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;AAE3C,MAAM,cAAc,GAAG,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;AACtE,MAAM,cAAc,GAAG,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;AACtE,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;AAEnE,2BAA2B;AAC3B,CAAC,cAAc,EAAE,cAAc,EAAE,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;IACnE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,YAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;AACL,CAAC,CAAC,CAAC;AAYH,SAAS;AACT,SAAS,GAAG,CAAC,KAAa,EAAE,OAAe;IACvC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,SAAS,MAAM,KAAK,KAAK,OAAO,IAAI,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/B,YAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,qDAAiD;AAEjD,MAAM,MAAM,GAAG,8BAAa,CAAC,IAAI,EAAE,CAAC;AAEpC,6BAA6B;AAC7B,mDAAmD;AACnD,MAAM,MAAM,GAAG,IAAI,wBAAM,CAAC;IACtB,YAAY,EAAE,IAAI,2BAAS,CAAC;QACxB,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,mBAAmB,CAAC;KAC9D,CAAC;IACF,SAAS,EAAE;QACP,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,CAAC,cAAc,EAAE,0BAA0B,CAAC;KACrD;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;IACnB,GAAG,CAAC,MAAM,EAAE,gCAAgC,CAAC,CAAC;IAC9C,yBAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;IACpB,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;IAE3C,oBAAoB;IACpB,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,yBAAyB,CAAC,CAAC;IAC1E,YAAE,CAAC,SAAS,CAAC,cAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,YAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;IAC5B,GAAG,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE;IAC9B,GAAG,CAAC,OAAO,EAAE,2BAA2B,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,2BAA2B;AAC3B,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;IACxC,IAAI,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,kBAAkB;QAClB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE9C,mBAAmB;QACnB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC;QAEjC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC;QAC5E,MAAM,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC;QAEnC,GAAG,CAAC,MAAM,EAAE,mBAAmB,MAAM,SAAS,QAAQ,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QAExF,0CAA0C;QAC1C,MAAM,eAAe,GAAG,MAAM,CAAC,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;QAC7F,kDAAkD;QAClD,IAAI,eAAe,IAAI,QAAQ,KAAK,eAAe,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACtF,+BAA+B;YAC/B,GAAG,CAAC,MAAM,EAAE,sCAAsC,MAAM,SAAS,QAAQ,GAAG,CAAC,CAAC;YAC9E,OAAO;QACZ,CAAC;QAED,0BAA0B;QAC1B,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACjC,GAAG,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;YACzC,MAAM,aAAa,GAAG,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;YACjE,YAAE,CAAC,aAAa,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACzC,MAAM,GAAG,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;YAC/F,OAAO;QACX,CAAC;QAED,6BAA6B;QAC7B,gEAAgE;QAChE,MAAM,SAAS,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAE1C,MAAM,SAAS,GAAc;YACzB,OAAO,EAAE,UAAU;YACnB,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,MAAM;SACjB,CAAC;QAEF,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,SAAS,OAAO,CAAC,CAAC;QACjE,YAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAEhE,GAAG,CAAC,MAAM,EAAE,oBAAoB,SAAS,EAAE,CAAC,CAAC;QAE7C,4CAA4C;QAC5C,yBAAyB;IAE7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,GAAG,CAAC,OAAO,EAAE,2BAA4B,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,oBAAoB;AACpB,MAAM,CAAC,UAAU,EAAE,CAAC;AAEpB,uBAAuB;AACvB,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE;IAC1B,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;IAC3C,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,GAAG,CAAC,OAAO,EAAE,0BAA2B,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC,CAAC;AAEF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACnC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAEpC,6BAA6B;AAC7B,WAAW,CAAC,GAAG,EAAE;IACb,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,YAAE,CAAC,WAAW,CAAC,cAAc,CAAC;aACvC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAEnE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;YAEjD,IAAI,CAAC;gBACD,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACjC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;gBAE1D,6CAA6C;gBAC7C,IAAI,MAAM,EAAE,CAAC;oBACT,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC;yBACnC,IAAI,CAAC,GAAG,EAAE;wBACP,GAAG,CAAC,MAAM,EAAE,sBAAsB,MAAM,EAAE,CAAC,CAAC;wBAC5C,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;oBAC5B,CAAC,CAAC;yBACD,KAAK,CAAC,GAAG,CAAC,EAAE;wBACT,GAAG,CAAC,OAAO,EAAE,oCAAoC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBACpE,CAAC,CAAC,CAAC;gBACX,CAAC;qBAAM,CAAC;oBACJ,GAAG,CAAC,MAAM,EAAE,+BAA+B,SAAS,kBAAkB,CAAC,CAAC;oBACxE,oCAAoC;oBACpC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBAC5B,CAAC;YAEL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,GAAG,CAAC,OAAO,EAAE,kCAAkC,IAAI,KAAM,GAAwB,CAAC,OAAO,EAAE,CAAC,CAAC;YACjG,CAAC;QACL,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,yBAAyB;IAC7B,CAAC;AACL,CAAC,EAAE,IAAI,CAAC,CAAC"}
|