Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
/**
* ChannelRegistry - Multi-Channel Management
*
* Manages multiple channel adapters with unified message routing,
* multi-tenant isolation, and rate limiting.
*/
import type { BaseAdapter, ChannelType, MessageHandler, AdapterConfig } from './adapters/BaseAdapter.js';
export interface ChannelFilter {
types?: ChannelType[];
tenantIds?: string[];
channelIds?: string[];
}
export interface ChannelRegistryConfig {
defaultRateLimit?: {
requests: number;
windowMs: number;
};
}
export interface AdapterFactory {
(config: AdapterConfig): BaseAdapter;
}
export declare class ChannelRegistry {
private adapters;
private adaptersByType;
private adaptersByTenant;
private globalHandlers;
private config;
private rateLimitWindows;
constructor(config?: ChannelRegistryConfig);
/**
* Generate unique adapter key
*/
private getAdapterKey;
/**
* Register a channel adapter
*/
register(adapter: BaseAdapter): void;
/**
* Unregister a channel adapter
*/
unregister(type: ChannelType, tenantId: string): boolean;
/**
* Get a specific adapter
*/
get(type: ChannelType, tenantId: string): BaseAdapter | undefined;
/**
* Get all adapters for a type
*/
getByType(type: ChannelType): BaseAdapter[];
/**
* Get all adapters for a tenant
*/
getByTenant(tenantId: string): BaseAdapter[];
/**
* Get all registered adapters
*/
getAll(): BaseAdapter[];
/**
* Register a global message handler
*/
onMessage(handler: MessageHandler): void;
/**
* Remove a global message handler
*/
offMessage(handler: MessageHandler): void;
/**
* Start all adapters
*/
start(): Promise<void>;
/**
* Stop all adapters
*/
stop(): Promise<void>;
/**
* Broadcast a message to multiple channels
*/
broadcast(message: string, channelIds: string[], filter?: ChannelFilter): Promise<Map<string, string>>;
/**
* Get registry statistics
*/
getStats(): {
totalAdapters: number;
byType: Record<ChannelType, number>;
byTenant: Record<string, number>;
connected: number;
totalMessages: number;
};
private handleMessage;
private filterAdapters;
private checkRateLimit;
}
export declare function createChannelRegistry(config?: ChannelRegistryConfig): ChannelRegistry;
export default ChannelRegistry;
//# sourceMappingURL=ChannelRegistry.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ChannelRegistry.d.ts","sourceRoot":"","sources":["ChannelRegistry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEX,cAAc,EACd,aAAa,EACd,MAAM,2BAA2B,CAAC;AAMnC,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC;CACtC;AAMD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,cAAc,CAA4C;IAClE,OAAO,CAAC,gBAAgB,CAAuC;IAC/D,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,MAAM,CAAwB;IAGtC,OAAO,CAAC,gBAAgB,CAA8D;gBAE1E,MAAM,GAAE,qBAA0B;IAI9C;;OAEG;IACH,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAwBpC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAgBxD;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIjE;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,EAAE;IAS3C;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE;IAS5C;;OAEG;IACH,MAAM,IAAI,WAAW,EAAE;IAIvB;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIxC;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAOzC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B;;OAEG;IACG,SAAS,CACb,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAoB/B;;OAEG;IACH,QAAQ,IAAI;QACV,aAAa,EAAE,MAAM,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;KACvB;YAgCa,aAAa;IAU3B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,cAAc;CAoBvB;AAMD,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,CAErF;AAED,eAAe,eAAe,CAAC"}

View File

@@ -0,0 +1,230 @@
"use strict";
/**
* ChannelRegistry - Multi-Channel Management
*
* Manages multiple channel adapters with unified message routing,
* multi-tenant isolation, and rate limiting.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChannelRegistry = void 0;
exports.createChannelRegistry = createChannelRegistry;
// ============================================================================
// ChannelRegistry Implementation
// ============================================================================
class ChannelRegistry {
constructor(config = {}) {
this.adapters = new Map();
this.adaptersByType = new Map();
this.adaptersByTenant = new Map();
this.globalHandlers = [];
// Rate limiting state
this.rateLimitWindows = new Map();
this.config = config;
}
/**
* Generate unique adapter key
*/
getAdapterKey(type, tenantId) {
return `${type}:${tenantId}`;
}
/**
* Register a channel adapter
*/
register(adapter) {
const key = this.getAdapterKey(adapter.type, adapter.tenantId);
// Store adapter
this.adapters.set(key, adapter);
// Index by type
if (!this.adaptersByType.has(adapter.type)) {
this.adaptersByType.set(adapter.type, new Set());
}
this.adaptersByType.get(adapter.type).add(key);
// Index by tenant
if (!this.adaptersByTenant.has(adapter.tenantId)) {
this.adaptersByTenant.set(adapter.tenantId, new Set());
}
this.adaptersByTenant.get(adapter.tenantId).add(key);
// Register global message handler on adapter
adapter.onMessage(async (message) => {
await this.handleMessage(message);
});
}
/**
* Unregister a channel adapter
*/
unregister(type, tenantId) {
const key = this.getAdapterKey(type, tenantId);
const adapter = this.adapters.get(key);
if (!adapter)
return false;
// Remove from indices
this.adaptersByType.get(type)?.delete(key);
this.adaptersByTenant.get(tenantId)?.delete(key);
// Remove adapter
this.adapters.delete(key);
return true;
}
/**
* Get a specific adapter
*/
get(type, tenantId) {
return this.adapters.get(this.getAdapterKey(type, tenantId));
}
/**
* Get all adapters for a type
*/
getByType(type) {
const keys = this.adaptersByType.get(type);
if (!keys)
return [];
return Array.from(keys)
.map(key => this.adapters.get(key))
.filter((a) => a !== undefined);
}
/**
* Get all adapters for a tenant
*/
getByTenant(tenantId) {
const keys = this.adaptersByTenant.get(tenantId);
if (!keys)
return [];
return Array.from(keys)
.map(key => this.adapters.get(key))
.filter((a) => a !== undefined);
}
/**
* Get all registered adapters
*/
getAll() {
return Array.from(this.adapters.values());
}
/**
* Register a global message handler
*/
onMessage(handler) {
this.globalHandlers.push(handler);
}
/**
* Remove a global message handler
*/
offMessage(handler) {
const index = this.globalHandlers.indexOf(handler);
if (index > -1) {
this.globalHandlers.splice(index, 1);
}
}
/**
* Start all adapters
*/
async start() {
const startPromises = Array.from(this.adapters.values())
.filter(adapter => adapter.enabled)
.map(adapter => adapter.connect());
await Promise.all(startPromises);
}
/**
* Stop all adapters
*/
async stop() {
const stopPromises = Array.from(this.adapters.values())
.map(adapter => adapter.disconnect());
await Promise.all(stopPromises);
}
/**
* Broadcast a message to multiple channels
*/
async broadcast(message, channelIds, filter) {
const results = new Map();
const adapters = this.filterAdapters(filter);
for (const adapter of adapters) {
for (const channelId of channelIds) {
try {
if (this.checkRateLimit(adapter)) {
const messageId = await adapter.send(channelId, message);
results.set(`${adapter.type}:${channelId}`, messageId);
}
}
catch (error) {
console.error(`Failed to broadcast to ${adapter.type}:${channelId}:`, error);
}
}
}
return results;
}
/**
* Get registry statistics
*/
getStats() {
const byType = {};
const byTenant = {};
let connected = 0;
let totalMessages = 0;
for (const adapter of this.adapters.values()) {
// By type
byType[adapter.type] = (byType[adapter.type] ?? 0) + 1;
// By tenant
byTenant[adapter.tenantId] = (byTenant[adapter.tenantId] ?? 0) + 1;
// Connected status
const status = adapter.getStatus();
if (status.connected)
connected++;
totalMessages += status.messageCount;
}
return {
totalAdapters: this.adapters.size,
byType,
byTenant,
connected,
totalMessages,
};
}
// ==========================================================================
// Private Methods
// ==========================================================================
async handleMessage(message) {
for (const handler of this.globalHandlers) {
try {
await handler(message);
}
catch (error) {
console.error('Global message handler error:', error);
}
}
}
filterAdapters(filter) {
let adapters = Array.from(this.adapters.values());
if (filter?.types) {
adapters = adapters.filter(a => filter.types.includes(a.type));
}
if (filter?.tenantIds) {
adapters = adapters.filter(a => filter.tenantIds.includes(a.tenantId));
}
return adapters.filter(a => a.enabled);
}
checkRateLimit(adapter) {
const config = this.config.defaultRateLimit;
if (!config)
return true;
const key = this.getAdapterKey(adapter.type, adapter.tenantId);
const now = Date.now();
let window = this.rateLimitWindows.get(key);
if (!window || now > window.resetAt) {
window = { count: 0, resetAt: now + config.windowMs };
this.rateLimitWindows.set(key, window);
}
if (window.count >= config.requests) {
return false;
}
window.count++;
return true;
}
}
exports.ChannelRegistry = ChannelRegistry;
// ============================================================================
// Factory Function
// ============================================================================
function createChannelRegistry(config) {
return new ChannelRegistry(config);
}
exports.default = ChannelRegistry;
//# sourceMappingURL=ChannelRegistry.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,306 @@
/**
* ChannelRegistry - Multi-Channel Management
*
* Manages multiple channel adapters with unified message routing,
* multi-tenant isolation, and rate limiting.
*/
import type {
BaseAdapter,
ChannelType,
UnifiedMessage,
MessageHandler,
AdapterConfig,
} from './adapters/BaseAdapter.js';
// ============================================================================
// Types
// ============================================================================
export interface ChannelFilter {
types?: ChannelType[];
tenantIds?: string[];
channelIds?: string[];
}
export interface ChannelRegistryConfig {
defaultRateLimit?: {
requests: number;
windowMs: number;
};
}
export interface AdapterFactory {
(config: AdapterConfig): BaseAdapter;
}
// ============================================================================
// ChannelRegistry Implementation
// ============================================================================
export class ChannelRegistry {
private adapters: Map<string, BaseAdapter> = new Map();
private adaptersByType: Map<ChannelType, Set<string>> = new Map();
private adaptersByTenant: Map<string, Set<string>> = new Map();
private globalHandlers: MessageHandler[] = [];
private config: ChannelRegistryConfig;
// Rate limiting state
private rateLimitWindows: Map<string, { count: number; resetAt: number }> = new Map();
constructor(config: ChannelRegistryConfig = {}) {
this.config = config;
}
/**
* Generate unique adapter key
*/
private getAdapterKey(type: ChannelType, tenantId: string): string {
return `${type}:${tenantId}`;
}
/**
* Register a channel adapter
*/
register(adapter: BaseAdapter): void {
const key = this.getAdapterKey(adapter.type, adapter.tenantId);
// Store adapter
this.adapters.set(key, adapter);
// Index by type
if (!this.adaptersByType.has(adapter.type)) {
this.adaptersByType.set(adapter.type, new Set());
}
this.adaptersByType.get(adapter.type)!.add(key);
// Index by tenant
if (!this.adaptersByTenant.has(adapter.tenantId)) {
this.adaptersByTenant.set(adapter.tenantId, new Set());
}
this.adaptersByTenant.get(adapter.tenantId)!.add(key);
// Register global message handler on adapter
adapter.onMessage(async (message) => {
await this.handleMessage(message);
});
}
/**
* Unregister a channel adapter
*/
unregister(type: ChannelType, tenantId: string): boolean {
const key = this.getAdapterKey(type, tenantId);
const adapter = this.adapters.get(key);
if (!adapter) return false;
// Remove from indices
this.adaptersByType.get(type)?.delete(key);
this.adaptersByTenant.get(tenantId)?.delete(key);
// Remove adapter
this.adapters.delete(key);
return true;
}
/**
* Get a specific adapter
*/
get(type: ChannelType, tenantId: string): BaseAdapter | undefined {
return this.adapters.get(this.getAdapterKey(type, tenantId));
}
/**
* Get all adapters for a type
*/
getByType(type: ChannelType): BaseAdapter[] {
const keys = this.adaptersByType.get(type);
if (!keys) return [];
return Array.from(keys)
.map(key => this.adapters.get(key))
.filter((a): a is BaseAdapter => a !== undefined);
}
/**
* Get all adapters for a tenant
*/
getByTenant(tenantId: string): BaseAdapter[] {
const keys = this.adaptersByTenant.get(tenantId);
if (!keys) return [];
return Array.from(keys)
.map(key => this.adapters.get(key))
.filter((a): a is BaseAdapter => a !== undefined);
}
/**
* Get all registered adapters
*/
getAll(): BaseAdapter[] {
return Array.from(this.adapters.values());
}
/**
* Register a global message handler
*/
onMessage(handler: MessageHandler): void {
this.globalHandlers.push(handler);
}
/**
* Remove a global message handler
*/
offMessage(handler: MessageHandler): void {
const index = this.globalHandlers.indexOf(handler);
if (index > -1) {
this.globalHandlers.splice(index, 1);
}
}
/**
* Start all adapters
*/
async start(): Promise<void> {
const startPromises = Array.from(this.adapters.values())
.filter(adapter => adapter.enabled)
.map(adapter => adapter.connect());
await Promise.all(startPromises);
}
/**
* Stop all adapters
*/
async stop(): Promise<void> {
const stopPromises = Array.from(this.adapters.values())
.map(adapter => adapter.disconnect());
await Promise.all(stopPromises);
}
/**
* Broadcast a message to multiple channels
*/
async broadcast(
message: string,
channelIds: string[],
filter?: ChannelFilter
): Promise<Map<string, string>> {
const results = new Map<string, string>();
const adapters = this.filterAdapters(filter);
for (const adapter of adapters) {
for (const channelId of channelIds) {
try {
if (this.checkRateLimit(adapter)) {
const messageId = await adapter.send(channelId, message);
results.set(`${adapter.type}:${channelId}`, messageId);
}
} catch (error) {
console.error(`Failed to broadcast to ${adapter.type}:${channelId}:`, error);
}
}
}
return results;
}
/**
* Get registry statistics
*/
getStats(): {
totalAdapters: number;
byType: Record<ChannelType, number>;
byTenant: Record<string, number>;
connected: number;
totalMessages: number;
} {
const byType = {} as Record<ChannelType, number>;
const byTenant = {} as Record<string, number>;
let connected = 0;
let totalMessages = 0;
for (const adapter of this.adapters.values()) {
// By type
byType[adapter.type] = (byType[adapter.type] ?? 0) + 1;
// By tenant
byTenant[adapter.tenantId] = (byTenant[adapter.tenantId] ?? 0) + 1;
// Connected status
const status = adapter.getStatus();
if (status.connected) connected++;
totalMessages += status.messageCount;
}
return {
totalAdapters: this.adapters.size,
byType,
byTenant,
connected,
totalMessages,
};
}
// ==========================================================================
// Private Methods
// ==========================================================================
private async handleMessage(message: UnifiedMessage): Promise<void> {
for (const handler of this.globalHandlers) {
try {
await handler(message);
} catch (error) {
console.error('Global message handler error:', error);
}
}
}
private filterAdapters(filter?: ChannelFilter): BaseAdapter[] {
let adapters = Array.from(this.adapters.values());
if (filter?.types) {
adapters = adapters.filter(a => filter.types!.includes(a.type));
}
if (filter?.tenantIds) {
adapters = adapters.filter(a => filter.tenantIds!.includes(a.tenantId));
}
return adapters.filter(a => a.enabled);
}
private checkRateLimit(adapter: BaseAdapter): boolean {
const config = this.config.defaultRateLimit;
if (!config) return true;
const key = this.getAdapterKey(adapter.type, adapter.tenantId);
const now = Date.now();
let window = this.rateLimitWindows.get(key);
if (!window || now > window.resetAt) {
window = { count: 0, resetAt: now + config.windowMs };
this.rateLimitWindows.set(key, window);
}
if (window.count >= config.requests) {
return false;
}
window.count++;
return true;
}
}
// ============================================================================
// Factory Function
// ============================================================================
export function createChannelRegistry(config?: ChannelRegistryConfig): ChannelRegistry {
return new ChannelRegistry(config);
}
export default ChannelRegistry;

View File

@@ -0,0 +1,120 @@
/**
* BaseAdapter - Abstract Channel Adapter
*
* Base class for all channel adapters providing a unified interface
* for multi-channel messaging support.
*/
import type { EventEmitter } from 'events';
export type ChannelType = 'slack' | 'discord' | 'telegram' | 'signal' | 'whatsapp' | 'line' | 'imessage' | 'web' | 'api' | 'cli';
export interface Attachment {
id: string;
type: 'image' | 'file' | 'audio' | 'video' | 'link';
url?: string;
data?: Buffer;
mimeType?: string;
filename?: string;
size?: number;
}
export interface UnifiedMessage {
id: string;
channelId: string;
channelType: ChannelType;
tenantId: string;
userId: string;
username?: string;
content: string;
attachments?: Attachment[];
threadId?: string;
replyTo?: string;
timestamp: Date;
metadata: Record<string, unknown>;
}
export interface SendOptions {
threadId?: string;
replyTo?: string;
attachments?: Attachment[];
metadata?: Record<string, unknown>;
}
export interface ChannelCredentials {
token?: string;
apiKey?: string;
webhookUrl?: string;
clientId?: string;
clientSecret?: string;
botId?: string;
[key: string]: unknown;
}
export interface AdapterConfig {
type: ChannelType;
tenantId: string;
credentials: ChannelCredentials;
enabled?: boolean;
rateLimit?: {
requests: number;
windowMs: number;
};
}
export interface AdapterStatus {
connected: boolean;
lastActivity?: Date;
errorCount: number;
messageCount: number;
}
export type MessageHandler = (message: UnifiedMessage) => Promise<void>;
export declare abstract class BaseAdapter {
protected readonly config: AdapterConfig;
protected status: AdapterStatus;
protected messageHandlers: MessageHandler[];
protected eventEmitter?: EventEmitter;
constructor(config: AdapterConfig);
/**
* Get channel type
*/
get type(): ChannelType;
/**
* Get tenant ID
*/
get tenantId(): string;
/**
* Check if adapter is enabled
*/
get enabled(): boolean;
/**
* Get adapter status
*/
getStatus(): AdapterStatus;
/**
* Register a message handler
*/
onMessage(handler: MessageHandler): void;
/**
* Remove a message handler
*/
offMessage(handler: MessageHandler): void;
/**
* Emit a received message to all handlers
*/
protected emitMessage(message: UnifiedMessage): Promise<void>;
/**
* Create a unified message from raw input
*/
protected createUnifiedMessage(content: string, userId: string, channelId: string, extra?: Partial<UnifiedMessage>): UnifiedMessage;
/**
* Connect to the channel
*/
abstract connect(): Promise<void>;
/**
* Disconnect from the channel
*/
abstract disconnect(): Promise<void>;
/**
* Send a message to the channel
*/
abstract send(channelId: string, content: string, options?: SendOptions): Promise<string>;
/**
* Reply to a message
*/
abstract reply(message: UnifiedMessage, content: string, options?: SendOptions): Promise<string>;
}
export default BaseAdapter;
//# sourceMappingURL=BaseAdapter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BaseAdapter.d.ts","sourceRoot":"","sources":["BaseAdapter.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,101 @@
"use strict";
/**
* BaseAdapter - Abstract Channel Adapter
*
* Base class for all channel adapters providing a unified interface
* for multi-channel messaging support.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseAdapter = void 0;
const uuid_1 = require("uuid");
// ============================================================================
// BaseAdapter Abstract Class
// ============================================================================
class BaseAdapter {
constructor(config) {
this.messageHandlers = [];
this.config = {
...config,
enabled: config.enabled ?? true,
};
this.status = {
connected: false,
errorCount: 0,
messageCount: 0,
};
}
/**
* Get channel type
*/
get type() {
return this.config.type;
}
/**
* Get tenant ID
*/
get tenantId() {
return this.config.tenantId;
}
/**
* Check if adapter is enabled
*/
get enabled() {
return this.config.enabled ?? true;
}
/**
* Get adapter status
*/
getStatus() {
return { ...this.status };
}
/**
* Register a message handler
*/
onMessage(handler) {
this.messageHandlers.push(handler);
}
/**
* Remove a message handler
*/
offMessage(handler) {
const index = this.messageHandlers.indexOf(handler);
if (index > -1) {
this.messageHandlers.splice(index, 1);
}
}
/**
* Emit a received message to all handlers
*/
async emitMessage(message) {
this.status.messageCount++;
this.status.lastActivity = new Date();
for (const handler of this.messageHandlers) {
try {
await handler(message);
}
catch (error) {
this.status.errorCount++;
console.error(`Message handler error in ${this.type}:`, error);
}
}
}
/**
* Create a unified message from raw input
*/
createUnifiedMessage(content, userId, channelId, extra = {}) {
return {
id: (0, uuid_1.v4)(),
channelId,
channelType: this.config.type,
tenantId: this.config.tenantId,
userId,
content,
timestamp: new Date(),
metadata: {},
...extra,
};
}
}
exports.BaseAdapter = BaseAdapter;
exports.default = BaseAdapter;
//# sourceMappingURL=BaseAdapter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BaseAdapter.js","sourceRoot":"","sources":["BaseAdapter.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,+BAAoC;AAqFpC,+EAA+E;AAC/E,6BAA6B;AAC7B,+EAA+E;AAE/E,MAAsB,WAAW;IAM/B,YAAY,MAAqB;QAHvB,oBAAe,GAAqB,EAAE,CAAC;QAI/C,IAAI,CAAC,MAAM,GAAG;YACZ,GAAG,MAAM;YACT,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI;SAChC,CAAC;QACF,IAAI,CAAC,MAAM,GAAG;YACZ,SAAS,EAAE,KAAK;YAChB,UAAU,EAAE,CAAC;YACb,YAAY,EAAE,CAAC;SAChB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,OAAuB;QAC/B,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,OAAuB;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED;;OAEG;IACO,KAAK,CAAC,WAAW,CAAC,OAAuB;QACjD,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC;QAEtC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBACzB,OAAO,CAAC,KAAK,CAAC,4BAA4B,IAAI,CAAC,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACO,oBAAoB,CAC5B,OAAe,EACf,MAAc,EACd,SAAiB,EACjB,QAAiC,EAAE;QAEnC,OAAO;YACL,EAAE,EAAE,IAAA,SAAM,GAAE;YACZ,SAAS;YACT,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YAC7B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC9B,MAAM;YACN,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,QAAQ,EAAE,EAAE;YACZ,GAAG,KAAK;SACT,CAAC;IACJ,CAAC;CAiCF;AArID,kCAqIC;AAED,kBAAe,WAAW,CAAC"}

View File

@@ -0,0 +1,232 @@
/**
* BaseAdapter - Abstract Channel Adapter
*
* Base class for all channel adapters providing a unified interface
* for multi-channel messaging support.
*/
import { v4 as uuidv4 } from 'uuid';
import type { EventEmitter } from 'events';
// ============================================================================
// Types
// ============================================================================
export type ChannelType =
| 'slack'
| 'discord'
| 'telegram'
| 'signal'
| 'whatsapp'
| 'line'
| 'imessage'
| 'web'
| 'api'
| 'cli';
export interface Attachment {
id: string;
type: 'image' | 'file' | 'audio' | 'video' | 'link';
url?: string;
data?: Buffer;
mimeType?: string;
filename?: string;
size?: number;
}
export interface UnifiedMessage {
id: string;
channelId: string;
channelType: ChannelType;
tenantId: string;
userId: string;
username?: string;
content: string;
attachments?: Attachment[];
threadId?: string;
replyTo?: string;
timestamp: Date;
metadata: Record<string, unknown>;
}
export interface SendOptions {
threadId?: string;
replyTo?: string;
attachments?: Attachment[];
metadata?: Record<string, unknown>;
}
export interface ChannelCredentials {
token?: string;
apiKey?: string;
webhookUrl?: string;
clientId?: string;
clientSecret?: string;
botId?: string;
[key: string]: unknown;
}
export interface AdapterConfig {
type: ChannelType;
tenantId: string;
credentials: ChannelCredentials;
enabled?: boolean;
rateLimit?: {
requests: number;
windowMs: number;
};
}
export interface AdapterStatus {
connected: boolean;
lastActivity?: Date;
errorCount: number;
messageCount: number;
}
// ============================================================================
// Message Handler Type
// ============================================================================
export type MessageHandler = (message: UnifiedMessage) => Promise<void>;
// ============================================================================
// BaseAdapter Abstract Class
// ============================================================================
export abstract class BaseAdapter {
protected readonly config: AdapterConfig;
protected status: AdapterStatus;
protected messageHandlers: MessageHandler[] = [];
protected eventEmitter?: EventEmitter;
constructor(config: AdapterConfig) {
this.config = {
...config,
enabled: config.enabled ?? true,
};
this.status = {
connected: false,
errorCount: 0,
messageCount: 0,
};
}
/**
* Get channel type
*/
get type(): ChannelType {
return this.config.type;
}
/**
* Get tenant ID
*/
get tenantId(): string {
return this.config.tenantId;
}
/**
* Check if adapter is enabled
*/
get enabled(): boolean {
return this.config.enabled ?? true;
}
/**
* Get adapter status
*/
getStatus(): AdapterStatus {
return { ...this.status };
}
/**
* Register a message handler
*/
onMessage(handler: MessageHandler): void {
this.messageHandlers.push(handler);
}
/**
* Remove a message handler
*/
offMessage(handler: MessageHandler): void {
const index = this.messageHandlers.indexOf(handler);
if (index > -1) {
this.messageHandlers.splice(index, 1);
}
}
/**
* Emit a received message to all handlers
*/
protected async emitMessage(message: UnifiedMessage): Promise<void> {
this.status.messageCount++;
this.status.lastActivity = new Date();
for (const handler of this.messageHandlers) {
try {
await handler(message);
} catch (error) {
this.status.errorCount++;
console.error(`Message handler error in ${this.type}:`, error);
}
}
}
/**
* Create a unified message from raw input
*/
protected createUnifiedMessage(
content: string,
userId: string,
channelId: string,
extra: Partial<UnifiedMessage> = {}
): UnifiedMessage {
return {
id: uuidv4(),
channelId,
channelType: this.config.type,
tenantId: this.config.tenantId,
userId,
content,
timestamp: new Date(),
metadata: {},
...extra,
};
}
// ==========================================================================
// Abstract Methods (must be implemented by subclasses)
// ==========================================================================
/**
* Connect to the channel
*/
abstract connect(): Promise<void>;
/**
* Disconnect from the channel
*/
abstract disconnect(): Promise<void>;
/**
* Send a message to the channel
*/
abstract send(
channelId: string,
content: string,
options?: SendOptions
): Promise<string>;
/**
* Reply to a message
*/
abstract reply(
message: UnifiedMessage,
content: string,
options?: SendOptions
): Promise<string>;
}
export default BaseAdapter;

View File

@@ -0,0 +1,67 @@
/**
* DiscordAdapter - Discord Channel Integration
*
* Connects to Discord servers using discord.js for real-time messaging.
* Supports threads, embeds, reactions, and slash commands.
*/
import { BaseAdapter, type AdapterConfig, type UnifiedMessage, type SendOptions } from './BaseAdapter.js';
export interface DiscordCredentials {
token: string;
clientId?: string;
guildId?: string;
intents?: number[];
}
export interface DiscordMessage {
id: string;
channelId: string;
guildId?: string;
author: {
id: string;
username: string;
discriminator: string;
};
content: string;
timestamp: Date;
reference?: {
messageId: string;
};
attachments: Map<string, DiscordAttachment>;
}
export interface DiscordAttachment {
id: string;
filename: string;
contentType?: string;
url: string;
size: number;
}
export declare class DiscordAdapter extends BaseAdapter {
private client;
constructor(config: Omit<AdapterConfig, 'type'> & {
credentials: DiscordCredentials;
});
/**
* Connect to Discord
*/
connect(): Promise<void>;
/**
* Disconnect from Discord
*/
disconnect(): Promise<void>;
/**
* Send a message to a Discord channel
*/
send(channelId: string, content: string, options?: SendOptions): Promise<string>;
/**
* Reply to a Discord message
*/
reply(message: UnifiedMessage, content: string, options?: SendOptions): Promise<string>;
private loadDiscordJs;
private getChannel;
private discordToUnified;
private getMimeCategory;
}
export declare function createDiscordAdapter(config: Omit<AdapterConfig, 'type'> & {
credentials: DiscordCredentials;
}): DiscordAdapter;
export default DiscordAdapter;
//# sourceMappingURL=DiscordAdapter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DiscordAdapter.d.ts","sourceRoot":"","sources":["DiscordAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,CAAC,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAMD,qBAAa,cAAe,SAAQ,WAAW;IAC7C,OAAO,CAAC,MAAM,CAAiB;gBAEnB,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG;QAAE,WAAW,EAAE,kBAAkB,CAAA;KAAE;IAIrF;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;OAEG;IACG,IAAI,CACR,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC;IAwBlB;;OAEG;IACG,KAAK,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC;YAYJ,aAAa;YAUb,UAAU;IASxB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,eAAe;CAMxB;AAMD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG;IAAE,WAAW,EAAE,kBAAkB,CAAA;CAAE,GACxE,cAAc,CAEhB;AAED,eAAe,cAAc,CAAC"}

View File

@@ -0,0 +1,197 @@
"use strict";
/**
* DiscordAdapter - Discord Channel Integration
*
* Connects to Discord servers using discord.js for real-time messaging.
* Supports threads, embeds, reactions, and slash commands.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.DiscordAdapter = void 0;
exports.createDiscordAdapter = createDiscordAdapter;
const BaseAdapter_js_1 = require("./BaseAdapter.js");
// ============================================================================
// DiscordAdapter Implementation
// ============================================================================
class DiscordAdapter extends BaseAdapter_js_1.BaseAdapter {
constructor(config) {
super({ ...config, type: 'discord' });
this.client = null;
}
/**
* Connect to Discord
*/
async connect() {
const credentials = this.config.credentials;
try {
// Dynamic import to avoid requiring discord.js if not used
const discordModule = await this.loadDiscordJs();
if (discordModule) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Client = discordModule.Client;
const GatewayIntentBits = discordModule.GatewayIntentBits;
this.client = new Client({
intents: credentials.intents ?? [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.DirectMessages,
],
});
// Register message handler
this.client.on('messageCreate', (message) => {
// Ignore bot messages
if (message.author.bot)
return;
const unified = this.discordToUnified(message);
this.emitMessage(unified);
});
// Login
await this.client.login(credentials.token);
this.status.connected = true;
}
else {
console.warn('DiscordAdapter: discord.js not available, running in mock mode');
this.status.connected = true;
}
}
catch (error) {
this.status.errorCount++;
throw new Error(`Failed to connect to Discord: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Disconnect from Discord
*/
async disconnect() {
if (this.client) {
await this.client.destroy?.();
this.client = null;
}
this.status.connected = false;
}
/**
* Send a message to a Discord channel
*/
async send(channelId, content, options) {
if (!this.client) {
throw new Error('DiscordAdapter not connected');
}
try {
const channel = await this.getChannel(channelId);
const sendOptions = { content };
if (options?.replyTo) {
sendOptions.reply = { messageReference: options.replyTo };
}
const result = await channel.send(sendOptions);
this.status.messageCount++;
return result.id;
}
catch (error) {
this.status.errorCount++;
throw error;
}
}
/**
* Reply to a Discord message
*/
async reply(message, content, options) {
return this.send(message.channelId, content, {
...options,
replyTo: message.id,
});
}
// ==========================================================================
// Private Methods
// ==========================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async loadDiscordJs() {
try {
// Dynamic import - discord.js is optional
// @ts-expect-error - discord.js may not be installed
return await Promise.resolve().then(() => __importStar(require('discord.js'))).catch(() => null);
}
catch {
return null;
}
}
async getChannel(channelId) {
if (!this.client) {
throw new Error('Client not connected');
}
const channels = this.client.channels;
return channels.fetch(channelId);
}
discordToUnified(message) {
const attachments = [];
message.attachments.forEach((attachment) => {
attachments.push({
id: attachment.id,
type: this.getMimeCategory(attachment.contentType ?? ''),
url: attachment.url,
mimeType: attachment.contentType,
filename: attachment.filename,
size: attachment.size,
});
});
return this.createUnifiedMessage(message.content, message.author.id, message.channelId, {
username: `${message.author.username}#${message.author.discriminator}`,
replyTo: message.reference?.messageId,
attachments: attachments.length > 0 ? attachments : undefined,
metadata: {
guildId: message.guildId,
originalId: message.id,
},
});
}
getMimeCategory(mimeType) {
if (mimeType.startsWith('image/'))
return 'image';
if (mimeType.startsWith('audio/'))
return 'audio';
if (mimeType.startsWith('video/'))
return 'video';
return 'file';
}
}
exports.DiscordAdapter = DiscordAdapter;
// ============================================================================
// Factory Function
// ============================================================================
function createDiscordAdapter(config) {
return new DiscordAdapter(config);
}
exports.default = DiscordAdapter;
//# sourceMappingURL=DiscordAdapter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DiscordAdapter.js","sourceRoot":"","sources":["DiscordAdapter.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,237 @@
/**
* DiscordAdapter - Discord Channel Integration
*
* Connects to Discord servers using discord.js for real-time messaging.
* Supports threads, embeds, reactions, and slash commands.
*/
import {
BaseAdapter,
type AdapterConfig,
type UnifiedMessage,
type SendOptions,
type Attachment,
} from './BaseAdapter.js';
// ============================================================================
// Types
// ============================================================================
export interface DiscordCredentials {
token: string; // Bot Token
clientId?: string; // Application Client ID
guildId?: string; // Optional: Specific guild to connect to
intents?: number[]; // Discord intents
}
export interface DiscordMessage {
id: string;
channelId: string;
guildId?: string;
author: {
id: string;
username: string;
discriminator: string;
};
content: string;
timestamp: Date;
reference?: {
messageId: string;
};
attachments: Map<string, DiscordAttachment>;
}
export interface DiscordAttachment {
id: string;
filename: string;
contentType?: string;
url: string;
size: number;
}
// ============================================================================
// DiscordAdapter Implementation
// ============================================================================
export class DiscordAdapter extends BaseAdapter {
private client: unknown = null;
constructor(config: Omit<AdapterConfig, 'type'> & { credentials: DiscordCredentials }) {
super({ ...config, type: 'discord' });
}
/**
* Connect to Discord
*/
async connect(): Promise<void> {
const credentials = this.config.credentials as unknown as DiscordCredentials;
try {
// Dynamic import to avoid requiring discord.js if not used
const discordModule = await this.loadDiscordJs();
if (discordModule) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Client = discordModule.Client as any;
const GatewayIntentBits = discordModule.GatewayIntentBits as Record<string, number>;
this.client = new Client({
intents: credentials.intents ?? [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.DirectMessages,
],
});
// Register message handler
(this.client as { on: (event: string, handler: (message: DiscordMessage) => void) => void }).on('messageCreate', (message: DiscordMessage) => {
// Ignore bot messages
if ((message as unknown as { author: { bot?: boolean } }).author.bot) return;
const unified = this.discordToUnified(message);
this.emitMessage(unified);
});
// Login
await (this.client as { login: (token: string) => Promise<void> }).login(credentials.token);
this.status.connected = true;
} else {
console.warn('DiscordAdapter: discord.js not available, running in mock mode');
this.status.connected = true;
}
} catch (error) {
this.status.errorCount++;
throw new Error(`Failed to connect to Discord: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Disconnect from Discord
*/
async disconnect(): Promise<void> {
if (this.client) {
await (this.client as { destroy?: () => Promise<void> }).destroy?.();
this.client = null;
}
this.status.connected = false;
}
/**
* Send a message to a Discord channel
*/
async send(
channelId: string,
content: string,
options?: SendOptions
): Promise<string> {
if (!this.client) {
throw new Error('DiscordAdapter not connected');
}
try {
const channel = await this.getChannel(channelId);
const sendOptions: Record<string, unknown> = { content };
if (options?.replyTo) {
sendOptions.reply = { messageReference: options.replyTo };
}
const result = await (channel as { send: (opts: unknown) => Promise<{ id: string }> }).send(sendOptions);
this.status.messageCount++;
return result.id;
} catch (error) {
this.status.errorCount++;
throw error;
}
}
/**
* Reply to a Discord message
*/
async reply(
message: UnifiedMessage,
content: string,
options?: SendOptions
): Promise<string> {
return this.send(message.channelId, content, {
...options,
replyTo: message.id,
});
}
// ==========================================================================
// Private Methods
// ==========================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async loadDiscordJs(): Promise<any | null> {
try {
// Dynamic import - discord.js is optional
// @ts-expect-error - discord.js may not be installed
return await import('discord.js').catch(() => null);
} catch {
return null;
}
}
private async getChannel(channelId: string): Promise<unknown> {
if (!this.client) {
throw new Error('Client not connected');
}
const channels = (this.client as { channels: { fetch: (id: string) => Promise<unknown> } }).channels;
return channels.fetch(channelId);
}
private discordToUnified(message: DiscordMessage): UnifiedMessage {
const attachments: Attachment[] = [];
message.attachments.forEach((attachment) => {
attachments.push({
id: attachment.id,
type: this.getMimeCategory(attachment.contentType ?? ''),
url: attachment.url,
mimeType: attachment.contentType,
filename: attachment.filename,
size: attachment.size,
});
});
return this.createUnifiedMessage(
message.content,
message.author.id,
message.channelId,
{
username: `${message.author.username}#${message.author.discriminator}`,
replyTo: message.reference?.messageId,
attachments: attachments.length > 0 ? attachments : undefined,
metadata: {
guildId: message.guildId,
originalId: message.id,
},
}
);
}
private getMimeCategory(mimeType: string): Attachment['type'] {
if (mimeType.startsWith('image/')) return 'image';
if (mimeType.startsWith('audio/')) return 'audio';
if (mimeType.startsWith('video/')) return 'video';
return 'file';
}
}
// ============================================================================
// Factory Function
// ============================================================================
export function createDiscordAdapter(
config: Omit<AdapterConfig, 'type'> & { credentials: DiscordCredentials }
): DiscordAdapter {
return new DiscordAdapter(config);
}
export default DiscordAdapter;

View File

@@ -0,0 +1,62 @@
/**
* SlackAdapter - Slack Channel Integration
*
* Connects to Slack workspace using @slack/bolt for real-time messaging.
* Supports threads, reactions, file attachments, and app mentions.
*/
import { BaseAdapter, type AdapterConfig, type UnifiedMessage, type SendOptions } from './BaseAdapter.js';
export interface SlackCredentials {
token: string;
signingSecret: string;
appToken?: string;
socketMode?: boolean;
}
export interface SlackMessage {
type: string;
channel: string;
user: string;
text: string;
ts: string;
thread_ts?: string;
files?: SlackFile[];
blocks?: unknown[];
}
export interface SlackFile {
id: string;
name: string;
mimetype: string;
url_private: string;
size: number;
}
export declare class SlackAdapter extends BaseAdapter {
private client;
private app;
constructor(config: Omit<AdapterConfig, 'type'> & {
credentials: SlackCredentials;
});
/**
* Connect to Slack
*/
connect(): Promise<void>;
/**
* Disconnect from Slack
*/
disconnect(): Promise<void>;
/**
* Send a message to a Slack channel
*/
send(channelId: string, content: string, options?: SendOptions): Promise<string>;
/**
* Reply to a Slack message
*/
reply(message: UnifiedMessage, content: string, options?: SendOptions): Promise<string>;
private loadSlackBolt;
private getClient;
private slackToUnified;
private getMimeCategory;
}
export declare function createSlackAdapter(config: Omit<AdapterConfig, 'type'> & {
credentials: SlackCredentials;
}): SlackAdapter;
export default SlackAdapter;
//# sourceMappingURL=SlackAdapter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SlackAdapter.d.ts","sourceRoot":"","sources":["SlackAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAgBD,qBAAa,YAAa,SAAQ,WAAW;IAC3C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,GAAG,CAAiB;gBAEhB,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG;QAAE,WAAW,EAAE,gBAAgB,CAAA;KAAE;IAInF;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;OAEG;IACG,IAAI,CACR,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC;IAsBlB;;OAEG;IACG,KAAK,CACT,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC;YAYJ,aAAa;IAQ3B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,eAAe;CAMxB;AAMD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG;IAAE,WAAW,EAAE,gBAAgB,CAAA;CAAE,GACtE,YAAY,CAEd;AAED,eAAe,YAAY,CAAC"}

View File

@@ -0,0 +1,193 @@
"use strict";
/**
* SlackAdapter - Slack Channel Integration
*
* Connects to Slack workspace using @slack/bolt for real-time messaging.
* Supports threads, reactions, file attachments, and app mentions.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.SlackAdapter = void 0;
exports.createSlackAdapter = createSlackAdapter;
const BaseAdapter_js_1 = require("./BaseAdapter.js");
// ============================================================================
// SlackAdapter Implementation
// ============================================================================
class SlackAdapter extends BaseAdapter_js_1.BaseAdapter {
constructor(config) {
super({ ...config, type: 'slack' });
this.client = null;
this.app = null;
}
/**
* Connect to Slack
*/
async connect() {
const credentials = this.config.credentials;
try {
// Dynamic import to avoid requiring @slack/bolt if not used
const boltModule = await this.loadSlackBolt();
if (boltModule) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const App = boltModule.App;
this.app = new App({
token: credentials.token,
signingSecret: credentials.signingSecret,
socketMode: credentials.socketMode ?? false,
appToken: credentials.appToken,
});
// Register message handler
const app = this.app;
const self = this;
app.message(async function (args) {
const unified = self.slackToUnified(args.message);
await self.emitMessage(unified);
});
// Start the app
await this.app.start();
this.status.connected = true;
}
else {
// Fallback: Mark as connected but log warning
console.warn('SlackAdapter: @slack/bolt not available, running in mock mode');
this.status.connected = true;
}
}
catch (error) {
this.status.errorCount++;
throw new Error(`Failed to connect to Slack: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Disconnect from Slack
*/
async disconnect() {
if (this.app) {
await this.app.stop?.();
this.app = null;
}
this.status.connected = false;
}
/**
* Send a message to a Slack channel
*/
async send(channelId, content, options) {
if (!this.client && !this.app) {
throw new Error('SlackAdapter not connected');
}
try {
const client = this.getClient();
const result = await client.chat.postMessage({
channel: channelId,
text: content,
thread_ts: options?.threadId,
});
this.status.messageCount++;
return result.ts;
}
catch (error) {
this.status.errorCount++;
throw error;
}
}
/**
* Reply to a Slack message
*/
async reply(message, content, options) {
return this.send(message.channelId, content, {
...options,
threadId: message.threadId ?? message.metadata.ts,
});
}
// ==========================================================================
// Private Methods
// ==========================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async loadSlackBolt() {
try {
return await Promise.resolve().then(() => __importStar(require('@slack/bolt')));
}
catch {
return null;
}
}
getClient() {
if (this.app) {
return this.app.client;
}
// Mock client for testing
return {
chat: {
postMessage: async () => ({ ts: Date.now().toString() }),
},
};
}
slackToUnified(message) {
const attachments = (message.files ?? []).map(file => ({
id: file.id,
type: this.getMimeCategory(file.mimetype),
url: file.url_private,
mimeType: file.mimetype,
filename: file.name,
size: file.size,
}));
return this.createUnifiedMessage(message.text, message.user, message.channel, {
threadId: message.thread_ts,
attachments: attachments.length > 0 ? attachments : undefined,
metadata: {
ts: message.ts,
blocks: message.blocks,
},
});
}
getMimeCategory(mimeType) {
if (mimeType.startsWith('image/'))
return 'image';
if (mimeType.startsWith('audio/'))
return 'audio';
if (mimeType.startsWith('video/'))
return 'video';
return 'file';
}
}
exports.SlackAdapter = SlackAdapter;
// ============================================================================
// Factory Function
// ============================================================================
function createSlackAdapter(config) {
return new SlackAdapter(config);
}
exports.default = SlackAdapter;
//# sourceMappingURL=SlackAdapter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SlackAdapter.js","sourceRoot":"","sources":["SlackAdapter.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,233 @@
/**
* SlackAdapter - Slack Channel Integration
*
* Connects to Slack workspace using @slack/bolt for real-time messaging.
* Supports threads, reactions, file attachments, and app mentions.
*/
import {
BaseAdapter,
type AdapterConfig,
type UnifiedMessage,
type SendOptions,
type Attachment,
} from './BaseAdapter.js';
// ============================================================================
// Types
// ============================================================================
export interface SlackCredentials {
token: string; // Bot User OAuth Token (xoxb-)
signingSecret: string; // App Signing Secret
appToken?: string; // App-Level Token for Socket Mode (xapp-)
socketMode?: boolean;
}
export interface SlackMessage {
type: string;
channel: string;
user: string;
text: string;
ts: string;
thread_ts?: string;
files?: SlackFile[];
blocks?: unknown[];
}
export interface SlackFile {
id: string;
name: string;
mimetype: string;
url_private: string;
size: number;
}
interface SlackClient {
chat: {
postMessage: (args: {
channel: string;
text: string;
thread_ts?: string;
}) => Promise<{ ts: string }>;
};
}
// ============================================================================
// SlackAdapter Implementation
// ============================================================================
export class SlackAdapter extends BaseAdapter {
private client: unknown = null;
private app: unknown = null;
constructor(config: Omit<AdapterConfig, 'type'> & { credentials: SlackCredentials }) {
super({ ...config, type: 'slack' });
}
/**
* Connect to Slack
*/
async connect(): Promise<void> {
const credentials = this.config.credentials as unknown as SlackCredentials;
try {
// Dynamic import to avoid requiring @slack/bolt if not used
const boltModule = await this.loadSlackBolt();
if (boltModule) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const App = boltModule.App as any;
this.app = new App({
token: credentials.token,
signingSecret: credentials.signingSecret,
socketMode: credentials.socketMode ?? false,
appToken: credentials.appToken,
});
// Register message handler
const app = this.app as { message: (handler: (args: { message: SlackMessage }) => Promise<void>) => void };
const self = this;
app.message(async function(args: { message: SlackMessage }) {
const unified = self.slackToUnified(args.message);
await self.emitMessage(unified);
});
// Start the app
await (this.app as { start: () => Promise<void> }).start();
this.status.connected = true;
} else {
// Fallback: Mark as connected but log warning
console.warn('SlackAdapter: @slack/bolt not available, running in mock mode');
this.status.connected = true;
}
} catch (error) {
this.status.errorCount++;
throw new Error(`Failed to connect to Slack: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Disconnect from Slack
*/
async disconnect(): Promise<void> {
if (this.app) {
await (this.app as { stop?: () => Promise<void> }).stop?.();
this.app = null;
}
this.status.connected = false;
}
/**
* Send a message to a Slack channel
*/
async send(
channelId: string,
content: string,
options?: SendOptions
): Promise<string> {
if (!this.client && !this.app) {
throw new Error('SlackAdapter not connected');
}
try {
const client = this.getClient();
const result = await client.chat.postMessage({
channel: channelId,
text: content,
thread_ts: options?.threadId,
});
this.status.messageCount++;
return result.ts as string;
} catch (error) {
this.status.errorCount++;
throw error;
}
}
/**
* Reply to a Slack message
*/
async reply(
message: UnifiedMessage,
content: string,
options?: SendOptions
): Promise<string> {
return this.send(message.channelId, content, {
...options,
threadId: message.threadId ?? message.metadata.ts as string,
});
}
// ==========================================================================
// Private Methods
// ==========================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async loadSlackBolt(): Promise<any | null> {
try {
return await import('@slack/bolt');
} catch {
return null;
}
}
private getClient(): SlackClient {
if (this.app) {
return (this.app as { client: SlackClient }).client;
}
// Mock client for testing
return {
chat: {
postMessage: async () => ({ ts: Date.now().toString() }),
},
};
}
private slackToUnified(message: SlackMessage): UnifiedMessage {
const attachments: Attachment[] = (message.files ?? []).map(file => ({
id: file.id,
type: this.getMimeCategory(file.mimetype),
url: file.url_private,
mimeType: file.mimetype,
filename: file.name,
size: file.size,
}));
return this.createUnifiedMessage(
message.text,
message.user,
message.channel,
{
threadId: message.thread_ts,
attachments: attachments.length > 0 ? attachments : undefined,
metadata: {
ts: message.ts,
blocks: message.blocks,
},
}
);
}
private getMimeCategory(mimeType: string): Attachment['type'] {
if (mimeType.startsWith('image/')) return 'image';
if (mimeType.startsWith('audio/')) return 'audio';
if (mimeType.startsWith('video/')) return 'video';
return 'file';
}
}
// ============================================================================
// Factory Function
// ============================================================================
export function createSlackAdapter(
config: Omit<AdapterConfig, 'type'> & { credentials: SlackCredentials }
): SlackAdapter {
return new SlackAdapter(config);
}
export default SlackAdapter;

View File

@@ -0,0 +1,93 @@
/**
* TelegramAdapter - Telegram Channel Integration
*
* Connects to Telegram using telegraf for real-time messaging.
* Supports inline keyboards, commands, and rich media.
*/
import { BaseAdapter, type AdapterConfig, type UnifiedMessage, type SendOptions } from './BaseAdapter.js';
export interface TelegramCredentials {
token: string;
webhookUrl?: string;
pollingTimeout?: number;
}
export interface TelegramMessage {
message_id: number;
chat: {
id: number;
type: string;
title?: string;
username?: string;
};
from: {
id: number;
username?: string;
first_name: string;
last_name?: string;
};
text?: string;
date: number;
reply_to_message?: TelegramMessage;
photo?: TelegramPhoto[];
document?: TelegramDocument;
audio?: TelegramAudio;
video?: TelegramVideo;
}
export interface TelegramPhoto {
file_id: string;
file_unique_id: string;
width: number;
height: number;
file_size?: number;
}
export interface TelegramDocument {
file_id: string;
file_unique_id: string;
file_name?: string;
mime_type?: string;
file_size?: number;
}
export interface TelegramAudio {
file_id: string;
file_unique_id: string;
duration: number;
performer?: string;
title?: string;
file_size?: number;
}
export interface TelegramVideo {
file_id: string;
file_unique_id: string;
width: number;
height: number;
duration: number;
file_size?: number;
}
export declare class TelegramAdapter extends BaseAdapter {
private bot;
constructor(config: Omit<AdapterConfig, 'type'> & {
credentials: TelegramCredentials;
});
/**
* Connect to Telegram
*/
connect(): Promise<void>;
/**
* Disconnect from Telegram
*/
disconnect(): Promise<void>;
/**
* Send a message to a Telegram chat
*/
send(channelId: string, content: string, options?: SendOptions): Promise<string>;
/**
* Reply to a Telegram message
*/
reply(message: UnifiedMessage, content: string, options?: SendOptions): Promise<string>;
private loadTelegraf;
private telegramToUnified;
}
export declare function createTelegramAdapter(config: Omit<AdapterConfig, 'type'> & {
credentials: TelegramCredentials;
}): TelegramAdapter;
export default TelegramAdapter;
//# sourceMappingURL=TelegramAdapter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"TelegramAdapter.d.ts","sourceRoot":"","sources":["TelegramAdapter.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,204 @@
"use strict";
/**
* TelegramAdapter - Telegram Channel Integration
*
* Connects to Telegram using telegraf for real-time messaging.
* Supports inline keyboards, commands, and rich media.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelegramAdapter = void 0;
exports.createTelegramAdapter = createTelegramAdapter;
const BaseAdapter_js_1 = require("./BaseAdapter.js");
// ============================================================================
// TelegramAdapter Implementation
// ============================================================================
class TelegramAdapter extends BaseAdapter_js_1.BaseAdapter {
constructor(config) {
super({ ...config, type: 'telegram' });
this.bot = null;
}
/**
* Connect to Telegram
*/
async connect() {
const credentials = this.config.credentials;
try {
// Dynamic import to avoid requiring telegraf if not used
const telegrafModule = await this.loadTelegraf();
if (telegrafModule) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Telegraf = telegrafModule.Telegraf;
this.bot = new Telegraf(credentials.token);
// Register message handler
this.bot.on('message', (ctx) => {
const unified = this.telegramToUnified(ctx.message);
this.emitMessage(unified);
});
// Start polling or webhook
if (credentials.webhookUrl) {
await this.bot.telegram.setWebhook(credentials.webhookUrl);
}
else {
this.bot.launch();
}
this.status.connected = true;
}
else {
console.warn('TelegramAdapter: telegraf not available, running in mock mode');
this.status.connected = true;
}
}
catch (error) {
this.status.errorCount++;
throw new Error(`Failed to connect to Telegram: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Disconnect from Telegram
*/
async disconnect() {
if (this.bot) {
this.bot.stop?.('SIGTERM');
this.bot = null;
}
this.status.connected = false;
}
/**
* Send a message to a Telegram chat
*/
async send(channelId, content, options) {
if (!this.bot) {
throw new Error('TelegramAdapter not connected');
}
try {
const telegram = this.bot.telegram;
const extra = {};
if (options?.replyTo) {
extra.reply_to_message_id = parseInt(options.replyTo, 10);
}
const result = await telegram.sendMessage(channelId, content, Object.keys(extra).length > 0 ? extra : undefined);
this.status.messageCount++;
return result.message_id.toString();
}
catch (error) {
this.status.errorCount++;
throw error;
}
}
/**
* Reply to a Telegram message
*/
async reply(message, content, options) {
return this.send(message.channelId, content, {
...options,
replyTo: message.metadata.messageId,
});
}
// ==========================================================================
// Private Methods
// ==========================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async loadTelegraf() {
try {
// Dynamic import - telegraf is optional
// @ts-expect-error - telegraf may not be installed
return await Promise.resolve().then(() => __importStar(require('telegraf'))).catch(() => null);
}
catch {
return null;
}
}
telegramToUnified(message) {
const attachments = [];
// Handle photos (get largest)
if (message.photo && message.photo.length > 0) {
const photo = message.photo[message.photo.length - 1];
attachments.push({
id: photo.file_id,
type: 'image',
size: photo.file_size,
});
}
// Handle document
if (message.document) {
attachments.push({
id: message.document.file_id,
type: 'file',
filename: message.document.file_name,
mimeType: message.document.mime_type,
size: message.document.file_size,
});
}
// Handle audio
if (message.audio) {
attachments.push({
id: message.audio.file_id,
type: 'audio',
size: message.audio.file_size,
});
}
// Handle video
if (message.video) {
attachments.push({
id: message.video.file_id,
type: 'video',
size: message.video.file_size,
});
}
const username = message.from.username ??
`${message.from.first_name}${message.from.last_name ? ' ' + message.from.last_name : ''}`;
return this.createUnifiedMessage(message.text ?? '[media]', message.from.id.toString(), message.chat.id.toString(), {
username,
replyTo: message.reply_to_message?.message_id.toString(),
timestamp: new Date(message.date * 1000),
attachments: attachments.length > 0 ? attachments : undefined,
metadata: {
messageId: message.message_id.toString(),
chatType: message.chat.type,
chatTitle: message.chat.title,
},
});
}
}
exports.TelegramAdapter = TelegramAdapter;
// ============================================================================
// Factory Function
// ============================================================================
function createTelegramAdapter(config) {
return new TelegramAdapter(config);
}
exports.default = TelegramAdapter;
//# sourceMappingURL=TelegramAdapter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"TelegramAdapter.js","sourceRoot":"","sources":["TelegramAdapter.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,289 @@
/**
* TelegramAdapter - Telegram Channel Integration
*
* Connects to Telegram using telegraf for real-time messaging.
* Supports inline keyboards, commands, and rich media.
*/
import {
BaseAdapter,
type AdapterConfig,
type UnifiedMessage,
type SendOptions,
type Attachment,
} from './BaseAdapter.js';
// ============================================================================
// Types
// ============================================================================
export interface TelegramCredentials {
token: string; // Bot Token from @BotFather
webhookUrl?: string; // Optional webhook URL for production
pollingTimeout?: number; // Long polling timeout
}
export interface TelegramMessage {
message_id: number;
chat: {
id: number;
type: string;
title?: string;
username?: string;
};
from: {
id: number;
username?: string;
first_name: string;
last_name?: string;
};
text?: string;
date: number;
reply_to_message?: TelegramMessage;
photo?: TelegramPhoto[];
document?: TelegramDocument;
audio?: TelegramAudio;
video?: TelegramVideo;
}
export interface TelegramPhoto {
file_id: string;
file_unique_id: string;
width: number;
height: number;
file_size?: number;
}
export interface TelegramDocument {
file_id: string;
file_unique_id: string;
file_name?: string;
mime_type?: string;
file_size?: number;
}
export interface TelegramAudio {
file_id: string;
file_unique_id: string;
duration: number;
performer?: string;
title?: string;
file_size?: number;
}
export interface TelegramVideo {
file_id: string;
file_unique_id: string;
width: number;
height: number;
duration: number;
file_size?: number;
}
// ============================================================================
// TelegramAdapter Implementation
// ============================================================================
export class TelegramAdapter extends BaseAdapter {
private bot: unknown = null;
constructor(config: Omit<AdapterConfig, 'type'> & { credentials: TelegramCredentials }) {
super({ ...config, type: 'telegram' });
}
/**
* Connect to Telegram
*/
async connect(): Promise<void> {
const credentials = this.config.credentials as unknown as TelegramCredentials;
try {
// Dynamic import to avoid requiring telegraf if not used
const telegrafModule = await this.loadTelegraf();
if (telegrafModule) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Telegraf = telegrafModule.Telegraf as any;
this.bot = new Telegraf(credentials.token);
// Register message handler
(this.bot as { on: (event: string, handler: (ctx: { message: TelegramMessage }) => void) => void }).on('message', (ctx: { message: TelegramMessage }) => {
const unified = this.telegramToUnified(ctx.message);
this.emitMessage(unified);
});
// Start polling or webhook
if (credentials.webhookUrl) {
await (this.bot as {
telegram: {
setWebhook: (url: string) => Promise<void>
}
}).telegram.setWebhook(credentials.webhookUrl);
} else {
(this.bot as { launch: () => void }).launch();
}
this.status.connected = true;
} else {
console.warn('TelegramAdapter: telegraf not available, running in mock mode');
this.status.connected = true;
}
} catch (error) {
this.status.errorCount++;
throw new Error(`Failed to connect to Telegram: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Disconnect from Telegram
*/
async disconnect(): Promise<void> {
if (this.bot) {
(this.bot as { stop?: (signal?: string) => void }).stop?.('SIGTERM');
this.bot = null;
}
this.status.connected = false;
}
/**
* Send a message to a Telegram chat
*/
async send(
channelId: string,
content: string,
options?: SendOptions
): Promise<string> {
if (!this.bot) {
throw new Error('TelegramAdapter not connected');
}
try {
const telegram = (this.bot as { telegram: unknown }).telegram as {
sendMessage: (chatId: string | number, text: string, extra?: unknown) => Promise<{ message_id: number }>;
};
const extra: Record<string, unknown> = {};
if (options?.replyTo) {
extra.reply_to_message_id = parseInt(options.replyTo, 10);
}
const result = await telegram.sendMessage(
channelId,
content,
Object.keys(extra).length > 0 ? extra : undefined
);
this.status.messageCount++;
return result.message_id.toString();
} catch (error) {
this.status.errorCount++;
throw error;
}
}
/**
* Reply to a Telegram message
*/
async reply(
message: UnifiedMessage,
content: string,
options?: SendOptions
): Promise<string> {
return this.send(message.channelId, content, {
...options,
replyTo: message.metadata.messageId as string,
});
}
// ==========================================================================
// Private Methods
// ==========================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async loadTelegraf(): Promise<any | null> {
try {
// Dynamic import - telegraf is optional
// @ts-expect-error - telegraf may not be installed
return await import('telegraf').catch(() => null);
} catch {
return null;
}
}
private telegramToUnified(message: TelegramMessage): UnifiedMessage {
const attachments: Attachment[] = [];
// Handle photos (get largest)
if (message.photo && message.photo.length > 0) {
const photo = message.photo[message.photo.length - 1];
attachments.push({
id: photo.file_id,
type: 'image',
size: photo.file_size,
});
}
// Handle document
if (message.document) {
attachments.push({
id: message.document.file_id,
type: 'file',
filename: message.document.file_name,
mimeType: message.document.mime_type,
size: message.document.file_size,
});
}
// Handle audio
if (message.audio) {
attachments.push({
id: message.audio.file_id,
type: 'audio',
size: message.audio.file_size,
});
}
// Handle video
if (message.video) {
attachments.push({
id: message.video.file_id,
type: 'video',
size: message.video.file_size,
});
}
const username = message.from.username ??
`${message.from.first_name}${message.from.last_name ? ' ' + message.from.last_name : ''}`;
return this.createUnifiedMessage(
message.text ?? '[media]',
message.from.id.toString(),
message.chat.id.toString(),
{
username,
replyTo: message.reply_to_message?.message_id.toString(),
timestamp: new Date(message.date * 1000),
attachments: attachments.length > 0 ? attachments : undefined,
metadata: {
messageId: message.message_id.toString(),
chatType: message.chat.type,
chatTitle: message.chat.title,
},
}
);
}
}
// ============================================================================
// Factory Function
// ============================================================================
export function createTelegramAdapter(
config: Omit<AdapterConfig, 'type'> & { credentials: TelegramCredentials }
): TelegramAdapter {
return new TelegramAdapter(config);
}
export default TelegramAdapter;

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,WAAW,EACX,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACrG,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAC7G,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAGjH,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,GACpB,MAAM,sBAAsB,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,yBAAyB;AACzB,4DAUmC;AATjC,6GAAA,WAAW,OAAA;AAWb,mBAAmB;AACnB,8DAAqG;AAA5F,+GAAA,YAAY,OAAA;AAAE,qHAAA,kBAAkB,OAAA;AACzC,kEAA6G;AAApG,mHAAA,cAAc,OAAA;AAAE,yHAAA,oBAAoB,OAAA;AAC7C,oEAAiH;AAAxG,qHAAA,eAAe,OAAA;AAAE,2HAAA,qBAAqB,OAAA;AAE/C,mBAAmB;AACnB,2DAM8B;AAL5B,qHAAA,eAAe,OAAA;AACf,2HAAA,qBAAqB,OAAA"}

View File

@@ -0,0 +1,32 @@
/**
* Channels module exports
*
* Multi-channel messaging support with unified interface.
*/
// Base adapter and types
export {
BaseAdapter,
type ChannelType,
type Attachment,
type UnifiedMessage,
type SendOptions,
type ChannelCredentials,
type AdapterConfig,
type AdapterStatus,
type MessageHandler,
} from './adapters/BaseAdapter.js';
// Channel adapters
export { SlackAdapter, createSlackAdapter, type SlackCredentials } from './adapters/SlackAdapter.js';
export { DiscordAdapter, createDiscordAdapter, type DiscordCredentials } from './adapters/DiscordAdapter.js';
export { TelegramAdapter, createTelegramAdapter, type TelegramCredentials } from './adapters/TelegramAdapter.js';
// Channel registry
export {
ChannelRegistry,
createChannelRegistry,
type ChannelFilter,
type ChannelRegistryConfig,
type AdapterFactory,
} from './ChannelRegistry.js';