@cortask/channels 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sebastian Kraus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,101 @@
1
+ interface TelegramConfig {
2
+ botToken: string;
3
+ allowedUsers: string[];
4
+ }
5
+ declare class TelegramAdapter implements ChannelPlugin {
6
+ id: string;
7
+ name: string;
8
+ private bot;
9
+ private config;
10
+ private running;
11
+ private handler;
12
+ constructor(config: TelegramConfig);
13
+ private setupHandlers;
14
+ start(): Promise<void>;
15
+ stop(): Promise<void>;
16
+ onMessage(handler: (msg: InboundMessage) => Promise<string>): void;
17
+ sendMessage(target: string, text: string): Promise<void>;
18
+ isRunning(): boolean;
19
+ }
20
+
21
+ interface DiscordConfig {
22
+ botToken: string;
23
+ allowedGuilds?: string[];
24
+ allowedUsers?: string[];
25
+ respondToMentions?: boolean;
26
+ respondToDMs?: boolean;
27
+ }
28
+ declare class DiscordAdapter implements ChannelPlugin {
29
+ id: string;
30
+ name: string;
31
+ private client;
32
+ private config;
33
+ private running;
34
+ private handler;
35
+ constructor(config: DiscordConfig);
36
+ start(): Promise<void>;
37
+ stop(): Promise<void>;
38
+ onMessage(handler: (msg: InboundMessage) => Promise<string>): void;
39
+ sendMessage(target: string, text: string): Promise<void>;
40
+ isRunning(): boolean;
41
+ private handleMessage;
42
+ }
43
+
44
+ interface TrustedContact {
45
+ phone: string;
46
+ name?: string;
47
+ permission: "read" | "write" | "admin";
48
+ }
49
+ interface WhatsAppConfig {
50
+ authDir?: string;
51
+ allowedUsers?: string[];
52
+ trustedContacts?: TrustedContact[];
53
+ }
54
+ interface QRCodeResult {
55
+ qrDataUrl?: string;
56
+ success: boolean;
57
+ message: string;
58
+ }
59
+
60
+ declare class WhatsAppAdapter implements ChannelPlugin {
61
+ id: string;
62
+ name: string;
63
+ private socket;
64
+ private config;
65
+ private running;
66
+ private handler;
67
+ readonly authDir: string;
68
+ private reconnectAttempts;
69
+ constructor(config?: WhatsAppConfig);
70
+ onMessage(handler: (msg: InboundMessage) => Promise<string>): void;
71
+ start(): Promise<void>;
72
+ stop(): Promise<void>;
73
+ sendMessage(target: string, text: string): Promise<void>;
74
+ isRunning(): boolean;
75
+ isAuthenticated(): boolean;
76
+ generateQR(): Promise<QRCodeResult>;
77
+ logout(): Promise<void>;
78
+ setTrustedContacts(contacts: TrustedContact[]): void;
79
+ private findTrustedContact;
80
+ private connectSocket;
81
+ }
82
+
83
+ interface ChannelPlugin {
84
+ id: string;
85
+ name: string;
86
+ start(): Promise<void>;
87
+ stop(): Promise<void>;
88
+ onMessage(handler: (msg: InboundMessage) => Promise<string>): void;
89
+ sendMessage(target: string, text: string): Promise<void>;
90
+ isRunning(): boolean;
91
+ }
92
+ interface InboundMessage {
93
+ channelId: string;
94
+ userId: string;
95
+ userName?: string;
96
+ chatId: string;
97
+ text: string;
98
+ messageId?: number;
99
+ }
100
+
101
+ export { type ChannelPlugin, DiscordAdapter, type DiscordConfig, type InboundMessage, type QRCodeResult, TelegramAdapter, type TelegramConfig, type TrustedContact, WhatsAppAdapter, type WhatsAppConfig };
package/dist/index.js ADDED
@@ -0,0 +1,488 @@
1
+ // src/telegram/adapter.ts
2
+ import { Bot } from "grammy";
3
+ var TelegramAdapter = class {
4
+ id = "telegram";
5
+ name = "Telegram";
6
+ bot;
7
+ config;
8
+ running = false;
9
+ handler = null;
10
+ constructor(config) {
11
+ this.config = config;
12
+ this.bot = new Bot(config.botToken);
13
+ this.setupHandlers();
14
+ }
15
+ setupHandlers() {
16
+ this.bot.use(async (ctx, next) => {
17
+ if (this.config.allowedUsers.length === 0) {
18
+ return next();
19
+ }
20
+ const userId = ctx.from?.id?.toString();
21
+ const username = ctx.from?.username;
22
+ const allowed = this.config.allowedUsers.some(
23
+ (u) => u === userId || u === username
24
+ );
25
+ if (!allowed) {
26
+ await ctx.reply("You are not authorized to use this bot.");
27
+ return;
28
+ }
29
+ return next();
30
+ });
31
+ this.bot.on("message:text", async (ctx) => {
32
+ if (!this.handler || !ctx.message?.text) return;
33
+ const message = {
34
+ channelId: this.id,
35
+ userId: ctx.from?.id?.toString() ?? "unknown",
36
+ userName: ctx.from?.username ?? ctx.from?.first_name,
37
+ chatId: ctx.chat?.id?.toString() ?? "unknown",
38
+ text: ctx.message.text,
39
+ messageId: ctx.message.message_id
40
+ };
41
+ try {
42
+ const response = await this.handler(message);
43
+ const chunks = splitMessage(response, 4e3);
44
+ for (const chunk of chunks) {
45
+ await ctx.reply(chunk, { parse_mode: "Markdown" }).catch(() => {
46
+ return ctx.reply(chunk);
47
+ });
48
+ }
49
+ } catch (err) {
50
+ const errMsg = err instanceof Error ? err.message : "An error occurred";
51
+ await ctx.reply(`Error: ${errMsg}`);
52
+ }
53
+ });
54
+ }
55
+ async start() {
56
+ if (this.running) return;
57
+ this.running = true;
58
+ this.bot.start({
59
+ onStart: () => {
60
+ console.log("[telegram] Bot started");
61
+ }
62
+ });
63
+ }
64
+ async stop() {
65
+ if (!this.running) return;
66
+ this.running = false;
67
+ await this.bot.stop();
68
+ console.log("[telegram] Bot stopped");
69
+ }
70
+ onMessage(handler) {
71
+ this.handler = handler;
72
+ }
73
+ async sendMessage(target, text) {
74
+ const chunks = splitMessage(text, 4e3);
75
+ for (const chunk of chunks) {
76
+ await this.bot.api.sendMessage(target, chunk, {
77
+ parse_mode: "Markdown"
78
+ }).catch(() => {
79
+ return this.bot.api.sendMessage(target, chunk);
80
+ });
81
+ }
82
+ }
83
+ isRunning() {
84
+ return this.running;
85
+ }
86
+ };
87
+ function splitMessage(text, maxLen) {
88
+ if (text.length <= maxLen) return [text];
89
+ const chunks = [];
90
+ let remaining = text;
91
+ while (remaining.length > 0) {
92
+ if (remaining.length <= maxLen) {
93
+ chunks.push(remaining);
94
+ break;
95
+ }
96
+ let breakAt = remaining.lastIndexOf("\n", maxLen);
97
+ if (breakAt < maxLen / 2) {
98
+ breakAt = remaining.lastIndexOf(" ", maxLen);
99
+ }
100
+ if (breakAt < maxLen / 2) {
101
+ breakAt = maxLen;
102
+ }
103
+ chunks.push(remaining.slice(0, breakAt));
104
+ remaining = remaining.slice(breakAt).trimStart();
105
+ }
106
+ return chunks;
107
+ }
108
+
109
+ // src/discord/adapter.ts
110
+ import {
111
+ Client,
112
+ GatewayIntentBits,
113
+ Partials
114
+ } from "discord.js";
115
+ var DiscordAdapter = class {
116
+ id = "discord";
117
+ name = "Discord";
118
+ client;
119
+ config;
120
+ running = false;
121
+ handler = null;
122
+ constructor(config) {
123
+ this.config = {
124
+ respondToMentions: true,
125
+ respondToDMs: true,
126
+ ...config
127
+ };
128
+ this.client = new Client({
129
+ intents: [
130
+ GatewayIntentBits.Guilds,
131
+ GatewayIntentBits.GuildMessages,
132
+ GatewayIntentBits.MessageContent,
133
+ GatewayIntentBits.DirectMessages
134
+ ],
135
+ partials: [Partials.Channel]
136
+ });
137
+ }
138
+ async start() {
139
+ if (this.running) return;
140
+ this.client.on("messageCreate", (msg) => this.handleMessage(msg));
141
+ this.client.once("ready", () => {
142
+ console.log(`[discord] Bot ready as ${this.client.user?.tag}`);
143
+ });
144
+ await this.client.login(this.config.botToken);
145
+ this.running = true;
146
+ }
147
+ async stop() {
148
+ if (!this.running) return;
149
+ this.running = false;
150
+ await this.client.destroy();
151
+ console.log("[discord] Bot stopped");
152
+ }
153
+ onMessage(handler) {
154
+ this.handler = handler;
155
+ }
156
+ async sendMessage(target, text) {
157
+ const channel = await this.client.channels.fetch(target);
158
+ if (channel?.isTextBased() && "send" in channel) {
159
+ const chunks = splitMessage2(text, 2e3);
160
+ for (const chunk of chunks) {
161
+ await channel.send(chunk);
162
+ }
163
+ }
164
+ }
165
+ isRunning() {
166
+ return this.running;
167
+ }
168
+ async handleMessage(msg) {
169
+ if (!this.handler || msg.author.bot) return;
170
+ const isDM = !msg.guild;
171
+ const isMention = msg.mentions.has(this.client.user);
172
+ if (msg.guild && this.config.allowedGuilds?.length && !this.config.allowedGuilds.includes(msg.guild.id)) {
173
+ return;
174
+ }
175
+ if (this.config.allowedUsers?.length && !this.config.allowedUsers.includes(msg.author.id)) {
176
+ return;
177
+ }
178
+ if (isDM && !this.config.respondToDMs) return;
179
+ if (!isDM && !isMention) return;
180
+ if (!isDM && !this.config.respondToMentions) return;
181
+ let text = msg.content;
182
+ if (isMention && this.client.user) {
183
+ text = text.replace(new RegExp(`<@!?${this.client.user.id}>\\s*`), "").trim();
184
+ }
185
+ if (!text) return;
186
+ const inbound = {
187
+ channelId: this.id,
188
+ userId: msg.author.id,
189
+ userName: msg.author.displayName ?? msg.author.username,
190
+ chatId: msg.channel.id,
191
+ text,
192
+ messageId: Number(msg.id)
193
+ };
194
+ try {
195
+ if ("sendTyping" in msg.channel) await msg.channel.sendTyping();
196
+ const response = await this.handler(inbound);
197
+ const chunks = splitMessage2(response, 2e3);
198
+ for (const chunk of chunks) {
199
+ await msg.reply(chunk);
200
+ }
201
+ } catch (err) {
202
+ const errMsg = err instanceof Error ? err.message : "An error occurred";
203
+ await msg.reply(`Error: ${errMsg}`).catch(() => {
204
+ });
205
+ }
206
+ }
207
+ };
208
+ function splitMessage2(text, maxLen) {
209
+ if (text.length <= maxLen) return [text];
210
+ const chunks = [];
211
+ let remaining = text;
212
+ while (remaining.length > 0) {
213
+ if (remaining.length <= maxLen) {
214
+ chunks.push(remaining);
215
+ break;
216
+ }
217
+ let breakAt = remaining.lastIndexOf("\n", maxLen);
218
+ if (breakAt < maxLen / 2) breakAt = remaining.lastIndexOf(" ", maxLen);
219
+ if (breakAt < maxLen / 2) breakAt = maxLen;
220
+ chunks.push(remaining.slice(0, breakAt));
221
+ remaining = remaining.slice(breakAt).trimStart();
222
+ }
223
+ return chunks;
224
+ }
225
+
226
+ // src/whatsapp/adapter.ts
227
+ import path2 from "path";
228
+ import os from "os";
229
+ import {
230
+ makeWASocket,
231
+ DisconnectReason,
232
+ fetchLatestBaileysVersion,
233
+ Browsers
234
+ } from "@whiskeysockets/baileys";
235
+
236
+ // src/whatsapp/auth.ts
237
+ import fs from "fs";
238
+ import path from "path";
239
+ import { useMultiFileAuthState } from "@whiskeysockets/baileys";
240
+ import QRCode from "qrcode";
241
+ async function createAuthState(authDir) {
242
+ if (!fs.existsSync(authDir)) {
243
+ fs.mkdirSync(authDir, { recursive: true });
244
+ }
245
+ return useMultiFileAuthState(authDir);
246
+ }
247
+ async function generateQRCode(qrString) {
248
+ return QRCode.toDataURL(qrString);
249
+ }
250
+ function isAuthenticated(authDir) {
251
+ return fs.existsSync(path.join(authDir, "creds.json"));
252
+ }
253
+ function clearAuthState(authDir) {
254
+ if (fs.existsSync(authDir)) {
255
+ fs.rmSync(authDir, { recursive: true, force: true });
256
+ }
257
+ }
258
+
259
+ // src/whatsapp/outbound.ts
260
+ function normalizeJID(phoneNumber) {
261
+ const cleaned = phoneNumber.replace(/\D/g, "");
262
+ return `${cleaned}@s.whatsapp.net`;
263
+ }
264
+ async function sendMessage(socket, target, text) {
265
+ const jid = target.includes("@") ? target : normalizeJID(target);
266
+ await socket.sendPresenceUpdate("composing", jid);
267
+ await socket.sendMessage(jid, { text });
268
+ await socket.sendPresenceUpdate("paused", jid);
269
+ }
270
+
271
+ // src/whatsapp/adapter.ts
272
+ var TERMINAL_STATUS_CODES = /* @__PURE__ */ new Set([
273
+ DisconnectReason.loggedOut,
274
+ DisconnectReason.forbidden,
275
+ DisconnectReason.multideviceMismatch
276
+ ]);
277
+ var MAX_RECONNECT_ATTEMPTS = 10;
278
+ var BASE_RECONNECT_DELAY = 5e3;
279
+ var MAX_RECONNECT_DELAY = 3e5;
280
+ var WhatsAppAdapter = class {
281
+ id = "whatsapp";
282
+ name = "WhatsApp";
283
+ socket = null;
284
+ config;
285
+ running = false;
286
+ handler = null;
287
+ authDir;
288
+ reconnectAttempts = 0;
289
+ constructor(config = {}) {
290
+ this.config = {
291
+ allowedUsers: [],
292
+ ...config
293
+ };
294
+ this.authDir = config.authDir || path2.join(os.homedir(), ".cortask", "whatsapp-auth");
295
+ }
296
+ onMessage(handler) {
297
+ this.handler = handler;
298
+ }
299
+ async start() {
300
+ if (this.running) return;
301
+ if (!isAuthenticated(this.authDir)) {
302
+ throw new Error("WhatsApp not authenticated. Scan QR code first.");
303
+ }
304
+ await this.connectSocket();
305
+ this.running = true;
306
+ }
307
+ async stop() {
308
+ if (!this.running) return;
309
+ if (this.socket) {
310
+ try {
311
+ await this.socket.logout();
312
+ } catch {
313
+ }
314
+ this.socket.end(void 0);
315
+ this.socket = null;
316
+ }
317
+ this.running = false;
318
+ console.log("[whatsapp] Bot stopped");
319
+ }
320
+ async sendMessage(target, text) {
321
+ if (!this.socket) throw new Error("WhatsApp socket not connected");
322
+ await sendMessage(this.socket, target, text);
323
+ }
324
+ isRunning() {
325
+ return this.running;
326
+ }
327
+ isAuthenticated() {
328
+ return isAuthenticated(this.authDir);
329
+ }
330
+ async generateQR() {
331
+ return new Promise(async (resolve, reject) => {
332
+ try {
333
+ const { state, saveCreds } = await createAuthState(this.authDir);
334
+ const { version } = await fetchLatestBaileysVersion();
335
+ const socket = makeWASocket({
336
+ auth: state,
337
+ version,
338
+ browser: Browsers.ubuntu("Cortask"),
339
+ printQRInTerminal: false
340
+ });
341
+ let qrGenerated = false;
342
+ socket.ev.on("connection.update", async (update) => {
343
+ const { connection, qr } = update;
344
+ if (qr && !qrGenerated) {
345
+ qrGenerated = true;
346
+ const qrDataUrl = await generateQRCode(qr);
347
+ resolve({
348
+ qrDataUrl,
349
+ success: true,
350
+ message: "Scan this QR code with WhatsApp"
351
+ });
352
+ }
353
+ if (connection === "open") {
354
+ console.log("[whatsapp] Successfully authenticated");
355
+ socket.end(void 0);
356
+ }
357
+ if (connection === "close") {
358
+ if (!qrGenerated) {
359
+ reject(new Error("Failed to generate QR code"));
360
+ }
361
+ socket.end(void 0);
362
+ }
363
+ });
364
+ socket.ev.on("creds.update", saveCreds);
365
+ setTimeout(() => {
366
+ if (!qrGenerated) {
367
+ socket.end(void 0);
368
+ reject(new Error("QR code generation timeout"));
369
+ }
370
+ }, 6e4);
371
+ } catch (err) {
372
+ reject(err);
373
+ }
374
+ });
375
+ }
376
+ async logout() {
377
+ if (this.socket) {
378
+ try {
379
+ await this.socket.logout();
380
+ this.socket.end(void 0);
381
+ } catch {
382
+ }
383
+ this.socket = null;
384
+ }
385
+ clearAuthState(this.authDir);
386
+ this.running = false;
387
+ console.log("[whatsapp] Logged out");
388
+ }
389
+ setTrustedContacts(contacts) {
390
+ this.config.trustedContacts = contacts;
391
+ }
392
+ findTrustedContact(userId) {
393
+ if (!this.config.trustedContacts?.length) return void 0;
394
+ return this.config.trustedContacts.find((c) => {
395
+ const normalized = c.phone.replace(/[\s+\-()]/g, "");
396
+ return userId === normalized || userId.endsWith(normalized) || normalized.endsWith(userId);
397
+ });
398
+ }
399
+ async connectSocket() {
400
+ const { state, saveCreds } = await createAuthState(this.authDir);
401
+ const { version } = await fetchLatestBaileysVersion();
402
+ this.socket = makeWASocket({
403
+ auth: state,
404
+ version,
405
+ browser: Browsers.ubuntu("Cortask"),
406
+ printQRInTerminal: false
407
+ });
408
+ this.socket.ev.on("connection.update", async (update) => {
409
+ const { connection, lastDisconnect } = update;
410
+ if (connection === "close") {
411
+ const statusCode = lastDisconnect?.error?.output?.statusCode;
412
+ if (statusCode != null && TERMINAL_STATUS_CODES.has(statusCode)) {
413
+ console.error(`[whatsapp] Session terminated (status ${statusCode}). Re-authenticate.`);
414
+ this.running = false;
415
+ return;
416
+ }
417
+ this.reconnectAttempts++;
418
+ if (this.reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {
419
+ console.error(`[whatsapp] Giving up after ${this.reconnectAttempts} attempts.`);
420
+ this.running = false;
421
+ return;
422
+ }
423
+ const delay = Math.min(
424
+ BASE_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts - 1),
425
+ MAX_RECONNECT_DELAY
426
+ );
427
+ console.log(`[whatsapp] Reconnecting in ${Math.round(delay / 1e3)}s (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);
428
+ setTimeout(() => {
429
+ if (this.running) this.connectSocket();
430
+ }, delay);
431
+ } else if (connection === "open") {
432
+ this.reconnectAttempts = 0;
433
+ console.log("[whatsapp] Connected");
434
+ }
435
+ });
436
+ this.socket.ev.on("creds.update", saveCreds);
437
+ this.socket.ev.on("messages.upsert", async ({ messages, type }) => {
438
+ if (type !== "notify") return;
439
+ for (const msg of messages) {
440
+ if (!msg.key?.remoteJid || msg.key.remoteJid === "status@broadcast" || msg.key.fromMe) continue;
441
+ const text = msg.message?.conversation || msg.message?.extendedTextMessage?.text || "";
442
+ if (!text) continue;
443
+ const remoteJid = msg.key.remoteJid;
444
+ const participantJid = msg.key.participant || remoteJid;
445
+ const userId = participantJid.replace("@s.whatsapp.net", "").replace(":@lid", "").replace("@lid", "");
446
+ if (this.config.trustedContacts?.length) {
447
+ const contact = this.findTrustedContact(userId);
448
+ if (!contact) continue;
449
+ if (contact.permission === "read") {
450
+ await sendMessage(this.socket, remoteJid, "You have read-only access.");
451
+ continue;
452
+ }
453
+ } else if (this.config.allowedUsers?.length) {
454
+ const phone = `+${userId}`;
455
+ const allowed = this.config.allowedUsers.some((u) => {
456
+ const normalized = u.replace(/[\s+]/g, "");
457
+ return u === phone || u === userId || userId.includes(normalized);
458
+ });
459
+ if (!allowed) continue;
460
+ }
461
+ if (!this.handler) continue;
462
+ await this.socket.sendPresenceUpdate("composing", remoteJid);
463
+ try {
464
+ const inbound = {
465
+ channelId: "whatsapp",
466
+ userId,
467
+ userName: msg.pushName || "Unknown",
468
+ chatId: remoteJid,
469
+ text
470
+ };
471
+ const response = await this.handler(inbound);
472
+ if (response) await sendMessage(this.socket, remoteJid, response);
473
+ } catch (err) {
474
+ console.error("[whatsapp] Error handling message:", err);
475
+ await sendMessage(this.socket, remoteJid, "Sorry, an error occurred.");
476
+ } finally {
477
+ await this.socket.sendPresenceUpdate("paused", remoteJid);
478
+ }
479
+ }
480
+ });
481
+ }
482
+ };
483
+ export {
484
+ DiscordAdapter,
485
+ TelegramAdapter,
486
+ WhatsAppAdapter
487
+ };
488
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/telegram/adapter.ts","../src/discord/adapter.ts","../src/whatsapp/adapter.ts","../src/whatsapp/auth.ts","../src/whatsapp/outbound.ts"],"sourcesContent":["import { Bot, type Context } from \"grammy\";\nimport type { ChannelPlugin, InboundMessage } from \"../index.js\";\n\nexport interface TelegramConfig {\n botToken: string;\n allowedUsers: string[]; // Telegram user IDs or usernames\n}\n\nexport class TelegramAdapter implements ChannelPlugin {\n id = \"telegram\";\n name = \"Telegram\";\n\n private bot: Bot;\n private config: TelegramConfig;\n private running = false;\n private handler: ((msg: InboundMessage) => Promise<string>) | null = null;\n\n constructor(config: TelegramConfig) {\n this.config = config;\n this.bot = new Bot(config.botToken);\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n // ACL check\n this.bot.use(async (ctx, next) => {\n if (this.config.allowedUsers.length === 0) {\n return next();\n }\n\n const userId = ctx.from?.id?.toString();\n const username = ctx.from?.username;\n\n const allowed = this.config.allowedUsers.some(\n (u) => u === userId || u === username,\n );\n\n if (!allowed) {\n await ctx.reply(\"You are not authorized to use this bot.\");\n return;\n }\n\n return next();\n });\n\n // Handle text messages\n this.bot.on(\"message:text\", async (ctx: Context) => {\n if (!this.handler || !ctx.message?.text) return;\n\n const message: InboundMessage = {\n channelId: this.id,\n userId: ctx.from?.id?.toString() ?? \"unknown\",\n userName: ctx.from?.username ?? ctx.from?.first_name,\n chatId: ctx.chat?.id?.toString() ?? \"unknown\",\n text: ctx.message.text,\n messageId: ctx.message.message_id,\n };\n\n try {\n const response = await this.handler(message);\n\n // Split long messages (Telegram has 4096 char limit)\n const chunks = splitMessage(response, 4000);\n for (const chunk of chunks) {\n await ctx.reply(chunk, { parse_mode: \"Markdown\" }).catch(() => {\n // Fallback without markdown if parsing fails\n return ctx.reply(chunk);\n });\n }\n } catch (err) {\n const errMsg =\n err instanceof Error ? err.message : \"An error occurred\";\n await ctx.reply(`Error: ${errMsg}`);\n }\n });\n }\n\n async start(): Promise<void> {\n if (this.running) return;\n this.running = true;\n\n // Start polling (non-blocking)\n this.bot.start({\n onStart: () => {\n console.log(\"[telegram] Bot started\");\n },\n });\n }\n\n async stop(): Promise<void> {\n if (!this.running) return;\n this.running = false;\n await this.bot.stop();\n console.log(\"[telegram] Bot stopped\");\n }\n\n onMessage(handler: (msg: InboundMessage) => Promise<string>): void {\n this.handler = handler;\n }\n\n async sendMessage(target: string, text: string): Promise<void> {\n const chunks = splitMessage(text, 4000);\n for (const chunk of chunks) {\n await this.bot.api.sendMessage(target, chunk, {\n parse_mode: \"Markdown\",\n }).catch(() => {\n return this.bot.api.sendMessage(target, chunk);\n });\n }\n }\n\n isRunning(): boolean {\n return this.running;\n }\n}\n\nfunction splitMessage(text: string, maxLen: number): string[] {\n if (text.length <= maxLen) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= maxLen) {\n chunks.push(remaining);\n break;\n }\n\n // Try to break at a newline\n let breakAt = remaining.lastIndexOf(\"\\n\", maxLen);\n if (breakAt < maxLen / 2) {\n // No good newline, break at space\n breakAt = remaining.lastIndexOf(\" \", maxLen);\n }\n if (breakAt < maxLen / 2) {\n // No good break point, just cut\n breakAt = maxLen;\n }\n\n chunks.push(remaining.slice(0, breakAt));\n remaining = remaining.slice(breakAt).trimStart();\n }\n\n return chunks;\n}\n","import {\n Client,\n GatewayIntentBits,\n Partials,\n type Message,\n} from \"discord.js\";\nimport type { ChannelPlugin, InboundMessage } from \"../index.js\";\n\nexport interface DiscordConfig {\n botToken: string;\n allowedGuilds?: string[];\n allowedUsers?: string[];\n respondToMentions?: boolean;\n respondToDMs?: boolean;\n}\n\nexport class DiscordAdapter implements ChannelPlugin {\n id = \"discord\";\n name = \"Discord\";\n\n private client: Client;\n private config: DiscordConfig;\n private running = false;\n private handler: ((msg: InboundMessage) => Promise<string>) | null = null;\n\n constructor(config: DiscordConfig) {\n this.config = {\n respondToMentions: true,\n respondToDMs: true,\n ...config,\n };\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.DirectMessages,\n ],\n partials: [Partials.Channel],\n });\n }\n\n async start(): Promise<void> {\n if (this.running) return;\n\n this.client.on(\"messageCreate\", (msg) => this.handleMessage(msg));\n\n this.client.once(\"ready\", () => {\n console.log(`[discord] Bot ready as ${this.client.user?.tag}`);\n });\n\n await this.client.login(this.config.botToken);\n this.running = true;\n }\n\n async stop(): Promise<void> {\n if (!this.running) return;\n this.running = false;\n await this.client.destroy();\n console.log(\"[discord] Bot stopped\");\n }\n\n onMessage(handler: (msg: InboundMessage) => Promise<string>): void {\n this.handler = handler;\n }\n\n async sendMessage(target: string, text: string): Promise<void> {\n const channel = await this.client.channels.fetch(target);\n if (channel?.isTextBased() && \"send\" in channel) {\n const chunks = splitMessage(text, 2000);\n for (const chunk of chunks) {\n await channel.send(chunk);\n }\n }\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n private async handleMessage(msg: Message): Promise<void> {\n if (!this.handler || msg.author.bot) return;\n\n const isDM = !msg.guild;\n const isMention = msg.mentions.has(this.client.user!);\n\n // Check guild allowlist\n if (\n msg.guild &&\n this.config.allowedGuilds?.length &&\n !this.config.allowedGuilds.includes(msg.guild.id)\n ) {\n return;\n }\n\n // Check user allowlist\n if (\n this.config.allowedUsers?.length &&\n !this.config.allowedUsers.includes(msg.author.id)\n ) {\n return;\n }\n\n // Only respond to DMs or mentions\n if (isDM && !this.config.respondToDMs) return;\n if (!isDM && !isMention) return;\n if (!isDM && !this.config.respondToMentions) return;\n\n // Strip bot mention from text\n let text = msg.content;\n if (isMention && this.client.user) {\n text = text.replace(new RegExp(`<@!?${this.client.user.id}>\\\\s*`), \"\").trim();\n }\n if (!text) return;\n\n const inbound: InboundMessage = {\n channelId: this.id,\n userId: msg.author.id,\n userName: msg.author.displayName ?? msg.author.username,\n chatId: msg.channel.id,\n text,\n messageId: Number(msg.id),\n };\n\n try {\n if (\"sendTyping\" in msg.channel) await msg.channel.sendTyping();\n const response = await this.handler(inbound);\n const chunks = splitMessage(response, 2000);\n for (const chunk of chunks) {\n await msg.reply(chunk);\n }\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : \"An error occurred\";\n await msg.reply(`Error: ${errMsg}`).catch(() => {});\n }\n }\n}\n\nfunction splitMessage(text: string, maxLen: number): string[] {\n if (text.length <= maxLen) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= maxLen) {\n chunks.push(remaining);\n break;\n }\n let breakAt = remaining.lastIndexOf(\"\\n\", maxLen);\n if (breakAt < maxLen / 2) breakAt = remaining.lastIndexOf(\" \", maxLen);\n if (breakAt < maxLen / 2) breakAt = maxLen;\n chunks.push(remaining.slice(0, breakAt));\n remaining = remaining.slice(breakAt).trimStart();\n }\n return chunks;\n}\n","import path from \"node:path\";\nimport os from \"node:os\";\nimport {\n makeWASocket,\n DisconnectReason,\n fetchLatestBaileysVersion,\n type WASocket,\n type ConnectionState,\n Browsers,\n} from \"@whiskeysockets/baileys\";\nimport type { ChannelPlugin, InboundMessage } from \"../index.js\";\nimport type { WhatsAppConfig, QRCodeResult, TrustedContact } from \"./types.js\";\nimport { createAuthState, generateQRCode, isAuthenticated, clearAuthState } from \"./auth.js\";\nimport { sendMessage } from \"./outbound.js\";\n\n// Noop logger to suppress baileys' verbose JSON output\nconst noop = () => {};\nconst silentLogger = { level: \"silent\", trace: noop, debug: noop, info: noop, warn: noop, error: noop, fatal: noop, child: () => silentLogger } as any;\n\nconst TERMINAL_STATUS_CODES = new Set([\n DisconnectReason.loggedOut,\n DisconnectReason.forbidden,\n DisconnectReason.multideviceMismatch,\n]);\n\nconst MAX_RECONNECT_ATTEMPTS = 10;\nconst BASE_RECONNECT_DELAY = 5_000;\nconst MAX_RECONNECT_DELAY = 300_000;\n\nexport class WhatsAppAdapter implements ChannelPlugin {\n id = \"whatsapp\";\n name = \"WhatsApp\";\n\n private socket: WASocket | null = null;\n private config: WhatsAppConfig;\n private running = false;\n private handler: ((msg: InboundMessage) => Promise<string>) | null = null;\n readonly authDir: string;\n private reconnectAttempts = 0;\n\n constructor(config: WhatsAppConfig = {}) {\n this.config = {\n allowedUsers: [],\n ...config,\n };\n this.authDir = config.authDir || path.join(os.homedir(), \".cortask\", \"whatsapp-auth\");\n }\n\n onMessage(handler: (msg: InboundMessage) => Promise<string>): void {\n this.handler = handler;\n }\n\n async start(): Promise<void> {\n if (this.running) return;\n if (!isAuthenticated(this.authDir)) {\n throw new Error(\"WhatsApp not authenticated. Scan QR code first.\");\n }\n await this.connectSocket();\n this.running = true;\n }\n\n async stop(): Promise<void> {\n if (!this.running) return;\n if (this.socket) {\n try { await this.socket.logout(); } catch { /* ignore */ }\n this.socket.end(undefined);\n this.socket = null;\n }\n this.running = false;\n console.log(\"[whatsapp] Bot stopped\");\n }\n\n async sendMessage(target: string, text: string): Promise<void> {\n if (!this.socket) throw new Error(\"WhatsApp socket not connected\");\n await sendMessage(this.socket, target, text);\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n isAuthenticated(): boolean {\n return isAuthenticated(this.authDir);\n }\n\n async generateQR(): Promise<QRCodeResult> {\n return new Promise(async (resolve, reject) => {\n try {\n const { state, saveCreds } = await createAuthState(this.authDir);\n const { version } = await fetchLatestBaileysVersion();\n\n const socket = makeWASocket({\n auth: state,\n version,\n browser: Browsers.ubuntu(\"Cortask\"),\n printQRInTerminal: false,\n });\n\n let qrGenerated = false;\n\n socket.ev.on(\"connection.update\", async (update: Partial<ConnectionState>) => {\n const { connection, qr } = update;\n\n if (qr && !qrGenerated) {\n qrGenerated = true;\n const qrDataUrl = await generateQRCode(qr);\n resolve({\n qrDataUrl,\n success: true,\n message: \"Scan this QR code with WhatsApp\",\n });\n }\n\n if (connection === \"open\") {\n console.log(\"[whatsapp] Successfully authenticated\");\n socket.end(undefined);\n }\n\n if (connection === \"close\") {\n if (!qrGenerated) {\n reject(new Error(\"Failed to generate QR code\"));\n }\n socket.end(undefined);\n }\n });\n\n socket.ev.on(\"creds.update\", saveCreds);\n\n setTimeout(() => {\n if (!qrGenerated) {\n socket.end(undefined);\n reject(new Error(\"QR code generation timeout\"));\n }\n }, 60_000);\n } catch (err) {\n reject(err);\n }\n });\n }\n\n async logout(): Promise<void> {\n if (this.socket) {\n try { await this.socket.logout(); this.socket.end(undefined); } catch { /* ignore */ }\n this.socket = null;\n }\n clearAuthState(this.authDir);\n this.running = false;\n console.log(\"[whatsapp] Logged out\");\n }\n\n setTrustedContacts(contacts: TrustedContact[]): void {\n this.config.trustedContacts = contacts;\n }\n\n private findTrustedContact(userId: string): TrustedContact | undefined {\n if (!this.config.trustedContacts?.length) return undefined;\n return this.config.trustedContacts.find((c) => {\n const normalized = c.phone.replace(/[\\s+\\-()]/g, \"\");\n return userId === normalized || userId.endsWith(normalized) || normalized.endsWith(userId);\n });\n }\n\n private async connectSocket(): Promise<void> {\n const { state, saveCreds } = await createAuthState(this.authDir);\n const { version } = await fetchLatestBaileysVersion();\n\n this.socket = makeWASocket({\n auth: state,\n version,\n browser: Browsers.ubuntu(\"Cortask\"),\n printQRInTerminal: false,\n });\n\n this.socket.ev.on(\"connection.update\", async (update: Partial<ConnectionState>) => {\n const { connection, lastDisconnect } = update;\n\n if (connection === \"close\") {\n const statusCode = (lastDisconnect?.error as any)?.output?.statusCode as number | undefined;\n\n if (statusCode != null && TERMINAL_STATUS_CODES.has(statusCode)) {\n console.error(`[whatsapp] Session terminated (status ${statusCode}). Re-authenticate.`);\n this.running = false;\n return;\n }\n\n this.reconnectAttempts++;\n if (this.reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {\n console.error(`[whatsapp] Giving up after ${this.reconnectAttempts} attempts.`);\n this.running = false;\n return;\n }\n\n const delay = Math.min(\n BASE_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts - 1),\n MAX_RECONNECT_DELAY,\n );\n console.log(`[whatsapp] Reconnecting in ${Math.round(delay / 1000)}s (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`);\n\n setTimeout(() => {\n if (this.running) this.connectSocket();\n }, delay);\n } else if (connection === \"open\") {\n this.reconnectAttempts = 0;\n console.log(\"[whatsapp] Connected\");\n }\n });\n\n this.socket.ev.on(\"creds.update\", saveCreds);\n\n this.socket.ev.on(\"messages.upsert\", async ({ messages, type }) => {\n if (type !== \"notify\") return;\n\n for (const msg of messages) {\n if (!msg.key?.remoteJid || msg.key.remoteJid === \"status@broadcast\" || msg.key.fromMe) continue;\n\n const text = msg.message?.conversation || msg.message?.extendedTextMessage?.text || \"\";\n if (!text) continue;\n\n const remoteJid = msg.key.remoteJid;\n const participantJid = msg.key.participant || remoteJid;\n const userId = participantJid.replace(\"@s.whatsapp.net\", \"\").replace(\":@lid\", \"\").replace(\"@lid\", \"\");\n\n // Check trusted contacts (takes priority over legacy allowedUsers)\n if (this.config.trustedContacts?.length) {\n const contact = this.findTrustedContact(userId);\n if (!contact) continue; // silently ignore unknown numbers\n if (contact.permission === \"read\") {\n await sendMessage(this.socket!, remoteJid, \"You have read-only access.\");\n continue;\n }\n // \"write\" and \"admin\" proceed to handler\n } else if (this.config.allowedUsers?.length) {\n // Legacy allowedUsers fallback\n const phone = `+${userId}`;\n const allowed = this.config.allowedUsers.some((u) => {\n const normalized = u.replace(/[\\s+]/g, \"\");\n return u === phone || u === userId || userId.includes(normalized);\n });\n if (!allowed) continue;\n }\n\n if (!this.handler) continue;\n\n await this.socket!.sendPresenceUpdate(\"composing\", remoteJid);\n\n try {\n const inbound: InboundMessage = {\n channelId: \"whatsapp\",\n userId,\n userName: msg.pushName || \"Unknown\",\n chatId: remoteJid,\n text,\n };\n\n const response = await this.handler(inbound);\n if (response) await sendMessage(this.socket!, remoteJid, response);\n } catch (err) {\n console.error(\"[whatsapp] Error handling message:\", err);\n await sendMessage(this.socket!, remoteJid, \"Sorry, an error occurred.\");\n } finally {\n await this.socket!.sendPresenceUpdate(\"paused\", remoteJid);\n }\n }\n });\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { useMultiFileAuthState } from \"@whiskeysockets/baileys\";\nimport QRCode from \"qrcode\";\n\nexport async function createAuthState(authDir: string) {\n if (!fs.existsSync(authDir)) {\n fs.mkdirSync(authDir, { recursive: true });\n }\n return useMultiFileAuthState(authDir);\n}\n\nexport async function generateQRCode(qrString: string): Promise<string> {\n return QRCode.toDataURL(qrString);\n}\n\nexport function isAuthenticated(authDir: string): boolean {\n return fs.existsSync(path.join(authDir, \"creds.json\"));\n}\n\nexport function clearAuthState(authDir: string): void {\n if (fs.existsSync(authDir)) {\n fs.rmSync(authDir, { recursive: true, force: true });\n }\n}\n","import type { WASocket } from \"@whiskeysockets/baileys\";\n\nexport function normalizeJID(phoneNumber: string): string {\n const cleaned = phoneNumber.replace(/\\D/g, \"\");\n return `${cleaned}@s.whatsapp.net`;\n}\n\nexport async function sendMessage(\n socket: WASocket,\n target: string,\n text: string,\n): Promise<void> {\n const jid = target.includes(\"@\") ? target : normalizeJID(target);\n await socket.sendPresenceUpdate(\"composing\", jid);\n await socket.sendMessage(jid, { text });\n await socket.sendPresenceUpdate(\"paused\", jid);\n}\n"],"mappings":"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","names":["splitMessage","path","path"]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@cortask/channels",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/cortask/cortask.git",
9
+ "directory": "packages/channels"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "dependencies": {
17
+ "@whiskeysockets/baileys": "7.0.0-rc.9",
18
+ "discord.js": "^14.25.1",
19
+ "grammy": "^1.35.0",
20
+ "qrcode": "^1.5.4",
21
+ "@cortask/core": "0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^22.0.0",
25
+ "@types/qrcode": "^1.5.6",
26
+ "tsup": "^8.3.0",
27
+ "typescript": "^5.7.0"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsup --watch",
32
+ "typecheck": "tsc --noEmit",
33
+ "clean": "rm -rf dist"
34
+ }
35
+ }