@auxiora/channels 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +191 -0
  2. package/dist/adapters/bluebubbles.d.ts +63 -0
  3. package/dist/adapters/bluebubbles.d.ts.map +1 -0
  4. package/dist/adapters/bluebubbles.js +197 -0
  5. package/dist/adapters/bluebubbles.js.map +1 -0
  6. package/dist/adapters/discord.d.ts +27 -0
  7. package/dist/adapters/discord.d.ts.map +1 -0
  8. package/dist/adapters/discord.js +202 -0
  9. package/dist/adapters/discord.js.map +1 -0
  10. package/dist/adapters/email.d.ts +39 -0
  11. package/dist/adapters/email.d.ts.map +1 -0
  12. package/dist/adapters/email.js +359 -0
  13. package/dist/adapters/email.js.map +1 -0
  14. package/dist/adapters/googlechat.d.ts +77 -0
  15. package/dist/adapters/googlechat.d.ts.map +1 -0
  16. package/dist/adapters/googlechat.js +232 -0
  17. package/dist/adapters/googlechat.js.map +1 -0
  18. package/dist/adapters/matrix.d.ts +37 -0
  19. package/dist/adapters/matrix.d.ts.map +1 -0
  20. package/dist/adapters/matrix.js +262 -0
  21. package/dist/adapters/matrix.js.map +1 -0
  22. package/dist/adapters/signal.d.ts +32 -0
  23. package/dist/adapters/signal.d.ts.map +1 -0
  24. package/dist/adapters/signal.js +216 -0
  25. package/dist/adapters/signal.js.map +1 -0
  26. package/dist/adapters/slack.d.ts +29 -0
  27. package/dist/adapters/slack.d.ts.map +1 -0
  28. package/dist/adapters/slack.js +202 -0
  29. package/dist/adapters/slack.js.map +1 -0
  30. package/dist/adapters/teams.d.ts +66 -0
  31. package/dist/adapters/teams.d.ts.map +1 -0
  32. package/dist/adapters/teams.js +227 -0
  33. package/dist/adapters/teams.js.map +1 -0
  34. package/dist/adapters/telegram.d.ts +28 -0
  35. package/dist/adapters/telegram.d.ts.map +1 -0
  36. package/dist/adapters/telegram.js +170 -0
  37. package/dist/adapters/telegram.js.map +1 -0
  38. package/dist/adapters/twilio.d.ts +63 -0
  39. package/dist/adapters/twilio.d.ts.map +1 -0
  40. package/dist/adapters/twilio.js +193 -0
  41. package/dist/adapters/twilio.js.map +1 -0
  42. package/dist/adapters/whatsapp.d.ts +99 -0
  43. package/dist/adapters/whatsapp.d.ts.map +1 -0
  44. package/dist/adapters/whatsapp.js +218 -0
  45. package/dist/adapters/whatsapp.js.map +1 -0
  46. package/dist/adapters/zalo.d.ts +64 -0
  47. package/dist/adapters/zalo.d.ts.map +1 -0
  48. package/dist/adapters/zalo.js +216 -0
  49. package/dist/adapters/zalo.js.map +1 -0
  50. package/dist/index.d.ts +15 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +16 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/manager.d.ts +35 -0
  55. package/dist/manager.d.ts.map +1 -0
  56. package/dist/manager.js +127 -0
  57. package/dist/manager.js.map +1 -0
  58. package/dist/types.d.ts +71 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +2 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +32 -0
  63. package/src/adapters/bluebubbles.ts +294 -0
  64. package/src/adapters/discord.ts +253 -0
  65. package/src/adapters/email.ts +457 -0
  66. package/src/adapters/googlechat.ts +364 -0
  67. package/src/adapters/matrix.ts +376 -0
  68. package/src/adapters/signal.ts +313 -0
  69. package/src/adapters/slack.ts +252 -0
  70. package/src/adapters/teams.ts +320 -0
  71. package/src/adapters/telegram.ts +208 -0
  72. package/src/adapters/twilio.ts +256 -0
  73. package/src/adapters/whatsapp.ts +342 -0
  74. package/src/adapters/zalo.ts +319 -0
  75. package/src/index.ts +78 -0
  76. package/src/manager.ts +180 -0
  77. package/src/types.ts +84 -0
  78. package/tests/bluebubbles.test.ts +438 -0
  79. package/tests/email.test.ts +136 -0
  80. package/tests/googlechat.test.ts +439 -0
  81. package/tests/matrix.test.ts +564 -0
  82. package/tests/signal.test.ts +404 -0
  83. package/tests/slack.test.ts +343 -0
  84. package/tests/teams.test.ts +429 -0
  85. package/tests/twilio.test.ts +269 -0
  86. package/tests/whatsapp.test.ts +530 -0
  87. package/tests/zalo.test.ts +499 -0
  88. package/tsconfig.json +8 -0
  89. package/tsconfig.tsbuildinfo +1 -0
package/src/index.ts ADDED
@@ -0,0 +1,78 @@
1
+ // Types
2
+ export type {
3
+ ChannelType,
4
+ ChannelAdapter,
5
+ ChannelConfig,
6
+ InboundMessage,
7
+ OutboundMessage,
8
+ SendResult,
9
+ Attachment,
10
+ } from './types.js';
11
+
12
+ // Adapters
13
+ export {
14
+ DiscordAdapter,
15
+ type DiscordAdapterConfig,
16
+ } from './adapters/discord.js';
17
+
18
+ export {
19
+ TelegramAdapter,
20
+ type TelegramAdapterConfig,
21
+ } from './adapters/telegram.js';
22
+
23
+ export {
24
+ SlackAdapter,
25
+ type SlackAdapterConfig,
26
+ } from './adapters/slack.js';
27
+
28
+ export {
29
+ TwilioAdapter,
30
+ type TwilioAdapterConfig,
31
+ type TwilioWebhookBody,
32
+ } from './adapters/twilio.js';
33
+
34
+ export {
35
+ MatrixAdapter,
36
+ type MatrixAdapterConfig,
37
+ } from './adapters/matrix.js';
38
+
39
+ export {
40
+ SignalAdapter,
41
+ type SignalAdapterConfig,
42
+ } from './adapters/signal.js';
43
+
44
+ export {
45
+ EmailAdapter,
46
+ type EmailAdapterConfig,
47
+ } from './adapters/email.js';
48
+
49
+ export {
50
+ TeamsAdapter,
51
+ type TeamsAdapterConfig,
52
+ } from './adapters/teams.js';
53
+
54
+ export {
55
+ WhatsAppAdapter,
56
+ type WhatsAppAdapterConfig,
57
+ } from './adapters/whatsapp.js';
58
+
59
+ export {
60
+ GoogleChatAdapter,
61
+ type GoogleChatAdapterConfig,
62
+ } from './adapters/googlechat.js';
63
+
64
+ export {
65
+ BlueBubblesAdapter,
66
+ type BlueBubblesAdapterConfig,
67
+ } from './adapters/bluebubbles.js';
68
+
69
+ export {
70
+ ZaloAdapter,
71
+ type ZaloAdapterConfig,
72
+ } from './adapters/zalo.js';
73
+
74
+ // Manager
75
+ export {
76
+ ChannelManager,
77
+ type ChannelManagerConfig,
78
+ } from './manager.js';
package/src/manager.ts ADDED
@@ -0,0 +1,180 @@
1
+ import { audit } from '@auxiora/audit';
2
+ import { getLogger } from '@auxiora/logger';
3
+
4
+ const logger = getLogger('channels');
5
+ import type {
6
+ ChannelAdapter,
7
+ ChannelType,
8
+ ChannelConfig,
9
+ InboundMessage,
10
+ OutboundMessage,
11
+ SendResult,
12
+ } from './types.js';
13
+ import { DiscordAdapter, type DiscordAdapterConfig } from './adapters/discord.js';
14
+ import { TelegramAdapter, type TelegramAdapterConfig } from './adapters/telegram.js';
15
+ import { SlackAdapter, type SlackAdapterConfig } from './adapters/slack.js';
16
+ import { TwilioAdapter, type TwilioAdapterConfig } from './adapters/twilio.js';
17
+ import { GoogleChatAdapter, type GoogleChatAdapterConfig } from './adapters/googlechat.js';
18
+ import { BlueBubblesAdapter, type BlueBubblesAdapterConfig } from './adapters/bluebubbles.js';
19
+ import { ZaloAdapter, type ZaloAdapterConfig } from './adapters/zalo.js';
20
+
21
+ export interface ChannelManagerConfig {
22
+ discord?: DiscordAdapterConfig;
23
+ telegram?: TelegramAdapterConfig;
24
+ slack?: SlackAdapterConfig;
25
+ twilio?: TwilioAdapterConfig;
26
+ googlechat?: GoogleChatAdapterConfig;
27
+ bluebubbles?: BlueBubblesAdapterConfig;
28
+ zalo?: ZaloAdapterConfig;
29
+ }
30
+
31
+ export class ChannelManager {
32
+ private adapters: Map<ChannelType, ChannelAdapter> = new Map();
33
+ private messageHandler?: (message: InboundMessage) => Promise<void>;
34
+ private errorHandler?: (error: Error, channelType: ChannelType) => void;
35
+
36
+ constructor(config: ChannelManagerConfig) {
37
+ // Initialize configured adapters
38
+ if (config.discord?.token) {
39
+ this.adapters.set('discord', new DiscordAdapter(config.discord));
40
+ }
41
+
42
+ if (config.telegram?.token) {
43
+ this.adapters.set('telegram', new TelegramAdapter(config.telegram));
44
+ }
45
+
46
+ if (config.slack?.botToken && config.slack?.appToken) {
47
+ this.adapters.set('slack', new SlackAdapter(config.slack));
48
+ }
49
+
50
+ if (config.twilio?.accountSid && config.twilio?.authToken) {
51
+ this.adapters.set('twilio', new TwilioAdapter(config.twilio));
52
+ }
53
+
54
+ if (config.googlechat?.serviceAccountKey) {
55
+ this.adapters.set('googlechat', new GoogleChatAdapter(config.googlechat));
56
+ }
57
+
58
+ if (config.bluebubbles?.serverUrl && config.bluebubbles?.password) {
59
+ this.adapters.set('bluebubbles', new BlueBubblesAdapter(config.bluebubbles));
60
+ }
61
+
62
+ if (config.zalo?.oaAccessToken && config.zalo?.oaSecretKey) {
63
+ this.adapters.set('zalo', new ZaloAdapter(config.zalo));
64
+ }
65
+ }
66
+
67
+ async connectAll(): Promise<void> {
68
+ const results = await Promise.allSettled(
69
+ Array.from(this.adapters.entries()).map(async ([type, adapter]) => {
70
+ try {
71
+ // Set up message handler
72
+ adapter.onMessage(async (message) => {
73
+ if (this.messageHandler) {
74
+ await this.messageHandler(message);
75
+ }
76
+ });
77
+
78
+ // Set up error handler
79
+ adapter.onError((error) => {
80
+ if (this.errorHandler) {
81
+ this.errorHandler(error, type);
82
+ }
83
+ });
84
+
85
+ await adapter.connect();
86
+ logger.info(`Connected to ${adapter.name}`);
87
+ } catch (error) {
88
+ logger.error(`Failed to connect to ${adapter.name}`, { error: error instanceof Error ? error : new Error(String(error)) });
89
+ throw error;
90
+ }
91
+ })
92
+ );
93
+
94
+ const failures = results.filter((r) => r.status === 'rejected');
95
+ if (failures.length > 0) {
96
+ logger.warn(`${failures.length} channel(s) failed to connect`);
97
+ }
98
+ }
99
+
100
+ async disconnectAll(): Promise<void> {
101
+ await Promise.allSettled(
102
+ Array.from(this.adapters.values()).map((adapter) => adapter.disconnect())
103
+ );
104
+ }
105
+
106
+ async connect(type: ChannelType): Promise<void> {
107
+ const adapter = this.adapters.get(type);
108
+ if (!adapter) {
109
+ throw new Error(`Channel not configured: ${type}`);
110
+ }
111
+
112
+ adapter.onMessage(async (message) => {
113
+ if (this.messageHandler) {
114
+ await this.messageHandler(message);
115
+ }
116
+ });
117
+
118
+ adapter.onError((error) => {
119
+ if (this.errorHandler) {
120
+ this.errorHandler(error, type);
121
+ }
122
+ });
123
+
124
+ await adapter.connect();
125
+ }
126
+
127
+ async disconnect(type: ChannelType): Promise<void> {
128
+ const adapter = this.adapters.get(type);
129
+ if (adapter) {
130
+ await adapter.disconnect();
131
+ }
132
+ }
133
+
134
+ async send(
135
+ channelType: ChannelType,
136
+ channelId: string,
137
+ message: OutboundMessage
138
+ ): Promise<SendResult> {
139
+ const adapter = this.adapters.get(channelType);
140
+ if (!adapter) {
141
+ return { success: false, error: `Channel not configured: ${channelType}` };
142
+ }
143
+
144
+ if (!adapter.isConnected()) {
145
+ return { success: false, error: `Channel not connected: ${channelType}` };
146
+ }
147
+
148
+ return adapter.send(channelId, message);
149
+ }
150
+
151
+ async startTyping(channelType: ChannelType, channelId: string): Promise<() => void> {
152
+ const adapter = this.adapters.get(channelType);
153
+ if (!adapter?.startTyping || !adapter.isConnected()) {
154
+ return () => {};
155
+ }
156
+ return adapter.startTyping(channelId);
157
+ }
158
+
159
+ getAdapter<T extends ChannelAdapter>(type: ChannelType): T | undefined {
160
+ return this.adapters.get(type) as T | undefined;
161
+ }
162
+
163
+ getConnectedChannels(): ChannelType[] {
164
+ return Array.from(this.adapters.entries())
165
+ .filter(([_, adapter]) => adapter.isConnected())
166
+ .map(([type]) => type);
167
+ }
168
+
169
+ getConfiguredChannels(): ChannelType[] {
170
+ return Array.from(this.adapters.keys());
171
+ }
172
+
173
+ onMessage(handler: (message: InboundMessage) => Promise<void>): void {
174
+ this.messageHandler = handler;
175
+ }
176
+
177
+ onError(handler: (error: Error, channelType: ChannelType) => void): void {
178
+ this.errorHandler = handler;
179
+ }
180
+ }
package/src/types.ts ADDED
@@ -0,0 +1,84 @@
1
+ export type ChannelType = 'discord' | 'telegram' | 'slack' | 'twilio' | 'webchat' | 'matrix' | 'signal' | 'email' | 'teams' | 'whatsapp' | 'googlechat' | 'bluebubbles' | 'zalo';
2
+
3
+ export interface InboundMessage {
4
+ id: string;
5
+ channelType: ChannelType;
6
+ channelId: string; // Server/chat ID
7
+ senderId: string; // User ID
8
+ senderName?: string; // Display name
9
+ content: string;
10
+ timestamp: number;
11
+ replyToId?: string; // If replying to a message
12
+ attachments?: Attachment[];
13
+ raw?: unknown; // Original platform message
14
+ }
15
+
16
+ export interface Attachment {
17
+ type: 'image' | 'audio' | 'video' | 'file';
18
+ url?: string;
19
+ data?: Buffer;
20
+ mimeType?: string;
21
+ filename?: string;
22
+ size?: number;
23
+ }
24
+
25
+ export interface OutboundMessage {
26
+ content: string;
27
+ replyToId?: string;
28
+ attachments?: Attachment[];
29
+ formatting?: {
30
+ markdown?: boolean;
31
+ html?: boolean;
32
+ };
33
+ }
34
+
35
+ export interface SendResult {
36
+ success: boolean;
37
+ messageId?: string;
38
+ error?: string;
39
+ }
40
+
41
+ export interface ChannelAdapter {
42
+ readonly type: ChannelType;
43
+ readonly name: string;
44
+
45
+ // Lifecycle
46
+ connect(): Promise<void>;
47
+ disconnect(): Promise<void>;
48
+ isConnected(): boolean;
49
+
50
+ // Messaging
51
+ send(channelId: string, message: OutboundMessage): Promise<SendResult>;
52
+
53
+ // Typing indicator — returns a cleanup function to stop the indicator
54
+ startTyping?(channelId: string): Promise<() => void>;
55
+
56
+ // Events
57
+ onMessage(handler: (message: InboundMessage) => Promise<void>): void;
58
+ onError(handler: (error: Error) => void): void;
59
+ }
60
+
61
+ export interface ChannelConfig {
62
+ discord?: {
63
+ token: string;
64
+ mentionOnly?: boolean;
65
+ allowedGuilds?: string[];
66
+ };
67
+ telegram?: {
68
+ token: string;
69
+ webhookUrl?: string;
70
+ allowedChats?: string[];
71
+ };
72
+ slack?: {
73
+ botToken: string;
74
+ appToken: string;
75
+ signingSecret?: string;
76
+ };
77
+ twilio?: {
78
+ accountSid: string;
79
+ authToken: string;
80
+ phoneNumber: string; // Your Twilio phone number
81
+ webhookUrl?: string; // For incoming messages
82
+ whatsappNumber?: string; // WhatsApp-enabled number
83
+ };
84
+ }