@operor/provider-telegram 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/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/package.json +21 -0
- package/src/TelegramProvider.ts +109 -0
- package/src/index.ts +2 -0
- package/tsconfig.json +9 -0
- package/tsdown.config.ts +10 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import EventEmitter from "eventemitter3";
|
|
2
|
+
import { MessageProvider, OutgoingMessage } from "@operor/core";
|
|
3
|
+
|
|
4
|
+
//#region src/TelegramProvider.d.ts
|
|
5
|
+
interface TelegramProviderConfig {
|
|
6
|
+
botToken: string;
|
|
7
|
+
/** Optional webhook URL. If not set, uses long polling. */
|
|
8
|
+
webhookUrl?: string;
|
|
9
|
+
}
|
|
10
|
+
declare class TelegramProvider extends EventEmitter implements MessageProvider {
|
|
11
|
+
readonly name = "telegram";
|
|
12
|
+
private bot;
|
|
13
|
+
private config;
|
|
14
|
+
private connected;
|
|
15
|
+
constructor(config: TelegramProviderConfig);
|
|
16
|
+
connect(): Promise<void>;
|
|
17
|
+
disconnect(): Promise<void>;
|
|
18
|
+
sendTypingIndicator(to: string): Promise<void>;
|
|
19
|
+
sendMessage(to: string, message: OutgoingMessage): Promise<void>;
|
|
20
|
+
isActive(): boolean;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { TelegramProvider, type TelegramProviderConfig };
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/TelegramProvider.ts"],"mappings":";;;;UAIiB,sBAAA;EACf,QAAA;EADe;EAGf,UAAA;AAAA;AAAA,cAGW,gBAAA,SAAyB,YAAA,YAAwB,eAAA;EAAA,SAC5C,IAAA;EAAA,QACR,GAAA;EAAA,QACA,MAAA;EAAA,QACA,SAAA;cAEI,MAAA,EAAQ,sBAAA;EAMd,OAAA,CAAA,GAAW,OAAA;EAoDX,UAAA,CAAA,GAAc,OAAA;EAMd,mBAAA,CAAoB,EAAA,WAAa,OAAA;EAWjC,WAAA,CAAY,EAAA,UAAY,OAAA,EAAS,eAAA,GAAkB,OAAA;EAczD,QAAA,CAAA;AAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import EventEmitter from "eventemitter3";
|
|
2
|
+
import { Bot } from "grammy";
|
|
3
|
+
|
|
4
|
+
//#region src/TelegramProvider.ts
|
|
5
|
+
var TelegramProvider = class extends EventEmitter {
|
|
6
|
+
name = "telegram";
|
|
7
|
+
bot;
|
|
8
|
+
config;
|
|
9
|
+
connected = false;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
super();
|
|
12
|
+
this.config = config;
|
|
13
|
+
this.bot = new Bot(config.botToken);
|
|
14
|
+
}
|
|
15
|
+
async connect() {
|
|
16
|
+
this.bot.on("message:text", (ctx) => {
|
|
17
|
+
const msg = {
|
|
18
|
+
id: String(ctx.message.message_id),
|
|
19
|
+
from: String(ctx.from?.id || ctx.chat.id),
|
|
20
|
+
text: ctx.message.text,
|
|
21
|
+
timestamp: ctx.message.date * 1e3,
|
|
22
|
+
channel: "telegram",
|
|
23
|
+
provider: this.name,
|
|
24
|
+
metadata: {
|
|
25
|
+
chatId: ctx.chat.id,
|
|
26
|
+
username: ctx.from?.username,
|
|
27
|
+
firstName: ctx.from?.first_name,
|
|
28
|
+
lastName: ctx.from?.last_name
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
console.log(`\nš„ [Telegram] New message from ${ctx.from?.first_name || ctx.from?.username || msg.from}`);
|
|
32
|
+
console.log(` Message: "${msg.text}"`);
|
|
33
|
+
this.emit("message", msg);
|
|
34
|
+
});
|
|
35
|
+
this.bot.catch((err) => {
|
|
36
|
+
console.error("ā [Telegram] Bot error:", err.message);
|
|
37
|
+
this.emit("error", err);
|
|
38
|
+
});
|
|
39
|
+
if (this.config.webhookUrl) {
|
|
40
|
+
await this.bot.api.setWebhook(this.config.webhookUrl);
|
|
41
|
+
console.log(`ā
Telegram bot connected (webhook: ${this.config.webhookUrl})`);
|
|
42
|
+
} else {
|
|
43
|
+
this.bot.start({ onStart: () => {
|
|
44
|
+
console.log("ā
Telegram bot connected (long polling)");
|
|
45
|
+
this.connected = true;
|
|
46
|
+
this.emit("ready");
|
|
47
|
+
} });
|
|
48
|
+
this.connected = true;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.connected = true;
|
|
52
|
+
this.emit("ready");
|
|
53
|
+
}
|
|
54
|
+
async disconnect() {
|
|
55
|
+
await this.bot.stop();
|
|
56
|
+
this.connected = false;
|
|
57
|
+
console.log("Telegram bot disconnected");
|
|
58
|
+
}
|
|
59
|
+
async sendTypingIndicator(to) {
|
|
60
|
+
if (!this.connected) return;
|
|
61
|
+
const chatId = parseInt(to, 10);
|
|
62
|
+
if (isNaN(chatId)) return;
|
|
63
|
+
try {
|
|
64
|
+
await this.bot.api.sendChatAction(chatId, "typing");
|
|
65
|
+
} catch {}
|
|
66
|
+
}
|
|
67
|
+
async sendMessage(to, message) {
|
|
68
|
+
if (!this.connected) throw new Error("Telegram bot not connected");
|
|
69
|
+
const chatId = parseInt(to, 10);
|
|
70
|
+
if (isNaN(chatId)) throw new Error(`Invalid Telegram chat ID: "${to}" ā must be numeric`);
|
|
71
|
+
await this.bot.api.sendMessage(chatId, message.text);
|
|
72
|
+
console.log(`š¤ [Telegram] Sent reply to ${to}`);
|
|
73
|
+
}
|
|
74
|
+
isActive() {
|
|
75
|
+
return this.connected;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
export { TelegramProvider };
|
|
81
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/TelegramProvider.ts"],"sourcesContent":["import EventEmitter from 'eventemitter3';\nimport { Bot } from 'grammy';\nimport type { MessageProvider, IncomingMessage, OutgoingMessage } from '@operor/core';\n\nexport interface TelegramProviderConfig {\n botToken: string;\n /** Optional webhook URL. If not set, uses long polling. */\n webhookUrl?: string;\n}\n\nexport class TelegramProvider extends EventEmitter implements MessageProvider {\n public readonly name = 'telegram';\n private bot: Bot;\n private config: TelegramProviderConfig;\n private connected = false;\n\n constructor(config: TelegramProviderConfig) {\n super();\n this.config = config;\n this.bot = new Bot(config.botToken);\n }\n\n async connect(): Promise<void> {\n // Listen for text messages\n this.bot.on('message:text', (ctx) => {\n const msg: IncomingMessage = {\n id: String(ctx.message.message_id),\n from: String(ctx.from?.id || ctx.chat.id),\n text: ctx.message.text,\n timestamp: ctx.message.date * 1000,\n channel: 'telegram',\n provider: this.name,\n metadata: {\n chatId: ctx.chat.id,\n username: ctx.from?.username,\n firstName: ctx.from?.first_name,\n lastName: ctx.from?.last_name,\n },\n };\n\n console.log(`\\nš„ [Telegram] New message from ${ctx.from?.first_name || ctx.from?.username || msg.from}`);\n console.log(` Message: \"${msg.text}\"`);\n\n this.emit('message', msg);\n });\n\n // Error handling\n this.bot.catch((err) => {\n console.error('ā [Telegram] Bot error:', err.message);\n this.emit('error', err);\n });\n\n // Start bot\n if (this.config.webhookUrl) {\n await this.bot.api.setWebhook(this.config.webhookUrl);\n console.log(`ā
Telegram bot connected (webhook: ${this.config.webhookUrl})`);\n } else {\n // Long polling for development ā non-blocking start\n this.bot.start({\n onStart: () => {\n console.log('ā
Telegram bot connected (long polling)');\n this.connected = true;\n this.emit('ready');\n },\n });\n // bot.start() is non-blocking in grammY, but onStart fires after first poll\n this.connected = true;\n return;\n }\n\n this.connected = true;\n this.emit('ready');\n }\n\n async disconnect(): Promise<void> {\n await this.bot.stop();\n this.connected = false;\n console.log('Telegram bot disconnected');\n }\n\n async sendTypingIndicator(to: string): Promise<void> {\n if (!this.connected) return;\n const chatId = parseInt(to, 10);\n if (isNaN(chatId)) return;\n try {\n await this.bot.api.sendChatAction(chatId, 'typing');\n } catch {\n // Non-critical ā silently ignore failures\n }\n }\n\n async sendMessage(to: string, message: OutgoingMessage): Promise<void> {\n if (!this.connected) {\n throw new Error('Telegram bot not connected');\n }\n\n const chatId = parseInt(to, 10);\n if (isNaN(chatId)) {\n throw new Error(`Invalid Telegram chat ID: \"${to}\" ā must be numeric`);\n }\n await this.bot.api.sendMessage(chatId, message.text);\n\n console.log(`š¤ [Telegram] Sent reply to ${to}`);\n }\n\n isActive(): boolean {\n return this.connected;\n }\n}\n"],"mappings":";;;;AAUA,IAAa,mBAAb,cAAsC,aAAwC;CAC5E,AAAgB,OAAO;CACvB,AAAQ;CACR,AAAQ;CACR,AAAQ,YAAY;CAEpB,YAAY,QAAgC;AAC1C,SAAO;AACP,OAAK,SAAS;AACd,OAAK,MAAM,IAAI,IAAI,OAAO,SAAS;;CAGrC,MAAM,UAAyB;AAE7B,OAAK,IAAI,GAAG,iBAAiB,QAAQ;GACnC,MAAM,MAAuB;IAC3B,IAAI,OAAO,IAAI,QAAQ,WAAW;IAClC,MAAM,OAAO,IAAI,MAAM,MAAM,IAAI,KAAK,GAAG;IACzC,MAAM,IAAI,QAAQ;IAClB,WAAW,IAAI,QAAQ,OAAO;IAC9B,SAAS;IACT,UAAU,KAAK;IACf,UAAU;KACR,QAAQ,IAAI,KAAK;KACjB,UAAU,IAAI,MAAM;KACpB,WAAW,IAAI,MAAM;KACrB,UAAU,IAAI,MAAM;KACrB;IACF;AAED,WAAQ,IAAI,oCAAoC,IAAI,MAAM,cAAc,IAAI,MAAM,YAAY,IAAI,OAAO;AACzG,WAAQ,IAAI,gBAAgB,IAAI,KAAK,GAAG;AAExC,QAAK,KAAK,WAAW,IAAI;IACzB;AAGF,OAAK,IAAI,OAAO,QAAQ;AACtB,WAAQ,MAAM,2BAA2B,IAAI,QAAQ;AACrD,QAAK,KAAK,SAAS,IAAI;IACvB;AAGF,MAAI,KAAK,OAAO,YAAY;AAC1B,SAAM,KAAK,IAAI,IAAI,WAAW,KAAK,OAAO,WAAW;AACrD,WAAQ,IAAI,sCAAsC,KAAK,OAAO,WAAW,GAAG;SACvE;AAEL,QAAK,IAAI,MAAM,EACb,eAAe;AACb,YAAQ,IAAI,0CAA0C;AACtD,SAAK,YAAY;AACjB,SAAK,KAAK,QAAQ;MAErB,CAAC;AAEF,QAAK,YAAY;AACjB;;AAGF,OAAK,YAAY;AACjB,OAAK,KAAK,QAAQ;;CAGpB,MAAM,aAA4B;AAChC,QAAM,KAAK,IAAI,MAAM;AACrB,OAAK,YAAY;AACjB,UAAQ,IAAI,4BAA4B;;CAG1C,MAAM,oBAAoB,IAA2B;AACnD,MAAI,CAAC,KAAK,UAAW;EACrB,MAAM,SAAS,SAAS,IAAI,GAAG;AAC/B,MAAI,MAAM,OAAO,CAAE;AACnB,MAAI;AACF,SAAM,KAAK,IAAI,IAAI,eAAe,QAAQ,SAAS;UAC7C;;CAKV,MAAM,YAAY,IAAY,SAAyC;AACrE,MAAI,CAAC,KAAK,UACR,OAAM,IAAI,MAAM,6BAA6B;EAG/C,MAAM,SAAS,SAAS,IAAI,GAAG;AAC/B,MAAI,MAAM,OAAO,CACf,OAAM,IAAI,MAAM,8BAA8B,GAAG,qBAAqB;AAExE,QAAM,KAAK,IAAI,IAAI,YAAY,QAAQ,QAAQ,KAAK;AAEpD,UAAQ,IAAI,+BAA+B,KAAK;;CAGlD,WAAoB;AAClB,SAAO,KAAK"}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@operor/provider-telegram",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Telegram provider for Agent OS using grammY",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"eventemitter3": "^5.0.1",
|
|
10
|
+
"grammy": "^1.35.0",
|
|
11
|
+
"@operor/core": "0.1.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"tsdown": "^0.20.3",
|
|
15
|
+
"typescript": "^5.3.3"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsdown",
|
|
19
|
+
"dev": "tsdown --watch"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import EventEmitter from 'eventemitter3';
|
|
2
|
+
import { Bot } from 'grammy';
|
|
3
|
+
import type { MessageProvider, IncomingMessage, OutgoingMessage } from '@operor/core';
|
|
4
|
+
|
|
5
|
+
export interface TelegramProviderConfig {
|
|
6
|
+
botToken: string;
|
|
7
|
+
/** Optional webhook URL. If not set, uses long polling. */
|
|
8
|
+
webhookUrl?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class TelegramProvider extends EventEmitter implements MessageProvider {
|
|
12
|
+
public readonly name = 'telegram';
|
|
13
|
+
private bot: Bot;
|
|
14
|
+
private config: TelegramProviderConfig;
|
|
15
|
+
private connected = false;
|
|
16
|
+
|
|
17
|
+
constructor(config: TelegramProviderConfig) {
|
|
18
|
+
super();
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.bot = new Bot(config.botToken);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async connect(): Promise<void> {
|
|
24
|
+
// Listen for text messages
|
|
25
|
+
this.bot.on('message:text', (ctx) => {
|
|
26
|
+
const msg: IncomingMessage = {
|
|
27
|
+
id: String(ctx.message.message_id),
|
|
28
|
+
from: String(ctx.from?.id || ctx.chat.id),
|
|
29
|
+
text: ctx.message.text,
|
|
30
|
+
timestamp: ctx.message.date * 1000,
|
|
31
|
+
channel: 'telegram',
|
|
32
|
+
provider: this.name,
|
|
33
|
+
metadata: {
|
|
34
|
+
chatId: ctx.chat.id,
|
|
35
|
+
username: ctx.from?.username,
|
|
36
|
+
firstName: ctx.from?.first_name,
|
|
37
|
+
lastName: ctx.from?.last_name,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
console.log(`\nš„ [Telegram] New message from ${ctx.from?.first_name || ctx.from?.username || msg.from}`);
|
|
42
|
+
console.log(` Message: "${msg.text}"`);
|
|
43
|
+
|
|
44
|
+
this.emit('message', msg);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Error handling
|
|
48
|
+
this.bot.catch((err) => {
|
|
49
|
+
console.error('ā [Telegram] Bot error:', err.message);
|
|
50
|
+
this.emit('error', err);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Start bot
|
|
54
|
+
if (this.config.webhookUrl) {
|
|
55
|
+
await this.bot.api.setWebhook(this.config.webhookUrl);
|
|
56
|
+
console.log(`ā
Telegram bot connected (webhook: ${this.config.webhookUrl})`);
|
|
57
|
+
} else {
|
|
58
|
+
// Long polling for development ā non-blocking start
|
|
59
|
+
this.bot.start({
|
|
60
|
+
onStart: () => {
|
|
61
|
+
console.log('ā
Telegram bot connected (long polling)');
|
|
62
|
+
this.connected = true;
|
|
63
|
+
this.emit('ready');
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
// bot.start() is non-blocking in grammY, but onStart fires after first poll
|
|
67
|
+
this.connected = true;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.connected = true;
|
|
72
|
+
this.emit('ready');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async disconnect(): Promise<void> {
|
|
76
|
+
await this.bot.stop();
|
|
77
|
+
this.connected = false;
|
|
78
|
+
console.log('Telegram bot disconnected');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async sendTypingIndicator(to: string): Promise<void> {
|
|
82
|
+
if (!this.connected) return;
|
|
83
|
+
const chatId = parseInt(to, 10);
|
|
84
|
+
if (isNaN(chatId)) return;
|
|
85
|
+
try {
|
|
86
|
+
await this.bot.api.sendChatAction(chatId, 'typing');
|
|
87
|
+
} catch {
|
|
88
|
+
// Non-critical ā silently ignore failures
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async sendMessage(to: string, message: OutgoingMessage): Promise<void> {
|
|
93
|
+
if (!this.connected) {
|
|
94
|
+
throw new Error('Telegram bot not connected');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const chatId = parseInt(to, 10);
|
|
98
|
+
if (isNaN(chatId)) {
|
|
99
|
+
throw new Error(`Invalid Telegram chat ID: "${to}" ā must be numeric`);
|
|
100
|
+
}
|
|
101
|
+
await this.bot.api.sendMessage(chatId, message.text);
|
|
102
|
+
|
|
103
|
+
console.log(`š¤ [Telegram] Sent reply to ${to}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
isActive(): boolean {
|
|
107
|
+
return this.connected;
|
|
108
|
+
}
|
|
109
|
+
}
|
package/src/index.ts
ADDED
package/tsconfig.json
ADDED