crewly 1.4.2 → 1.4.4
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/config/skills/orchestrator/reply-gchat/execute.sh +4 -4
- package/config/templates/dev-fullstack/norms/docker-deploy-cleanup.md +28 -0
- package/dist/backend/backend/src/constants.d.ts +45 -14
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +45 -14
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +14 -3
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts +15 -3
- package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/relay.controller.js +46 -8
- package/dist/backend/backend/src/controllers/cloud/relay.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/relay.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/relay.routes.js +2 -1
- package/dist/backend/backend/src/controllers/cloud/relay.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +86 -3
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +5 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +33 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +27 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js +28 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts +47 -44
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-client.service.js +185 -152
- package/dist/backend/backend/src/services/cloud/relay-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-server.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay-server.service.js +3 -12
- package/dist/backend/backend/src/services/cloud/relay-server.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay.types.d.ts +27 -4
- package/dist/backend/backend/src/services/cloud/relay.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/relay.types.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts +16 -8
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js +30 -35
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/response-router.service.d.ts +8 -0
- package/dist/backend/backend/src/services/messaging/response-router.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/response-router.service.js +16 -0
- package/dist/backend/backend/src/services/messaging/response-router.service.js.map +1 -1
- package/dist/backend/backend/src/services/telegram/index.d.ts +14 -0
- package/dist/backend/backend/src/services/telegram/index.d.ts.map +1 -0
- package/dist/backend/backend/src/services/telegram/index.js +11 -0
- package/dist/backend/backend/src/services/telegram/index.js.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-credentials.service.d.ts +54 -0
- package/dist/backend/backend/src/services/telegram/telegram-credentials.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-credentials.service.js +98 -0
- package/dist/backend/backend/src/services/telegram/telegram-credentials.service.js.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-initializer.d.ts +76 -0
- package/dist/backend/backend/src/services/telegram/telegram-initializer.d.ts.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-initializer.js +131 -0
- package/dist/backend/backend/src/services/telegram/telegram-initializer.js.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts +73 -0
- package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js +172 -0
- package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.d.ts +86 -0
- package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.js +157 -0
- package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.js.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram.service.d.ts +173 -0
- package/dist/backend/backend/src/services/telegram/telegram.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/telegram/telegram.service.js +304 -0
- package/dist/backend/backend/src/services/telegram/telegram.service.js.map +1 -0
- package/dist/cli/backend/src/constants.d.ts +45 -14
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +45 -14
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/cli/src/commands/migrate.d.ts +101 -0
- package/dist/cli/cli/src/commands/migrate.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/migrate.js +335 -0
- package/dist/cli/cli/src/commands/migrate.js.map +1 -0
- package/dist/cli/cli/src/index.js +8 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/frontend/dist/assets/{index-f1dc9f80.css → index-2b76b01d.css} +1 -1
- package/frontend/dist/assets/{index-c35cdbc5.js → index-83869ca7.js} +321 -321
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram Thread Store Service
|
|
3
|
+
*
|
|
4
|
+
* Persists Telegram chat conversations as markdown files so the
|
|
5
|
+
* orchestrator can read conversation history after restart.
|
|
6
|
+
*
|
|
7
|
+
* Storage layout:
|
|
8
|
+
* ~/.crewly/telegram-threads/
|
|
9
|
+
* {chatId}.md — Chat conversation file
|
|
10
|
+
*
|
|
11
|
+
* @module services/telegram/telegram-thread-store
|
|
12
|
+
*/
|
|
13
|
+
import { promises as fs } from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import os from 'os';
|
|
16
|
+
import { formatMessageTimestamp } from '../../utils/format-date.js';
|
|
17
|
+
/** Storage directory name for Telegram threads */
|
|
18
|
+
const STORAGE_DIR = 'telegram-threads';
|
|
19
|
+
/** File extension for thread files */
|
|
20
|
+
const FILE_EXTENSION = '.md';
|
|
21
|
+
/**
|
|
22
|
+
* TelegramThreadStoreService manages persistent storage of Telegram
|
|
23
|
+
* chat conversations as markdown files.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const store = new TelegramThreadStoreService();
|
|
28
|
+
* await store.appendUserMessage('12345', 'Alice', 'Hello bot!');
|
|
29
|
+
* await store.appendBotReply('12345', 'Hello Alice!');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class TelegramThreadStoreService {
|
|
33
|
+
baseDir;
|
|
34
|
+
/**
|
|
35
|
+
* Create a new TelegramThreadStoreService.
|
|
36
|
+
*
|
|
37
|
+
* @param crewlyHome - Base crewly home directory (defaults to ~/.crewly)
|
|
38
|
+
*/
|
|
39
|
+
constructor(crewlyHome) {
|
|
40
|
+
const home = crewlyHome || path.join(os.homedir(), '.crewly');
|
|
41
|
+
this.baseDir = path.join(home, STORAGE_DIR);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compute the file path for a chat conversation file.
|
|
45
|
+
*
|
|
46
|
+
* @param chatId - Telegram chat ID
|
|
47
|
+
* @returns Absolute path to the chat markdown file
|
|
48
|
+
*/
|
|
49
|
+
getChatFilePath(chatId) {
|
|
50
|
+
// Sanitize chatId (remove any non-alphanumeric/dash/underscore characters)
|
|
51
|
+
const safeChatId = chatId.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
52
|
+
return path.join(this.baseDir, `${safeChatId}${FILE_EXTENSION}`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Ensure the chat file exists, creating it with frontmatter if needed.
|
|
56
|
+
*
|
|
57
|
+
* @param chatId - Telegram chat ID
|
|
58
|
+
* @param userName - Name of the user who started the conversation
|
|
59
|
+
* @returns Absolute path to the chat file
|
|
60
|
+
*/
|
|
61
|
+
async ensureChatFile(chatId, userName) {
|
|
62
|
+
const filePath = this.getChatFilePath(chatId);
|
|
63
|
+
const dir = path.dirname(filePath);
|
|
64
|
+
await fs.mkdir(dir, { recursive: true });
|
|
65
|
+
try {
|
|
66
|
+
await fs.access(filePath);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// File doesn't exist — create with frontmatter
|
|
70
|
+
const frontmatter = [
|
|
71
|
+
'---',
|
|
72
|
+
`chatId: ${chatId}`,
|
|
73
|
+
`user: ${userName}`,
|
|
74
|
+
`started: ${new Date().toISOString()}`,
|
|
75
|
+
'---',
|
|
76
|
+
'',
|
|
77
|
+
'## Messages',
|
|
78
|
+
'',
|
|
79
|
+
].join('\n');
|
|
80
|
+
await fs.writeFile(filePath, frontmatter, 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
return filePath;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Append a user message to the chat conversation file.
|
|
86
|
+
*
|
|
87
|
+
* @param chatId - Telegram chat ID
|
|
88
|
+
* @param userName - Display name of the sender
|
|
89
|
+
* @param message - Message content
|
|
90
|
+
*/
|
|
91
|
+
async appendUserMessage(chatId, userName, message) {
|
|
92
|
+
const filePath = await this.ensureChatFile(chatId, userName);
|
|
93
|
+
const timestamp = formatMessageTimestamp();
|
|
94
|
+
const entry = `\n**${userName}** (${timestamp}):\n${message}\n`;
|
|
95
|
+
await fs.appendFile(filePath, entry, 'utf-8');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Append a bot reply to the chat conversation file.
|
|
99
|
+
*
|
|
100
|
+
* @param chatId - Telegram chat ID
|
|
101
|
+
* @param message - Bot response content
|
|
102
|
+
*/
|
|
103
|
+
async appendBotReply(chatId, message) {
|
|
104
|
+
const filePath = this.getChatFilePath(chatId);
|
|
105
|
+
try {
|
|
106
|
+
await fs.access(filePath);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Chat file doesn't exist — skip silently
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const timestamp = formatMessageTimestamp();
|
|
113
|
+
const entry = `\n**Crewly** (${timestamp}):\n${message}\n`;
|
|
114
|
+
await fs.appendFile(filePath, entry, 'utf-8');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Read the latest conversation thread file path for a given chat.
|
|
118
|
+
*
|
|
119
|
+
* @param chatId - Telegram chat ID
|
|
120
|
+
* @returns Path to the thread file, or null if not found
|
|
121
|
+
*/
|
|
122
|
+
async getLatestThreadPath(chatId) {
|
|
123
|
+
const filePath = this.getChatFilePath(chatId);
|
|
124
|
+
try {
|
|
125
|
+
await fs.access(filePath);
|
|
126
|
+
return filePath;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Singleton instance */
|
|
134
|
+
let instance = null;
|
|
135
|
+
/**
|
|
136
|
+
* Get the TelegramThreadStoreService singleton.
|
|
137
|
+
*
|
|
138
|
+
* @returns The service instance or null if not initialized
|
|
139
|
+
*/
|
|
140
|
+
export function getTelegramThreadStore() {
|
|
141
|
+
return instance;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Set the TelegramThreadStoreService singleton.
|
|
145
|
+
*
|
|
146
|
+
* @param store - The service instance to set
|
|
147
|
+
*/
|
|
148
|
+
export function setTelegramThreadStore(store) {
|
|
149
|
+
instance = store;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Reset the TelegramThreadStoreService singleton (for testing).
|
|
153
|
+
*/
|
|
154
|
+
export function resetTelegramThreadStore() {
|
|
155
|
+
instance = null;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=telegram-thread-store.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram-thread-store.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram-thread-store.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram Service
|
|
3
|
+
*
|
|
4
|
+
* Core service for Telegram Bot API integration with long-polling
|
|
5
|
+
* for incoming messages. Manages bot lifecycle, incoming message
|
|
6
|
+
* polling, and outgoing message delivery.
|
|
7
|
+
*
|
|
8
|
+
* @module services/telegram/telegram
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import type { TelegramConfig } from './telegram-credentials.service.js';
|
|
12
|
+
/**
|
|
13
|
+
* Telegram Bot API Update object (simplified).
|
|
14
|
+
*/
|
|
15
|
+
export interface TelegramUpdate {
|
|
16
|
+
/** Unique update identifier */
|
|
17
|
+
update_id: number;
|
|
18
|
+
/** Incoming message (present when a text message is received) */
|
|
19
|
+
message?: TelegramMessage;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Telegram Bot API Message object (simplified).
|
|
23
|
+
*/
|
|
24
|
+
export interface TelegramMessage {
|
|
25
|
+
/** Unique message identifier */
|
|
26
|
+
message_id: number;
|
|
27
|
+
/** Sender information */
|
|
28
|
+
from?: {
|
|
29
|
+
id: number;
|
|
30
|
+
is_bot: boolean;
|
|
31
|
+
first_name: string;
|
|
32
|
+
last_name?: string;
|
|
33
|
+
username?: string;
|
|
34
|
+
};
|
|
35
|
+
/** Chat information */
|
|
36
|
+
chat: {
|
|
37
|
+
id: number;
|
|
38
|
+
type: 'private' | 'group' | 'supergroup' | 'channel';
|
|
39
|
+
title?: string;
|
|
40
|
+
first_name?: string;
|
|
41
|
+
last_name?: string;
|
|
42
|
+
username?: string;
|
|
43
|
+
};
|
|
44
|
+
/** Date the message was sent (Unix timestamp) */
|
|
45
|
+
date: number;
|
|
46
|
+
/** Message text */
|
|
47
|
+
text?: string;
|
|
48
|
+
/** If the message is a reply, the original message */
|
|
49
|
+
reply_to_message?: TelegramMessage;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Incoming message event payload emitted by TelegramService.
|
|
53
|
+
*/
|
|
54
|
+
export interface TelegramIncomingMessage {
|
|
55
|
+
/** Telegram chat ID */
|
|
56
|
+
chatId: string;
|
|
57
|
+
/** Telegram message ID */
|
|
58
|
+
messageId: number;
|
|
59
|
+
/** Sender user ID */
|
|
60
|
+
userId: string;
|
|
61
|
+
/** Sender display name */
|
|
62
|
+
userName: string;
|
|
63
|
+
/** Message text content */
|
|
64
|
+
text: string;
|
|
65
|
+
/** Unix timestamp */
|
|
66
|
+
timestamp: number;
|
|
67
|
+
/** Reply-to message ID (if replying) */
|
|
68
|
+
replyToMessageId?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* TelegramService manages the Telegram Bot API connection, incoming
|
|
72
|
+
* message polling via getUpdates, and outgoing message delivery.
|
|
73
|
+
*
|
|
74
|
+
* Events:
|
|
75
|
+
* - 'message' — Emitted when a text message is received
|
|
76
|
+
* - 'error' — Emitted on polling errors
|
|
77
|
+
* - 'connected' — Emitted when polling starts
|
|
78
|
+
* - 'disconnected' — Emitted when polling stops
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const service = getTelegramService();
|
|
83
|
+
* await service.initialize({ botToken: 'BOT_TOKEN' });
|
|
84
|
+
* service.on('message', (msg) => console.log(msg.text));
|
|
85
|
+
* service.startPolling();
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare class TelegramService extends EventEmitter {
|
|
89
|
+
private logger;
|
|
90
|
+
private config;
|
|
91
|
+
private botInfo;
|
|
92
|
+
private polling;
|
|
93
|
+
private pollTimer;
|
|
94
|
+
private lastUpdateOffset;
|
|
95
|
+
private consecutiveFailures;
|
|
96
|
+
private connected;
|
|
97
|
+
constructor();
|
|
98
|
+
/**
|
|
99
|
+
* Initialize the Telegram service by validating the bot token.
|
|
100
|
+
*
|
|
101
|
+
* @param config - Telegram configuration with bot token
|
|
102
|
+
* @throws Error if token is invalid or validation fails
|
|
103
|
+
*/
|
|
104
|
+
initialize(config: TelegramConfig): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Start long-polling for incoming messages.
|
|
107
|
+
* Emits 'message' events for each incoming text message.
|
|
108
|
+
*/
|
|
109
|
+
startPolling(): void;
|
|
110
|
+
/**
|
|
111
|
+
* Stop polling for incoming messages.
|
|
112
|
+
*/
|
|
113
|
+
stopPolling(): void;
|
|
114
|
+
/**
|
|
115
|
+
* Send a text message to a Telegram chat.
|
|
116
|
+
*
|
|
117
|
+
* @param chatId - Telegram chat ID
|
|
118
|
+
* @param text - Message content
|
|
119
|
+
* @param replyToMessageId - Optional message ID to reply to
|
|
120
|
+
* @returns The sent message ID
|
|
121
|
+
* @throws Error if service is not initialized or send fails
|
|
122
|
+
*/
|
|
123
|
+
sendMessage(chatId: string, text: string, replyToMessageId?: number): Promise<number>;
|
|
124
|
+
/**
|
|
125
|
+
* Check if the service is currently connected and polling.
|
|
126
|
+
*
|
|
127
|
+
* @returns True if polling is active
|
|
128
|
+
*/
|
|
129
|
+
isConnected(): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Get the current service status.
|
|
132
|
+
*
|
|
133
|
+
* @returns Status object with connection state and bot info
|
|
134
|
+
*/
|
|
135
|
+
getStatus(): Record<string, unknown>;
|
|
136
|
+
/**
|
|
137
|
+
* Disconnect the service and stop polling.
|
|
138
|
+
*/
|
|
139
|
+
disconnect(): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Get the bot's username.
|
|
142
|
+
*
|
|
143
|
+
* @returns Bot username or null if not initialized
|
|
144
|
+
*/
|
|
145
|
+
getBotUsername(): string | null;
|
|
146
|
+
/**
|
|
147
|
+
* Internal polling loop. Calls getUpdates and schedules next poll.
|
|
148
|
+
*/
|
|
149
|
+
private poll;
|
|
150
|
+
/**
|
|
151
|
+
* Call the Telegram getUpdates API with long polling.
|
|
152
|
+
*
|
|
153
|
+
* @returns Array of updates
|
|
154
|
+
*/
|
|
155
|
+
private getUpdates;
|
|
156
|
+
/**
|
|
157
|
+
* Process a single Telegram update and emit events.
|
|
158
|
+
*
|
|
159
|
+
* @param update - The update to process
|
|
160
|
+
*/
|
|
161
|
+
private processUpdate;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get the TelegramService singleton.
|
|
165
|
+
*
|
|
166
|
+
* @returns The service instance
|
|
167
|
+
*/
|
|
168
|
+
export declare function getTelegramService(): TelegramService;
|
|
169
|
+
/**
|
|
170
|
+
* Reset the TelegramService singleton (for testing).
|
|
171
|
+
*/
|
|
172
|
+
export declare function resetTelegramService(): void;
|
|
173
|
+
//# sourceMappingURL=telegram.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram Service
|
|
3
|
+
*
|
|
4
|
+
* Core service for Telegram Bot API integration with long-polling
|
|
5
|
+
* for incoming messages. Manages bot lifecycle, incoming message
|
|
6
|
+
* polling, and outgoing message delivery.
|
|
7
|
+
*
|
|
8
|
+
* @module services/telegram/telegram
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { TELEGRAM_CONSTANTS } from '../../constants.js';
|
|
12
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
13
|
+
import { formatError } from '../../utils/format-error.js';
|
|
14
|
+
/**
|
|
15
|
+
* TelegramService manages the Telegram Bot API connection, incoming
|
|
16
|
+
* message polling via getUpdates, and outgoing message delivery.
|
|
17
|
+
*
|
|
18
|
+
* Events:
|
|
19
|
+
* - 'message' — Emitted when a text message is received
|
|
20
|
+
* - 'error' — Emitted on polling errors
|
|
21
|
+
* - 'connected' — Emitted when polling starts
|
|
22
|
+
* - 'disconnected' — Emitted when polling stops
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const service = getTelegramService();
|
|
27
|
+
* await service.initialize({ botToken: 'BOT_TOKEN' });
|
|
28
|
+
* service.on('message', (msg) => console.log(msg.text));
|
|
29
|
+
* service.startPolling();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class TelegramService extends EventEmitter {
|
|
33
|
+
logger;
|
|
34
|
+
config = null;
|
|
35
|
+
botInfo = null;
|
|
36
|
+
polling = false;
|
|
37
|
+
pollTimer = null;
|
|
38
|
+
lastUpdateOffset = 0;
|
|
39
|
+
consecutiveFailures = 0;
|
|
40
|
+
connected = false;
|
|
41
|
+
constructor() {
|
|
42
|
+
super();
|
|
43
|
+
this.logger = LoggerService.getInstance().createComponentLogger('TelegramService');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Initialize the Telegram service by validating the bot token.
|
|
47
|
+
*
|
|
48
|
+
* @param config - Telegram configuration with bot token
|
|
49
|
+
* @throws Error if token is invalid or validation fails
|
|
50
|
+
*/
|
|
51
|
+
async initialize(config) {
|
|
52
|
+
if (!config.botToken) {
|
|
53
|
+
throw new Error('Telegram bot token is required');
|
|
54
|
+
}
|
|
55
|
+
// Validate token via getMe
|
|
56
|
+
const resp = await fetch(`${TELEGRAM_CONSTANTS.API_BASE}${config.botToken}/getMe`, {
|
|
57
|
+
signal: AbortSignal.timeout(TELEGRAM_CONSTANTS.FETCH_TIMEOUT_MS),
|
|
58
|
+
});
|
|
59
|
+
if (!resp.ok) {
|
|
60
|
+
throw new Error(`Telegram token validation failed (HTTP ${resp.status})`);
|
|
61
|
+
}
|
|
62
|
+
const data = (await resp.json());
|
|
63
|
+
if (!data.ok || !data.result) {
|
|
64
|
+
throw new Error(data.description || 'Telegram token validation failed');
|
|
65
|
+
}
|
|
66
|
+
this.config = config;
|
|
67
|
+
this.botInfo = { id: data.result.id, username: data.result.username };
|
|
68
|
+
this.logger.info('Telegram bot validated', { username: data.result.username });
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Start long-polling for incoming messages.
|
|
72
|
+
* Emits 'message' events for each incoming text message.
|
|
73
|
+
*/
|
|
74
|
+
startPolling() {
|
|
75
|
+
if (this.polling) {
|
|
76
|
+
this.logger.warn('Polling already active');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!this.config) {
|
|
80
|
+
throw new Error('TelegramService not initialized — call initialize() first');
|
|
81
|
+
}
|
|
82
|
+
this.polling = true;
|
|
83
|
+
this.connected = true;
|
|
84
|
+
this.consecutiveFailures = 0;
|
|
85
|
+
this.emit('connected');
|
|
86
|
+
this.logger.info('Polling started');
|
|
87
|
+
this.poll();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Stop polling for incoming messages.
|
|
91
|
+
*/
|
|
92
|
+
stopPolling() {
|
|
93
|
+
this.polling = false;
|
|
94
|
+
this.connected = false;
|
|
95
|
+
if (this.pollTimer) {
|
|
96
|
+
clearTimeout(this.pollTimer);
|
|
97
|
+
this.pollTimer = null;
|
|
98
|
+
}
|
|
99
|
+
this.emit('disconnected');
|
|
100
|
+
this.logger.info('Polling stopped');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Send a text message to a Telegram chat.
|
|
104
|
+
*
|
|
105
|
+
* @param chatId - Telegram chat ID
|
|
106
|
+
* @param text - Message content
|
|
107
|
+
* @param replyToMessageId - Optional message ID to reply to
|
|
108
|
+
* @returns The sent message ID
|
|
109
|
+
* @throws Error if service is not initialized or send fails
|
|
110
|
+
*/
|
|
111
|
+
async sendMessage(chatId, text, replyToMessageId) {
|
|
112
|
+
if (!this.config) {
|
|
113
|
+
throw new Error('TelegramService not initialized');
|
|
114
|
+
}
|
|
115
|
+
// Truncate message if too long
|
|
116
|
+
const truncatedText = text.length > TELEGRAM_CONSTANTS.MAX_MESSAGE_LENGTH
|
|
117
|
+
? text.slice(0, TELEGRAM_CONSTANTS.MAX_MESSAGE_LENGTH - 20) + '\n\n...(truncated)'
|
|
118
|
+
: text;
|
|
119
|
+
const body = {
|
|
120
|
+
chat_id: chatId,
|
|
121
|
+
text: truncatedText,
|
|
122
|
+
parse_mode: 'Markdown',
|
|
123
|
+
};
|
|
124
|
+
if (replyToMessageId) {
|
|
125
|
+
body.reply_to_message_id = replyToMessageId;
|
|
126
|
+
}
|
|
127
|
+
const resp = await fetch(`${TELEGRAM_CONSTANTS.API_BASE}${this.config.botToken}/sendMessage`, {
|
|
128
|
+
method: 'POST',
|
|
129
|
+
headers: { 'Content-Type': 'application/json' },
|
|
130
|
+
body: JSON.stringify(body),
|
|
131
|
+
signal: AbortSignal.timeout(TELEGRAM_CONSTANTS.FETCH_TIMEOUT_MS),
|
|
132
|
+
});
|
|
133
|
+
if (!resp.ok) {
|
|
134
|
+
const details = await resp.text();
|
|
135
|
+
throw new Error(`Telegram send failed (${resp.status}): ${details}`);
|
|
136
|
+
}
|
|
137
|
+
const data = (await resp.json());
|
|
138
|
+
return data.result?.message_id ?? 0;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if the service is currently connected and polling.
|
|
142
|
+
*
|
|
143
|
+
* @returns True if polling is active
|
|
144
|
+
*/
|
|
145
|
+
isConnected() {
|
|
146
|
+
return this.connected && this.polling;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get the current service status.
|
|
150
|
+
*
|
|
151
|
+
* @returns Status object with connection state and bot info
|
|
152
|
+
*/
|
|
153
|
+
getStatus() {
|
|
154
|
+
return {
|
|
155
|
+
connected: this.isConnected(),
|
|
156
|
+
polling: this.polling,
|
|
157
|
+
botUsername: this.botInfo?.username ?? null,
|
|
158
|
+
botId: this.botInfo?.id ?? null,
|
|
159
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
160
|
+
lastUpdateOffset: this.lastUpdateOffset,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Disconnect the service and stop polling.
|
|
165
|
+
*/
|
|
166
|
+
async disconnect() {
|
|
167
|
+
this.stopPolling();
|
|
168
|
+
this.config = null;
|
|
169
|
+
this.botInfo = null;
|
|
170
|
+
this.lastUpdateOffset = 0;
|
|
171
|
+
this.consecutiveFailures = 0;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get the bot's username.
|
|
175
|
+
*
|
|
176
|
+
* @returns Bot username or null if not initialized
|
|
177
|
+
*/
|
|
178
|
+
getBotUsername() {
|
|
179
|
+
return this.botInfo?.username ?? null;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Internal polling loop. Calls getUpdates and schedules next poll.
|
|
183
|
+
*/
|
|
184
|
+
async poll() {
|
|
185
|
+
if (!this.polling || !this.config)
|
|
186
|
+
return;
|
|
187
|
+
try {
|
|
188
|
+
const updates = await this.getUpdates();
|
|
189
|
+
this.consecutiveFailures = 0;
|
|
190
|
+
for (const update of updates) {
|
|
191
|
+
this.processUpdate(update);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
this.consecutiveFailures++;
|
|
196
|
+
this.logger.error('Polling error', {
|
|
197
|
+
error: formatError(error),
|
|
198
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
199
|
+
});
|
|
200
|
+
this.emit('error', error);
|
|
201
|
+
if (this.consecutiveFailures >= TELEGRAM_CONSTANTS.MAX_CONSECUTIVE_FAILURES) {
|
|
202
|
+
this.logger.error('Max consecutive failures reached — pausing polling');
|
|
203
|
+
this.stopPolling();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Schedule next poll
|
|
208
|
+
if (this.polling) {
|
|
209
|
+
this.pollTimer = setTimeout(() => this.poll(), TELEGRAM_CONSTANTS.POLL_INTERVAL_MS);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Call the Telegram getUpdates API with long polling.
|
|
214
|
+
*
|
|
215
|
+
* @returns Array of updates
|
|
216
|
+
*/
|
|
217
|
+
async getUpdates() {
|
|
218
|
+
if (!this.config)
|
|
219
|
+
return [];
|
|
220
|
+
const params = new URLSearchParams({
|
|
221
|
+
timeout: String(TELEGRAM_CONSTANTS.LONG_POLL_TIMEOUT_S),
|
|
222
|
+
allowed_updates: JSON.stringify(['message']),
|
|
223
|
+
});
|
|
224
|
+
if (this.lastUpdateOffset > 0) {
|
|
225
|
+
params.set('offset', String(this.lastUpdateOffset));
|
|
226
|
+
}
|
|
227
|
+
const resp = await fetch(`${TELEGRAM_CONSTANTS.API_BASE}${this.config.botToken}/getUpdates?${params}`, {
|
|
228
|
+
signal: AbortSignal.timeout(TELEGRAM_CONSTANTS.FETCH_TIMEOUT_MS),
|
|
229
|
+
});
|
|
230
|
+
if (!resp.ok) {
|
|
231
|
+
throw new Error(`getUpdates failed (HTTP ${resp.status})`);
|
|
232
|
+
}
|
|
233
|
+
const data = (await resp.json());
|
|
234
|
+
const updates = data.result ?? [];
|
|
235
|
+
// Update offset to acknowledge processed updates
|
|
236
|
+
if (updates.length > 0) {
|
|
237
|
+
const maxId = Math.max(...updates.map((u) => u.update_id));
|
|
238
|
+
this.lastUpdateOffset = maxId + 1;
|
|
239
|
+
}
|
|
240
|
+
return updates;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Process a single Telegram update and emit events.
|
|
244
|
+
*
|
|
245
|
+
* @param update - The update to process
|
|
246
|
+
*/
|
|
247
|
+
processUpdate(update) {
|
|
248
|
+
if (!update.message?.text)
|
|
249
|
+
return;
|
|
250
|
+
const msg = update.message;
|
|
251
|
+
// Skip messages from bots
|
|
252
|
+
if (msg.from?.is_bot)
|
|
253
|
+
return;
|
|
254
|
+
// Check allowed users filter
|
|
255
|
+
if (this.config?.allowedUserIds &&
|
|
256
|
+
this.config.allowedUserIds.length > 0 &&
|
|
257
|
+
!this.config.allowedUserIds.includes(String(msg.from?.id))) {
|
|
258
|
+
this.logger.debug('Message from non-allowed user ignored', {
|
|
259
|
+
userId: msg.from?.id,
|
|
260
|
+
});
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const incoming = {
|
|
264
|
+
chatId: String(msg.chat.id),
|
|
265
|
+
messageId: msg.message_id,
|
|
266
|
+
userId: String(msg.from?.id ?? 0),
|
|
267
|
+
userName: msg.from?.first_name +
|
|
268
|
+
(msg.from?.last_name ? ` ${msg.from.last_name}` : ''),
|
|
269
|
+
text: msg.text,
|
|
270
|
+
timestamp: msg.date,
|
|
271
|
+
replyToMessageId: msg.reply_to_message?.message_id,
|
|
272
|
+
};
|
|
273
|
+
this.logger.debug('Incoming message', {
|
|
274
|
+
chatId: incoming.chatId,
|
|
275
|
+
userId: incoming.userId,
|
|
276
|
+
textLength: incoming.text.length,
|
|
277
|
+
});
|
|
278
|
+
this.emit('message', incoming);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/** Singleton instance */
|
|
282
|
+
let instance = null;
|
|
283
|
+
/**
|
|
284
|
+
* Get the TelegramService singleton.
|
|
285
|
+
*
|
|
286
|
+
* @returns The service instance
|
|
287
|
+
*/
|
|
288
|
+
export function getTelegramService() {
|
|
289
|
+
if (!instance) {
|
|
290
|
+
instance = new TelegramService();
|
|
291
|
+
}
|
|
292
|
+
return instance;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Reset the TelegramService singleton (for testing).
|
|
296
|
+
*/
|
|
297
|
+
export function resetTelegramService() {
|
|
298
|
+
if (instance) {
|
|
299
|
+
instance.stopPolling();
|
|
300
|
+
instance.removeAllListeners();
|
|
301
|
+
}
|
|
302
|
+
instance = null;
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=telegram.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram.service.ts"],"names":[],"mappings":"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"}
|