@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
@@ -0,0 +1,193 @@
1
+ import Twilio from 'twilio';
2
+ import { audit } from '@auxiora/audit';
3
+ const MAX_SMS_LENGTH = 1600; // SMS segment limit
4
+ const MAX_WHATSAPP_LENGTH = 4096;
5
+ export class TwilioAdapter {
6
+ type = 'twilio';
7
+ name = 'Twilio';
8
+ client;
9
+ config;
10
+ messageHandler;
11
+ errorHandler;
12
+ connected = false;
13
+ constructor(config) {
14
+ this.config = config;
15
+ this.client = Twilio(config.accountSid, config.authToken);
16
+ }
17
+ async connect() {
18
+ // Verify credentials by fetching account info
19
+ try {
20
+ await this.client.api.accounts(this.config.accountSid).fetch();
21
+ this.connected = true;
22
+ audit('channel.connected', { channelType: 'twilio' });
23
+ }
24
+ catch (error) {
25
+ throw new Error(`Failed to connect to Twilio: ${error instanceof Error ? error.message : error}`);
26
+ }
27
+ }
28
+ async disconnect() {
29
+ this.connected = false;
30
+ audit('channel.disconnected', { channelType: 'twilio' });
31
+ }
32
+ isConnected() {
33
+ return this.connected;
34
+ }
35
+ /**
36
+ * Handle incoming webhook from Twilio
37
+ * Call this from your HTTP server when receiving POST to your webhook URL
38
+ */
39
+ async handleWebhook(body) {
40
+ const isWhatsApp = body.From.startsWith('whatsapp:');
41
+ // Check allowed numbers (strip whatsapp: prefix for matching)
42
+ const senderNumber = isWhatsApp ? body.From.replace('whatsapp:', '') : body.From;
43
+ if (this.config.allowedNumbers?.length && !this.config.allowedNumbers.includes(senderNumber)) {
44
+ audit('message.filtered', { channelType: 'twilio', senderId: body.From, reason: 'number_not_allowed' });
45
+ return null;
46
+ }
47
+ const inbound = {
48
+ id: body.MessageSid,
49
+ channelType: 'twilio',
50
+ channelId: isWhatsApp ? 'whatsapp' : 'sms',
51
+ senderId: body.From,
52
+ content: body.Body,
53
+ timestamp: Date.now(),
54
+ attachments: body.NumMedia && parseInt(body.NumMedia, 10) > 0
55
+ ? [{
56
+ type: body.MediaContentType0?.startsWith('image/') ? 'image' : 'file',
57
+ url: body.MediaUrl0,
58
+ mimeType: body.MediaContentType0,
59
+ }]
60
+ : undefined,
61
+ raw: body,
62
+ };
63
+ audit('message.received', {
64
+ channelType: 'twilio',
65
+ senderId: inbound.senderId,
66
+ channelId: inbound.channelId,
67
+ isWhatsApp,
68
+ });
69
+ if (this.messageHandler) {
70
+ try {
71
+ await this.messageHandler(inbound);
72
+ }
73
+ catch (error) {
74
+ this.errorHandler?.(error instanceof Error ? error : new Error(String(error)));
75
+ }
76
+ }
77
+ // Return null to indicate no TwiML response needed
78
+ // Or return TwiML XML string if you want to respond immediately
79
+ return null;
80
+ }
81
+ /**
82
+ * Send message to a phone number
83
+ * @param channelId Phone number in E.164 format (+1234567890) or whatsapp:+1234567890
84
+ */
85
+ async send(channelId, message) {
86
+ try {
87
+ const isWhatsApp = channelId.startsWith('whatsapp:');
88
+ const fromNumber = isWhatsApp
89
+ ? this.config.whatsappNumber || `whatsapp:${this.config.phoneNumber}`
90
+ : this.config.phoneNumber;
91
+ if (!fromNumber) {
92
+ return { success: false, error: 'No phone number configured for this channel type' };
93
+ }
94
+ const maxLength = isWhatsApp ? MAX_WHATSAPP_LENGTH : MAX_SMS_LENGTH;
95
+ const chunks = this.chunkMessage(message.content, maxLength);
96
+ let lastMessageSid;
97
+ for (const chunk of chunks) {
98
+ const sent = await this.client.messages.create({
99
+ from: fromNumber,
100
+ to: channelId,
101
+ body: chunk,
102
+ });
103
+ lastMessageSid = sent.sid;
104
+ }
105
+ audit('message.sent', {
106
+ channelType: 'twilio',
107
+ channelId,
108
+ messageId: lastMessageSid,
109
+ isWhatsApp,
110
+ });
111
+ return { success: true, messageId: lastMessageSid };
112
+ }
113
+ catch (error) {
114
+ const errorMessage = error instanceof Error ? error.message : String(error);
115
+ audit('channel.error', {
116
+ channelType: 'twilio',
117
+ action: 'send',
118
+ error: errorMessage,
119
+ });
120
+ return { success: false, error: errorMessage };
121
+ }
122
+ }
123
+ /**
124
+ * Send SMS to a phone number
125
+ */
126
+ async sendSMS(to, message) {
127
+ // Ensure proper format
128
+ const phoneNumber = to.startsWith('+') ? to : `+${to}`;
129
+ return this.send(phoneNumber, { content: message });
130
+ }
131
+ /**
132
+ * Send WhatsApp message
133
+ */
134
+ async sendWhatsApp(to, message) {
135
+ // Ensure proper format
136
+ const phoneNumber = to.replace('whatsapp:', '');
137
+ const whatsappTo = `whatsapp:${phoneNumber.startsWith('+') ? phoneNumber : `+${phoneNumber}`}`;
138
+ return this.send(whatsappTo, { content: message });
139
+ }
140
+ chunkMessage(content, maxLength) {
141
+ if (content.length <= maxLength) {
142
+ return [content];
143
+ }
144
+ const chunks = [];
145
+ let remaining = content;
146
+ while (remaining.length > 0) {
147
+ if (remaining.length <= maxLength) {
148
+ chunks.push(remaining);
149
+ break;
150
+ }
151
+ let breakPoint = remaining.lastIndexOf('\n', maxLength);
152
+ if (breakPoint === -1 || breakPoint < maxLength / 2) {
153
+ breakPoint = remaining.lastIndexOf(' ', maxLength);
154
+ }
155
+ if (breakPoint === -1 || breakPoint < maxLength / 2) {
156
+ breakPoint = maxLength;
157
+ }
158
+ chunks.push(remaining.slice(0, breakPoint));
159
+ remaining = remaining.slice(breakPoint).trimStart();
160
+ }
161
+ return chunks;
162
+ }
163
+ /**
164
+ * Validate Twilio webhook signature
165
+ */
166
+ validateWebhookSignature(signature, url, params) {
167
+ return Twilio.validateRequest(this.config.authToken, signature, url, params);
168
+ }
169
+ /**
170
+ * Generate TwiML response for immediate reply
171
+ */
172
+ static generateTwiML(message) {
173
+ return `<?xml version="1.0" encoding="UTF-8"?>
174
+ <Response>
175
+ <Message>${this.escapeXml(message)}</Message>
176
+ </Response>`;
177
+ }
178
+ static escapeXml(text) {
179
+ return text
180
+ .replace(/&/g, '&amp;')
181
+ .replace(/</g, '&lt;')
182
+ .replace(/>/g, '&gt;')
183
+ .replace(/"/g, '&quot;')
184
+ .replace(/'/g, '&apos;');
185
+ }
186
+ onMessage(handler) {
187
+ this.messageHandler = handler;
188
+ }
189
+ onError(handler) {
190
+ this.errorHandler = handler;
191
+ }
192
+ }
193
+ //# sourceMappingURL=twilio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twilio.js","sourceRoot":"","sources":["../../src/adapters/twilio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import type { ChannelAdapter, InboundMessage, OutboundMessage, SendResult } from '../types.js';
2
+ export interface WhatsAppAdapterConfig {
3
+ phoneNumberId: string;
4
+ accessToken: string;
5
+ verifyToken: string;
6
+ allowedNumbers?: string[];
7
+ }
8
+ interface WhatsAppWebhookBody {
9
+ object: string;
10
+ entry: Array<{
11
+ id: string;
12
+ changes: Array<{
13
+ value: {
14
+ messaging_product: string;
15
+ metadata: {
16
+ display_phone_number: string;
17
+ phone_number_id: string;
18
+ };
19
+ contacts?: Array<{
20
+ profile: {
21
+ name: string;
22
+ };
23
+ wa_id: string;
24
+ }>;
25
+ messages?: Array<WhatsAppIncomingMessage>;
26
+ statuses?: Array<{
27
+ id: string;
28
+ status: string;
29
+ timestamp: string;
30
+ }>;
31
+ };
32
+ field: string;
33
+ }>;
34
+ }>;
35
+ }
36
+ interface WhatsAppIncomingMessage {
37
+ from: string;
38
+ id: string;
39
+ timestamp: string;
40
+ type: string;
41
+ text?: {
42
+ body: string;
43
+ };
44
+ image?: {
45
+ id: string;
46
+ mime_type: string;
47
+ sha256: string;
48
+ caption?: string;
49
+ };
50
+ document?: {
51
+ id: string;
52
+ mime_type: string;
53
+ filename?: string;
54
+ sha256: string;
55
+ caption?: string;
56
+ };
57
+ audio?: {
58
+ id: string;
59
+ mime_type: string;
60
+ };
61
+ video?: {
62
+ id: string;
63
+ mime_type: string;
64
+ };
65
+ context?: {
66
+ from: string;
67
+ id: string;
68
+ };
69
+ }
70
+ export declare class WhatsAppAdapter implements ChannelAdapter {
71
+ readonly type: "whatsapp";
72
+ readonly name = "WhatsApp";
73
+ private config;
74
+ private messageHandler?;
75
+ private errorHandler?;
76
+ private connected;
77
+ constructor(config: WhatsAppAdapterConfig);
78
+ connect(): Promise<void>;
79
+ disconnect(): Promise<void>;
80
+ isConnected(): boolean;
81
+ /**
82
+ * Verify webhook subscription from Meta.
83
+ * Returns the challenge string if the verify token matches.
84
+ */
85
+ verifyWebhook(mode: string, token: string, challenge: string): string | null;
86
+ /**
87
+ * Handle incoming webhook from WhatsApp Business API.
88
+ * Call this from your HTTP server when receiving POST to your webhook URL.
89
+ */
90
+ handleWebhook(body: WhatsAppWebhookBody): Promise<void>;
91
+ private handleMessage;
92
+ private toInboundMessage;
93
+ send(channelId: string, message: OutboundMessage): Promise<SendResult>;
94
+ private chunkMessage;
95
+ onMessage(handler: (message: InboundMessage) => Promise<void>): void;
96
+ onError(handler: (error: Error) => void): void;
97
+ }
98
+ export {};
99
+ //# sourceMappingURL=whatsapp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.d.ts","sourceRoot":"","sources":["../../src/adapters/whatsapp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,218 @@
1
+ import { audit } from '@auxiora/audit';
2
+ const GRAPH_API_BASE = 'https://graph.facebook.com/v18.0';
3
+ const MAX_MESSAGE_LENGTH = 4096;
4
+ export class WhatsAppAdapter {
5
+ type = 'whatsapp';
6
+ name = 'WhatsApp';
7
+ config;
8
+ messageHandler;
9
+ errorHandler;
10
+ connected = false;
11
+ constructor(config) {
12
+ this.config = config;
13
+ }
14
+ async connect() {
15
+ // Verify credentials by checking the phone number ID
16
+ const response = await fetch(`${GRAPH_API_BASE}/${this.config.phoneNumberId}`, {
17
+ headers: {
18
+ 'Authorization': `Bearer ${this.config.accessToken}`,
19
+ },
20
+ });
21
+ if (!response.ok) {
22
+ throw new Error(`Failed to verify WhatsApp credentials: ${response.status} ${response.statusText}`);
23
+ }
24
+ this.connected = true;
25
+ audit('channel.connected', {
26
+ channelType: 'whatsapp',
27
+ phoneNumberId: this.config.phoneNumberId,
28
+ });
29
+ }
30
+ async disconnect() {
31
+ this.connected = false;
32
+ audit('channel.disconnected', { channelType: 'whatsapp' });
33
+ }
34
+ isConnected() {
35
+ return this.connected;
36
+ }
37
+ /**
38
+ * Verify webhook subscription from Meta.
39
+ * Returns the challenge string if the verify token matches.
40
+ */
41
+ verifyWebhook(mode, token, challenge) {
42
+ if (mode === 'subscribe' && token === this.config.verifyToken) {
43
+ return challenge;
44
+ }
45
+ return null;
46
+ }
47
+ /**
48
+ * Handle incoming webhook from WhatsApp Business API.
49
+ * Call this from your HTTP server when receiving POST to your webhook URL.
50
+ */
51
+ async handleWebhook(body) {
52
+ if (body.object !== 'whatsapp_business_account')
53
+ return;
54
+ for (const entry of body.entry) {
55
+ for (const change of entry.changes) {
56
+ if (change.field !== 'messages')
57
+ continue;
58
+ const messages = change.value.messages;
59
+ if (!messages)
60
+ continue;
61
+ const contacts = change.value.contacts;
62
+ for (const msg of messages) {
63
+ const contact = contacts?.find((c) => c.wa_id === msg.from);
64
+ await this.handleMessage(msg, contact);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ async handleMessage(msg, contact) {
70
+ // Only process text messages for now
71
+ if (msg.type !== 'text' && msg.type !== 'image' && msg.type !== 'document')
72
+ return;
73
+ // Check allowed numbers
74
+ if (this.config.allowedNumbers?.length && !this.config.allowedNumbers.includes(msg.from)) {
75
+ audit('message.filtered', { channelType: 'whatsapp', senderId: msg.from, reason: 'number_not_allowed' });
76
+ return;
77
+ }
78
+ const inbound = this.toInboundMessage(msg, contact);
79
+ audit('message.received', {
80
+ channelType: 'whatsapp',
81
+ senderId: inbound.senderId,
82
+ channelId: inbound.channelId,
83
+ });
84
+ if (this.messageHandler) {
85
+ try {
86
+ await this.messageHandler(inbound);
87
+ }
88
+ catch (error) {
89
+ this.errorHandler?.(error instanceof Error ? error : new Error(String(error)));
90
+ }
91
+ }
92
+ }
93
+ toInboundMessage(msg, contact) {
94
+ let content = '';
95
+ const attachments = [];
96
+ switch (msg.type) {
97
+ case 'text':
98
+ content = msg.text?.body || '';
99
+ break;
100
+ case 'image':
101
+ content = msg.image?.caption || '';
102
+ attachments.push({
103
+ type: 'image',
104
+ mimeType: msg.image?.mime_type,
105
+ });
106
+ break;
107
+ case 'document':
108
+ content = msg.document?.caption || '';
109
+ attachments.push({
110
+ type: 'file',
111
+ mimeType: msg.document?.mime_type,
112
+ filename: msg.document?.filename,
113
+ });
114
+ break;
115
+ case 'audio':
116
+ attachments.push({
117
+ type: 'audio',
118
+ mimeType: msg.audio?.mime_type,
119
+ });
120
+ break;
121
+ case 'video':
122
+ attachments.push({
123
+ type: 'video',
124
+ mimeType: msg.video?.mime_type,
125
+ });
126
+ break;
127
+ }
128
+ return {
129
+ id: msg.id,
130
+ channelType: 'whatsapp',
131
+ channelId: msg.from,
132
+ senderId: msg.from,
133
+ senderName: contact?.profile.name,
134
+ content,
135
+ timestamp: parseInt(msg.timestamp, 10) * 1000,
136
+ replyToId: msg.context?.id,
137
+ attachments: attachments.length > 0 ? attachments : undefined,
138
+ raw: msg,
139
+ };
140
+ }
141
+ async send(channelId, message) {
142
+ try {
143
+ const chunks = this.chunkMessage(message.content);
144
+ let lastMessageId;
145
+ for (const chunk of chunks) {
146
+ const body = {
147
+ messaging_product: 'whatsapp',
148
+ recipient_type: 'individual',
149
+ to: channelId,
150
+ type: 'text',
151
+ text: { body: chunk },
152
+ };
153
+ if (message.replyToId) {
154
+ body.context = { message_id: message.replyToId };
155
+ }
156
+ const response = await fetch(`${GRAPH_API_BASE}/${this.config.phoneNumberId}/messages`, {
157
+ method: 'POST',
158
+ headers: {
159
+ 'Authorization': `Bearer ${this.config.accessToken}`,
160
+ 'Content-Type': 'application/json',
161
+ },
162
+ body: JSON.stringify(body),
163
+ });
164
+ if (!response.ok) {
165
+ const errorText = await response.text().catch(() => response.statusText);
166
+ throw new Error(`WhatsApp API error ${response.status}: ${errorText}`);
167
+ }
168
+ const result = await response.json();
169
+ lastMessageId = result.messages?.[0]?.id;
170
+ }
171
+ audit('message.sent', {
172
+ channelType: 'whatsapp',
173
+ channelId,
174
+ messageId: lastMessageId,
175
+ });
176
+ return { success: true, messageId: lastMessageId };
177
+ }
178
+ catch (error) {
179
+ const errorMessage = error instanceof Error ? error.message : String(error);
180
+ audit('channel.error', {
181
+ channelType: 'whatsapp',
182
+ action: 'send',
183
+ error: errorMessage,
184
+ });
185
+ return { success: false, error: errorMessage };
186
+ }
187
+ }
188
+ chunkMessage(content) {
189
+ if (content.length <= MAX_MESSAGE_LENGTH) {
190
+ return [content];
191
+ }
192
+ const chunks = [];
193
+ let remaining = content;
194
+ while (remaining.length > 0) {
195
+ if (remaining.length <= MAX_MESSAGE_LENGTH) {
196
+ chunks.push(remaining);
197
+ break;
198
+ }
199
+ let breakPoint = remaining.lastIndexOf('\n', MAX_MESSAGE_LENGTH);
200
+ if (breakPoint === -1 || breakPoint < MAX_MESSAGE_LENGTH / 2) {
201
+ breakPoint = remaining.lastIndexOf(' ', MAX_MESSAGE_LENGTH);
202
+ }
203
+ if (breakPoint === -1 || breakPoint < MAX_MESSAGE_LENGTH / 2) {
204
+ breakPoint = MAX_MESSAGE_LENGTH;
205
+ }
206
+ chunks.push(remaining.slice(0, breakPoint));
207
+ remaining = remaining.slice(breakPoint).trimStart();
208
+ }
209
+ return chunks;
210
+ }
211
+ onMessage(handler) {
212
+ this.messageHandler = handler;
213
+ }
214
+ onError(handler) {
215
+ this.errorHandler = handler;
216
+ }
217
+ }
218
+ //# sourceMappingURL=whatsapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../../src/adapters/whatsapp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { ChannelAdapter, InboundMessage, OutboundMessage, SendResult } from '../types.js';
2
+ export interface ZaloAdapterConfig {
3
+ oaAccessToken: string;
4
+ oaSecretKey: string;
5
+ allowedUserIds?: string[];
6
+ }
7
+ interface ZaloWebhookEvent {
8
+ app_id: string;
9
+ sender: {
10
+ id: string;
11
+ };
12
+ recipient: {
13
+ id: string;
14
+ };
15
+ event_name: string;
16
+ message?: {
17
+ msg_id: string;
18
+ text?: string;
19
+ attachments?: Array<{
20
+ type: string;
21
+ payload: {
22
+ url?: string;
23
+ thumbnail?: string;
24
+ id?: string;
25
+ size?: number;
26
+ name?: string;
27
+ type?: string;
28
+ };
29
+ }>;
30
+ quote_msg_id?: string;
31
+ };
32
+ timestamp: string;
33
+ }
34
+ export declare class ZaloAdapter implements ChannelAdapter {
35
+ readonly type: "zalo";
36
+ readonly name = "Zalo";
37
+ private config;
38
+ private messageHandler?;
39
+ private errorHandler?;
40
+ private connected;
41
+ private userNameCache;
42
+ constructor(config: ZaloAdapterConfig);
43
+ connect(): Promise<void>;
44
+ disconnect(): Promise<void>;
45
+ isConnected(): boolean;
46
+ /**
47
+ * Verify the webhook signature from Zalo.
48
+ * Returns true if the signature is valid.
49
+ */
50
+ verifyWebhookSignature(body: string, signature: string): boolean;
51
+ /**
52
+ * Handle incoming webhook from Zalo OA.
53
+ * Call this from your HTTP server when receiving POST to your webhook URL.
54
+ */
55
+ handleWebhook(event: ZaloWebhookEvent): Promise<void>;
56
+ private getUserName;
57
+ private toInboundMessage;
58
+ send(channelId: string, message: OutboundMessage): Promise<SendResult>;
59
+ private chunkMessage;
60
+ onMessage(handler: (message: InboundMessage) => Promise<void>): void;
61
+ onError(handler: (error: Error) => void): void;
62
+ }
63
+ export {};
64
+ //# sourceMappingURL=zalo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zalo.d.ts","sourceRoot":"","sources":["../../src/adapters/zalo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,eAAe,EACf,UAAU,EACX,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,SAAS,EAAE;QACT,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,KAAK,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE;gBACP,GAAG,CAAC,EAAE,MAAM,CAAC;gBACb,SAAS,CAAC,EAAE,MAAM,CAAC;gBACnB,EAAE,CAAC,EAAE,MAAM,CAAC;gBACZ,IAAI,CAAC,EAAE,MAAM,CAAC;gBACd,IAAI,CAAC,EAAE,MAAM,CAAC;gBACd,IAAI,CAAC,EAAE,MAAM,CAAC;aACf,CAAC;SACH,CAAC,CAAC;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAuBD,qBAAa,WAAY,YAAW,cAAc;IAChD,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,IAAI,UAAU;IAEvB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,cAAc,CAAC,CAA6C;IACpE,OAAO,CAAC,YAAY,CAAC,CAAyB;IAC9C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAkC;gBAE3C,MAAM,EAAE,iBAAiB;IAI/B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,WAAW,IAAI,OAAO;IAItB;;;OAGG;IACH,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAOhE;;;OAGG;IACG,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;YAuC7C,WAAW;IA4BzB,OAAO,CAAC,gBAAgB;IAiClB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAuD5E,OAAO,CAAC,YAAY;IA6BpB,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIpE,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI;CAG/C"}