@hasna/connectors 1.1.5 → 1.1.6

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.
Files changed (37) hide show
  1. package/bin/index.js +1 -1
  2. package/bin/mcp.js +1 -1
  3. package/connectors/connect-gmail/src/api/attachments.ts +143 -0
  4. package/connectors/connect-gmail/src/api/bulk.ts +713 -0
  5. package/connectors/connect-gmail/src/api/client.ts +131 -0
  6. package/connectors/connect-gmail/src/api/drafts.ts +198 -0
  7. package/connectors/connect-gmail/src/api/export.ts +312 -0
  8. package/connectors/connect-gmail/src/api/filters.ts +127 -0
  9. package/connectors/connect-gmail/src/api/index.ts +63 -0
  10. package/connectors/connect-gmail/src/api/labels.ts +123 -0
  11. package/connectors/connect-gmail/src/api/messages.ts +527 -0
  12. package/connectors/connect-gmail/src/api/profile.ts +72 -0
  13. package/connectors/connect-gmail/src/api/threads.ts +85 -0
  14. package/connectors/connect-gmail/src/cli/index.ts +2389 -0
  15. package/connectors/connect-gmail/src/index.ts +30 -0
  16. package/connectors/connect-gmail/src/types/index.ts +202 -0
  17. package/connectors/connect-gmail/src/utils/auth.ts +256 -0
  18. package/connectors/connect-gmail/src/utils/config.ts +466 -0
  19. package/connectors/connect-gmail/src/utils/contacts.ts +147 -0
  20. package/connectors/connect-gmail/src/utils/markdown.ts +119 -0
  21. package/connectors/connect-gmail/src/utils/output.ts +119 -0
  22. package/connectors/connect-gmail/src/utils/settings.ts +87 -0
  23. package/connectors/connect-gmail/tsconfig.json +16 -0
  24. package/connectors/connect-telegram/src/api/bot.ts +223 -0
  25. package/connectors/connect-telegram/src/api/chats.ts +290 -0
  26. package/connectors/connect-telegram/src/api/client.ts +134 -0
  27. package/connectors/connect-telegram/src/api/index.ts +66 -0
  28. package/connectors/connect-telegram/src/api/inline.ts +63 -0
  29. package/connectors/connect-telegram/src/api/messages.ts +781 -0
  30. package/connectors/connect-telegram/src/api/updates.ts +97 -0
  31. package/connectors/connect-telegram/src/cli/index.ts +690 -0
  32. package/connectors/connect-telegram/src/index.ts +22 -0
  33. package/connectors/connect-telegram/src/types/index.ts +617 -0
  34. package/connectors/connect-telegram/src/utils/config.ts +197 -0
  35. package/connectors/connect-telegram/src/utils/output.ts +119 -0
  36. package/connectors/connect-telegram/tsconfig.json +16 -0
  37. package/package.json +1 -1
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Simple markdown to HTML converter for emails
3
+ * Supports: headers, bold, italic, links, code, lists, blockquotes, hr
4
+ */
5
+
6
+ export function markdownToHtml(markdown: string): string {
7
+ let html = markdown;
8
+
9
+ // Escape HTML entities first (but preserve intentional HTML)
10
+ html = html
11
+ .replace(/&(?!amp;|lt;|gt;|quot;|#)/g, '&')
12
+ .replace(/</g, '&lt;')
13
+ .replace(/>/g, '&gt;');
14
+
15
+ // Headers (must be at start of line)
16
+ html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
17
+ html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
18
+ html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');
19
+
20
+ // Horizontal rule
21
+ html = html.replace(/^(-{3,}|\*{3,}|_{3,})$/gm, '<hr>');
22
+
23
+ // Bold and italic (order matters)
24
+ html = html.replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>');
25
+ html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
26
+ html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
27
+ html = html.replace(/___(.+?)___/g, '<strong><em>$1</em></strong>');
28
+ html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
29
+ html = html.replace(/_(.+?)_/g, '<em>$1</em>');
30
+
31
+ // Strikethrough
32
+ html = html.replace(/~~(.+?)~~/g, '<del>$1</del>');
33
+
34
+ // Inline code
35
+ html = html.replace(/`([^`]+)`/g, '<code style="background:#f4f4f4;padding:2px 4px;border-radius:3px;">$1</code>');
36
+
37
+ // Code blocks
38
+ html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {
39
+ return `<pre style="background:#f4f4f4;padding:12px;border-radius:4px;overflow-x:auto;"><code>${code.trim()}</code></pre>`;
40
+ });
41
+
42
+ // Links [text](url)
43
+ html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" style="color:#1a73e8;">$1</a>');
44
+
45
+ // Images ![alt](url)
46
+ html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1" style="max-width:100%;">');
47
+
48
+ // Blockquotes
49
+ html = html.replace(/^> (.+)$/gm, '<blockquote style="border-left:4px solid #ddd;margin:0;padding-left:16px;color:#666;">$1</blockquote>');
50
+
51
+ // Unordered lists
52
+ html = html.replace(/^[\*\-] (.+)$/gm, '<li style="margin:0;padding:0;">$1</li>');
53
+ html = html.replace(/(<li style[^>]*>.*?<\/li>\n?)+/g, '<ul style="margin:4px 0;padding-left:20px;">$&</ul>');
54
+
55
+ // Ordered lists
56
+ html = html.replace(/^\d+\. (.+)$/gm, '<li style="margin:0;padding:0;">$1</li>');
57
+
58
+ // Paragraphs (double newlines)
59
+ html = html.replace(/\n\n+/g, '</p><p>');
60
+ html = `<p>${html}</p>`;
61
+
62
+ // Remove newlines between list items (prevent <br> between <li> elements)
63
+ html = html.replace(/<\/li>\n<li/g, '</li><li');
64
+ html = html.replace(/<\/li>\n<\/ul>/g, '</li></ul>');
65
+
66
+ // Single line breaks to <br>
67
+ html = html.replace(/\n/g, '<br>');
68
+
69
+ // Clean up empty paragraphs
70
+ html = html.replace(/<p><\/p>/g, '');
71
+ html = html.replace(/<p>(<h[1-6]>)/g, '$1');
72
+ html = html.replace(/(<\/h[1-6]>)<\/p>/g, '$1');
73
+ html = html.replace(/<p>(<ul)/g, '$1');
74
+ html = html.replace(/(<\/ul>)<\/p>/g, '$1');
75
+ html = html.replace(/<p>(<pre)/g, '$1');
76
+ html = html.replace(/(<\/pre>)<\/p>/g, '$1');
77
+ html = html.replace(/<p>(<blockquote)/g, '$1');
78
+ html = html.replace(/(<\/blockquote>)<\/p>/g, '$1');
79
+ html = html.replace(/<p><hr><\/p>/g, '<hr>');
80
+
81
+ return html;
82
+ }
83
+
84
+ /**
85
+ * Wrap HTML content in a basic email template (no custom fonts - uses Gmail defaults)
86
+ */
87
+ export function wrapInEmailTemplate(html: string): string {
88
+ return `<!DOCTYPE html>
89
+ <html>
90
+ <head>
91
+ <meta charset="UTF-8">
92
+ <style>
93
+ ul, ol { margin: 4px 0; padding-left: 20px; }
94
+ li { margin: 0; padding: 0; line-height: 1.5; }
95
+ p { margin: 0 0 8px 0; }
96
+ </style>
97
+ </head>
98
+ <body style="font-family:Arial,sans-serif;font-size:14px;line-height:1.6;color:#202124;">
99
+ ${html}
100
+ </body>
101
+ </html>`;
102
+ }
103
+
104
+ /**
105
+ * Check if text appears to be markdown (has markdown syntax)
106
+ */
107
+ export function looksLikeMarkdown(text: string): boolean {
108
+ const markdownPatterns = [
109
+ /^#{1,6} /m, // Headers
110
+ /\*\*.+\*\*/, // Bold
111
+ /\[.+\]\(.+\)/, // Links
112
+ /^[\*\-] /m, // Unordered lists
113
+ /^\d+\. /m, // Ordered lists
114
+ /```/, // Code blocks
115
+ /^> /m, // Blockquotes
116
+ ];
117
+
118
+ return markdownPatterns.some(pattern => pattern.test(text));
119
+ }
@@ -0,0 +1,119 @@
1
+ import chalk from 'chalk';
2
+
3
+ export type OutputFormat = 'json' | 'table' | 'pretty';
4
+
5
+ export function formatOutput(data: unknown, format: OutputFormat = 'pretty'): string {
6
+ switch (format) {
7
+ case 'json':
8
+ return JSON.stringify(data, null, 2);
9
+ case 'table':
10
+ return formatAsTable(data);
11
+ case 'pretty':
12
+ default:
13
+ return formatPretty(data);
14
+ }
15
+ }
16
+
17
+ function formatAsTable(data: unknown): string {
18
+ if (!Array.isArray(data)) {
19
+ data = [data];
20
+ }
21
+
22
+ const items = data as Record<string, unknown>[];
23
+ if (items.length === 0) {
24
+ return 'No data';
25
+ }
26
+
27
+ const firstItem = items[0];
28
+ if (!firstItem || typeof firstItem !== 'object') {
29
+ return 'No data';
30
+ }
31
+
32
+ const keys = Object.keys(firstItem);
33
+ const colWidths = keys.map(key => {
34
+ const maxValue = Math.max(
35
+ key.length,
36
+ ...items.map(item => String(item[key] ?? '').length)
37
+ );
38
+ return Math.min(maxValue, 40);
39
+ });
40
+
41
+ const header = keys.map((key, i) => key.padEnd(colWidths[i] ?? 10)).join(' | ');
42
+ const separator = colWidths.map(w => '-'.repeat(w)).join('-+-');
43
+
44
+ const rows = items.map(item =>
45
+ keys.map((key, i) => {
46
+ const value = String(item[key] ?? '');
47
+ const width = colWidths[i] ?? 10;
48
+ return value.length > width
49
+ ? value.substring(0, width - 3) + '...'
50
+ : value.padEnd(width);
51
+ }).join(' | ')
52
+ );
53
+
54
+ return [header, separator, ...rows].join('\n');
55
+ }
56
+
57
+ function formatPretty(data: unknown): string {
58
+ if (Array.isArray(data)) {
59
+ return data.map((item, i) => `${chalk.cyan(`[${i + 1}]`)} ${formatPrettyItem(item)}`).join('\n\n');
60
+ }
61
+ return formatPrettyItem(data);
62
+ }
63
+
64
+ function formatPrettyItem(item: unknown, indent = 0): string {
65
+ if (item === null || item === undefined) {
66
+ return chalk.gray('null');
67
+ }
68
+
69
+ if (typeof item !== 'object') {
70
+ return String(item);
71
+ }
72
+
73
+ const spaces = ' '.repeat(indent);
74
+ const entries = Object.entries(item as Record<string, unknown>);
75
+
76
+ return entries
77
+ .map(([key, value]) => {
78
+ if (Array.isArray(value)) {
79
+ if (value.length === 0) {
80
+ return `${spaces}${chalk.blue(key)}: ${chalk.gray('[]')}`;
81
+ }
82
+ if (typeof value[0] === 'object') {
83
+ return `${spaces}${chalk.blue(key)}:\n${value.map(v => formatPrettyItem(v, indent + 1)).join('\n')}`;
84
+ }
85
+ return `${spaces}${chalk.blue(key)}: ${value.join(', ')}`;
86
+ }
87
+
88
+ if (typeof value === 'object' && value !== null) {
89
+ return `${spaces}${chalk.blue(key)}:\n${formatPrettyItem(value, indent + 1)}`;
90
+ }
91
+
92
+ return `${spaces}${chalk.blue(key)}: ${chalk.white(String(value))}`;
93
+ })
94
+ .join('\n');
95
+ }
96
+
97
+ export function success(message: string): void {
98
+ console.log(chalk.green('✓'), message);
99
+ }
100
+
101
+ export function error(message: string): void {
102
+ console.error(chalk.red('✗'), message);
103
+ }
104
+
105
+ export function warn(message: string): void {
106
+ console.warn(chalk.yellow('⚠'), message);
107
+ }
108
+
109
+ export function info(message: string): void {
110
+ console.log(chalk.blue('ℹ'), message);
111
+ }
112
+
113
+ export function heading(message: string): void {
114
+ console.log(chalk.bold.cyan(`\n${message}\n`));
115
+ }
116
+
117
+ export function print(data: unknown, format: OutputFormat = 'pretty'): void {
118
+ console.log(formatOutput(data, format));
119
+ }
@@ -0,0 +1,87 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { getConfigDir, ensureConfigDir } from './config';
4
+
5
+ export interface Settings {
6
+ // Signature settings
7
+ appendSignature: boolean; // Append signature to new emails (default: true)
8
+ appendSignatureToReplies: boolean; // Append signature to replies (default: false)
9
+ signature?: string; // Custom signature (if not set, fetches from Gmail)
10
+
11
+ // Formatting settings
12
+ markdownEnabled: boolean; // Convert markdown to HTML (default: true)
13
+
14
+ // Display settings
15
+ defaultFormat: 'json' | 'table' | 'pretty';
16
+
17
+ // Sending defaults
18
+ defaultSendAsHtml: boolean; // Send as HTML by default (default: true when markdown enabled)
19
+ }
20
+
21
+ const DEFAULT_SETTINGS: Settings = {
22
+ appendSignature: true,
23
+ appendSignatureToReplies: false,
24
+ markdownEnabled: true,
25
+ defaultFormat: 'pretty',
26
+ defaultSendAsHtml: true,
27
+ };
28
+
29
+ function getSettingsPath(): string {
30
+ return join(getConfigDir(), 'settings.json');
31
+ }
32
+
33
+ export function loadSettings(): Settings {
34
+ ensureConfigDir();
35
+ const filepath = getSettingsPath();
36
+
37
+ if (!existsSync(filepath)) {
38
+ // Create default settings file
39
+ saveSettings(DEFAULT_SETTINGS);
40
+ return DEFAULT_SETTINGS;
41
+ }
42
+
43
+ try {
44
+ const content = readFileSync(filepath, 'utf-8');
45
+ const loaded = JSON.parse(content);
46
+ // Merge with defaults to ensure all fields exist
47
+ return { ...DEFAULT_SETTINGS, ...loaded };
48
+ } catch {
49
+ return DEFAULT_SETTINGS;
50
+ }
51
+ }
52
+
53
+ export function saveSettings(settings: Settings): void {
54
+ ensureConfigDir();
55
+ const filepath = getSettingsPath();
56
+ writeFileSync(filepath, JSON.stringify(settings, null, 2));
57
+ }
58
+
59
+ export function getSetting<K extends keyof Settings>(key: K): Settings[K] {
60
+ return loadSettings()[key];
61
+ }
62
+
63
+ export function setSetting<K extends keyof Settings>(key: K, value: Settings[K]): void {
64
+ const settings = loadSettings();
65
+ settings[key] = value;
66
+ saveSettings(settings);
67
+ }
68
+
69
+ export function getSignature(): string | undefined {
70
+ return loadSettings().signature;
71
+ }
72
+
73
+ export function setSignature(signature: string): void {
74
+ setSetting('signature', signature);
75
+ }
76
+
77
+ export function isMarkdownEnabled(): boolean {
78
+ return loadSettings().markdownEnabled;
79
+ }
80
+
81
+ export function shouldAppendSignature(isReply: boolean = false): boolean {
82
+ const settings = loadSettings();
83
+ if (isReply) {
84
+ return settings.appendSignatureToReplies;
85
+ }
86
+ return settings.appendSignature;
87
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "declaration": true,
10
+ "outDir": "./dist",
11
+ "rootDir": "./src",
12
+ "types": ["@types/bun"]
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist", "bin"]
16
+ }
@@ -0,0 +1,223 @@
1
+ import type { TelegramClient } from './client';
2
+ import type { TelegramUser, TelegramFile } from '../types';
3
+
4
+ export interface BotCommand {
5
+ command: string;
6
+ description: string;
7
+ }
8
+
9
+ export interface BotCommandScope {
10
+ type: 'default' | 'all_private_chats' | 'all_group_chats' | 'all_chat_administrators' | 'chat' | 'chat_administrators' | 'chat_member';
11
+ chat_id?: number | string;
12
+ user_id?: number;
13
+ }
14
+
15
+ export interface SetMyCommandsOptions {
16
+ commands: BotCommand[];
17
+ scope?: BotCommandScope;
18
+ languageCode?: string;
19
+ }
20
+
21
+ export interface DeleteMyCommandsOptions {
22
+ scope?: BotCommandScope;
23
+ languageCode?: string;
24
+ }
25
+
26
+ export interface GetMyCommandsOptions {
27
+ scope?: BotCommandScope;
28
+ languageCode?: string;
29
+ }
30
+
31
+ export interface SetMyNameOptions {
32
+ name?: string;
33
+ languageCode?: string;
34
+ }
35
+
36
+ export interface GetMyNameOptions {
37
+ languageCode?: string;
38
+ }
39
+
40
+ export interface SetMyDescriptionOptions {
41
+ description?: string;
42
+ languageCode?: string;
43
+ }
44
+
45
+ export interface GetMyDescriptionOptions {
46
+ languageCode?: string;
47
+ }
48
+
49
+ export interface SetMyShortDescriptionOptions {
50
+ shortDescription?: string;
51
+ languageCode?: string;
52
+ }
53
+
54
+ export interface GetMyShortDescriptionOptions {
55
+ languageCode?: string;
56
+ }
57
+
58
+ export interface GetFileOptions {
59
+ fileId: string;
60
+ }
61
+
62
+ export interface BotName {
63
+ name: string;
64
+ }
65
+
66
+ export interface BotDescription {
67
+ description: string;
68
+ }
69
+
70
+ export interface BotShortDescription {
71
+ short_description: string;
72
+ }
73
+
74
+ /**
75
+ * Telegram Bot API
76
+ */
77
+ export class BotApi {
78
+ constructor(private readonly client: TelegramClient) {}
79
+
80
+ /**
81
+ * Get bot information
82
+ */
83
+ async getMe(): Promise<TelegramUser> {
84
+ return this.client.request<TelegramUser>('getMe', {
85
+ method: 'GET',
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Log out from the cloud Bot API server
91
+ */
92
+ async logOut(): Promise<boolean> {
93
+ return this.client.request<boolean>('logOut');
94
+ }
95
+
96
+ /**
97
+ * Close the bot instance
98
+ */
99
+ async close(): Promise<boolean> {
100
+ return this.client.request<boolean>('close');
101
+ }
102
+
103
+ /**
104
+ * Set bot commands
105
+ */
106
+ async setMyCommands(options: SetMyCommandsOptions): Promise<boolean> {
107
+ return this.client.request<boolean>('setMyCommands', {
108
+ params: {
109
+ commands: JSON.stringify(options.commands),
110
+ scope: options.scope ? JSON.stringify(options.scope) : undefined,
111
+ language_code: options.languageCode,
112
+ },
113
+ });
114
+ }
115
+
116
+ /**
117
+ * Delete bot commands
118
+ */
119
+ async deleteMyCommands(options: DeleteMyCommandsOptions = {}): Promise<boolean> {
120
+ return this.client.request<boolean>('deleteMyCommands', {
121
+ params: {
122
+ scope: options.scope ? JSON.stringify(options.scope) : undefined,
123
+ language_code: options.languageCode,
124
+ },
125
+ });
126
+ }
127
+
128
+ /**
129
+ * Get bot commands
130
+ */
131
+ async getMyCommands(options: GetMyCommandsOptions = {}): Promise<BotCommand[]> {
132
+ return this.client.request<BotCommand[]>('getMyCommands', {
133
+ method: 'GET',
134
+ params: {
135
+ scope: options.scope ? JSON.stringify(options.scope) : undefined,
136
+ language_code: options.languageCode,
137
+ },
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Set bot name
143
+ */
144
+ async setMyName(options: SetMyNameOptions = {}): Promise<boolean> {
145
+ return this.client.request<boolean>('setMyName', {
146
+ params: {
147
+ name: options.name,
148
+ language_code: options.languageCode,
149
+ },
150
+ });
151
+ }
152
+
153
+ /**
154
+ * Get bot name
155
+ */
156
+ async getMyName(options: GetMyNameOptions = {}): Promise<BotName> {
157
+ return this.client.request<BotName>('getMyName', {
158
+ method: 'GET',
159
+ params: {
160
+ language_code: options.languageCode,
161
+ },
162
+ });
163
+ }
164
+
165
+ /**
166
+ * Set bot description
167
+ */
168
+ async setMyDescription(options: SetMyDescriptionOptions = {}): Promise<boolean> {
169
+ return this.client.request<boolean>('setMyDescription', {
170
+ params: {
171
+ description: options.description,
172
+ language_code: options.languageCode,
173
+ },
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Get bot description
179
+ */
180
+ async getMyDescription(options: GetMyDescriptionOptions = {}): Promise<BotDescription> {
181
+ return this.client.request<BotDescription>('getMyDescription', {
182
+ method: 'GET',
183
+ params: {
184
+ language_code: options.languageCode,
185
+ },
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Set bot short description
191
+ */
192
+ async setMyShortDescription(options: SetMyShortDescriptionOptions = {}): Promise<boolean> {
193
+ return this.client.request<boolean>('setMyShortDescription', {
194
+ params: {
195
+ short_description: options.shortDescription,
196
+ language_code: options.languageCode,
197
+ },
198
+ });
199
+ }
200
+
201
+ /**
202
+ * Get bot short description
203
+ */
204
+ async getMyShortDescription(options: GetMyShortDescriptionOptions = {}): Promise<BotShortDescription> {
205
+ return this.client.request<BotShortDescription>('getMyShortDescription', {
206
+ method: 'GET',
207
+ params: {
208
+ language_code: options.languageCode,
209
+ },
210
+ });
211
+ }
212
+
213
+ /**
214
+ * Get file information
215
+ */
216
+ async getFile(options: GetFileOptions): Promise<TelegramFile> {
217
+ return this.client.request<TelegramFile>('getFile', {
218
+ params: {
219
+ file_id: options.fileId,
220
+ },
221
+ });
222
+ }
223
+ }