Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
94
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.d.ts
vendored
Normal file
94
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.d.ts
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.d.ts.map
vendored
Normal 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"}
|
||||
230
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.js
vendored
Normal file
230
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.js
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
306
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.ts
vendored
Normal file
306
vendor/ruvector/npm/packages/ruvbot/src/channels/ChannelRegistry.ts
vendored
Normal 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;
|
||||
120
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.d.ts
vendored
Normal file
120
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.d.ts
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"BaseAdapter.d.ts","sourceRoot":"","sources":["BaseAdapter.ts"],"names":[],"mappings":"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"}
|
||||
101
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.js
vendored
Normal file
101
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.js
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.js.map
vendored
Normal 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"}
|
||||
232
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.ts
vendored
Normal file
232
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/BaseAdapter.ts
vendored
Normal 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;
|
||||
67
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.d.ts
vendored
Normal file
67
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.d.ts
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.d.ts.map
vendored
Normal 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"}
|
||||
197
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.js
vendored
Normal file
197
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.js
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"DiscordAdapter.js","sourceRoot":"","sources":["DiscordAdapter.ts"],"names":[],"mappings":"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"}
|
||||
237
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.ts
vendored
Normal file
237
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/DiscordAdapter.ts
vendored
Normal 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;
|
||||
62
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.d.ts
vendored
Normal file
62
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.d.ts
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.d.ts.map
vendored
Normal 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"}
|
||||
193
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.js
vendored
Normal file
193
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.js
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"SlackAdapter.js","sourceRoot":"","sources":["SlackAdapter.ts"],"names":[],"mappings":"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"}
|
||||
233
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.ts
vendored
Normal file
233
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/SlackAdapter.ts
vendored
Normal 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;
|
||||
93
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.d.ts
vendored
Normal file
93
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.d.ts
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"TelegramAdapter.d.ts","sourceRoot":"","sources":["TelegramAdapter.ts"],"names":[],"mappings":"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"}
|
||||
204
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.js
vendored
Normal file
204
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.js
vendored
Normal 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
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"TelegramAdapter.js","sourceRoot":"","sources":["TelegramAdapter.ts"],"names":[],"mappings":"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"}
|
||||
289
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.ts
vendored
Normal file
289
vendor/ruvector/npm/packages/ruvbot/src/channels/adapters/TelegramAdapter.ts
vendored
Normal 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;
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/index.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/index.d.ts.map
vendored
Normal 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"}
|
||||
1
vendor/ruvector/npm/packages/ruvbot/src/channels/index.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/ruvbot/src/channels/index.js.map
vendored
Normal 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"}
|
||||
32
vendor/ruvector/npm/packages/ruvbot/src/channels/index.ts
vendored
Normal file
32
vendor/ruvector/npm/packages/ruvbot/src/channels/index.ts
vendored
Normal 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';
|
||||
Reference in New Issue
Block a user