n8n-nodes-zalo-loma-funnel 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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/dist/bridge/zalo-bridge.d.ts +46 -0
  4. package/dist/bridge/zalo-bridge.d.ts.map +1 -0
  5. package/dist/bridge/zalo-bridge.js +213 -0
  6. package/dist/bridge/zalo-bridge.js.map +1 -0
  7. package/dist/credentials/zalo-api.credentials.d.ts +8 -0
  8. package/dist/credentials/zalo-api.credentials.d.ts.map +1 -0
  9. package/dist/credentials/zalo-api.credentials.js +82 -0
  10. package/dist/credentials/zalo-api.credentials.js.map +1 -0
  11. package/dist/index.d.ts +9 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +36 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/interfaces/auth.interface.d.ts +33 -0
  16. package/dist/interfaces/auth.interface.d.ts.map +1 -0
  17. package/dist/interfaces/auth.interface.js +3 -0
  18. package/dist/interfaces/auth.interface.js.map +1 -0
  19. package/dist/interfaces/config.interface.d.ts +37 -0
  20. package/dist/interfaces/config.interface.d.ts.map +1 -0
  21. package/dist/interfaces/config.interface.js +3 -0
  22. package/dist/interfaces/config.interface.js.map +1 -0
  23. package/dist/interfaces/index.d.ts +4 -0
  24. package/dist/interfaces/index.d.ts.map +1 -0
  25. package/dist/interfaces/index.js +20 -0
  26. package/dist/interfaces/index.js.map +1 -0
  27. package/dist/interfaces/zalo.interface.d.ts +74 -0
  28. package/dist/interfaces/zalo.interface.d.ts.map +1 -0
  29. package/dist/interfaces/zalo.interface.js +14 -0
  30. package/dist/interfaces/zalo.interface.js.map +1 -0
  31. package/dist/nodes/ZaloManage/zalo-manage.node.d.ts +6 -0
  32. package/dist/nodes/ZaloManage/zalo-manage.node.d.ts.map +1 -0
  33. package/dist/nodes/ZaloManage/zalo-manage.node.js +426 -0
  34. package/dist/nodes/ZaloManage/zalo-manage.node.js.map +1 -0
  35. package/dist/nodes/ZaloSend/zalo-send.node.d.ts +6 -0
  36. package/dist/nodes/ZaloSend/zalo-send.node.d.ts.map +1 -0
  37. package/dist/nodes/ZaloSend/zalo-send.node.js +538 -0
  38. package/dist/nodes/ZaloSend/zalo-send.node.js.map +1 -0
  39. package/dist/nodes/ZaloTrigger/zalo-trigger.node.d.ts +6 -0
  40. package/dist/nodes/ZaloTrigger/zalo-trigger.node.d.ts.map +1 -0
  41. package/dist/nodes/ZaloTrigger/zalo-trigger.node.js +308 -0
  42. package/dist/nodes/ZaloTrigger/zalo-trigger.node.js.map +1 -0
  43. package/dist/queues/in-memory-queue.d.ts +20 -0
  44. package/dist/queues/in-memory-queue.d.ts.map +1 -0
  45. package/dist/queues/in-memory-queue.js +68 -0
  46. package/dist/queues/in-memory-queue.js.map +1 -0
  47. package/dist/queues/index.d.ts +4 -0
  48. package/dist/queues/index.d.ts.map +1 -0
  49. package/dist/queues/index.js +8 -0
  50. package/dist/queues/index.js.map +1 -0
  51. package/dist/queues/queue.interface.d.ts +15 -0
  52. package/dist/queues/queue.interface.d.ts.map +1 -0
  53. package/dist/queues/queue.interface.js +3 -0
  54. package/dist/queues/queue.interface.js.map +1 -0
  55. package/dist/queues/redis-queue.d.ts +22 -0
  56. package/dist/queues/redis-queue.d.ts.map +1 -0
  57. package/dist/queues/redis-queue.js +65 -0
  58. package/dist/queues/redis-queue.js.map +1 -0
  59. package/dist/services/error-handler.service.d.ts +67 -0
  60. package/dist/services/error-handler.service.d.ts.map +1 -0
  61. package/dist/services/error-handler.service.js +201 -0
  62. package/dist/services/error-handler.service.js.map +1 -0
  63. package/dist/services/index.d.ts +4 -0
  64. package/dist/services/index.d.ts.map +1 -0
  65. package/dist/services/index.js +13 -0
  66. package/dist/services/index.js.map +1 -0
  67. package/dist/services/rate-limiter.service.d.ts +68 -0
  68. package/dist/services/rate-limiter.service.d.ts.map +1 -0
  69. package/dist/services/rate-limiter.service.js +149 -0
  70. package/dist/services/rate-limiter.service.js.map +1 -0
  71. package/dist/services/zalo-connection-manager.service.d.ts +85 -0
  72. package/dist/services/zalo-connection-manager.service.d.ts.map +1 -0
  73. package/dist/services/zalo-connection-manager.service.js +243 -0
  74. package/dist/services/zalo-connection-manager.service.js.map +1 -0
  75. package/dist/utils/auth-helpers.d.ts +25 -0
  76. package/dist/utils/auth-helpers.d.ts.map +1 -0
  77. package/dist/utils/auth-helpers.js +66 -0
  78. package/dist/utils/auth-helpers.js.map +1 -0
  79. package/package.json +75 -0
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZaloTrigger = void 0;
4
+ const zca_js_1 = require("zca-js");
5
+ const zalo_connection_manager_service_1 = require("../../services/zalo-connection-manager.service");
6
+ const in_memory_queue_1 = require("../../queues/in-memory-queue");
7
+ const redis_queue_1 = require("../../queues/redis-queue");
8
+ const error_handler_service_1 = require("../../services/error-handler.service");
9
+ const zalo_interface_1 = require("../../interfaces/zalo.interface");
10
+ class ZaloTrigger {
11
+ constructor() {
12
+ this.description = {
13
+ displayName: 'Zalo Trigger',
14
+ name: 'zaloTrigger',
15
+ icon: 'file:zalo.svg',
16
+ group: ['trigger'],
17
+ version: 1,
18
+ subtitle: '={{$parameter["triggerMode"]}} mode',
19
+ description: 'Receives Zalo messages via WebSocket or polling',
20
+ defaults: {
21
+ name: 'Zalo Trigger',
22
+ },
23
+ inputs: [],
24
+ outputs: ['main'],
25
+ credentials: [
26
+ {
27
+ name: 'zaloApi',
28
+ required: true,
29
+ },
30
+ ],
31
+ properties: [
32
+ {
33
+ displayName: 'Trigger Mode',
34
+ name: 'triggerMode',
35
+ type: 'options',
36
+ options: [
37
+ {
38
+ name: 'WebSocket (Real-time)',
39
+ value: 'websocket',
40
+ description: 'Real-time message reception via WebSocket',
41
+ },
42
+ {
43
+ name: 'Polling (Queue)',
44
+ value: 'polling',
45
+ description: 'Poll from message queue (for external bridge)',
46
+ },
47
+ ],
48
+ default: 'websocket',
49
+ description: 'How to receive messages',
50
+ },
51
+ {
52
+ displayName: 'Queue Mode',
53
+ name: 'queueMode',
54
+ type: 'options',
55
+ options: [
56
+ {
57
+ name: 'In-Memory',
58
+ value: 'memory',
59
+ },
60
+ {
61
+ name: 'Redis',
62
+ value: 'redis',
63
+ },
64
+ ],
65
+ default: 'memory',
66
+ displayOptions: {
67
+ show: {
68
+ triggerMode: ['polling'],
69
+ },
70
+ },
71
+ description: 'Where to store message queue',
72
+ },
73
+ {
74
+ displayName: 'Redis URL',
75
+ name: 'redisUrl',
76
+ type: 'string',
77
+ default: 'redis://localhost:6379',
78
+ displayOptions: {
79
+ show: {
80
+ triggerMode: ['polling'],
81
+ queueMode: ['redis'],
82
+ },
83
+ },
84
+ description: 'Redis connection URL',
85
+ },
86
+ {
87
+ displayName: 'Polling Interval (ms)',
88
+ name: 'pollingInterval',
89
+ type: 'number',
90
+ default: 1000,
91
+ displayOptions: {
92
+ show: {
93
+ triggerMode: ['polling'],
94
+ },
95
+ },
96
+ description: 'How often to check for new messages',
97
+ },
98
+ {
99
+ displayName: 'Filter',
100
+ name: 'filter',
101
+ type: 'collection',
102
+ placeholder: 'Add Filter',
103
+ default: {},
104
+ options: [
105
+ {
106
+ displayName: 'Thread Type',
107
+ name: 'threadType',
108
+ type: 'options',
109
+ options: [
110
+ {
111
+ name: 'All',
112
+ value: 'all',
113
+ },
114
+ {
115
+ name: 'User (Direct Messages)',
116
+ value: 'user',
117
+ },
118
+ {
119
+ name: 'Group',
120
+ value: 'group',
121
+ },
122
+ ],
123
+ default: 'all',
124
+ description: 'Filter by thread type',
125
+ },
126
+ {
127
+ displayName: 'Thread IDs',
128
+ name: 'threadIds',
129
+ type: 'string',
130
+ default: '',
131
+ description: 'Comma-separated list of thread IDs to filter',
132
+ },
133
+ {
134
+ displayName: 'Include Self Messages',
135
+ name: 'includeSelf',
136
+ type: 'boolean',
137
+ default: false,
138
+ description: 'Whether to include messages sent by self',
139
+ },
140
+ ],
141
+ },
142
+ {
143
+ displayName: 'Options',
144
+ name: 'options',
145
+ type: 'collection',
146
+ placeholder: 'Add Option',
147
+ default: {},
148
+ options: [
149
+ {
150
+ displayName: 'Retry on Disconnect',
151
+ name: 'retryOnDisconnect',
152
+ type: 'boolean',
153
+ default: true,
154
+ displayOptions: {
155
+ show: {
156
+ '/triggerMode': ['websocket'],
157
+ },
158
+ },
159
+ description: 'Whether to automatically reconnect on disconnect',
160
+ },
161
+ {
162
+ displayName: 'Max Queue Size',
163
+ name: 'maxQueueSize',
164
+ type: 'number',
165
+ default: 1000,
166
+ description: 'Maximum number of messages to keep in queue',
167
+ },
168
+ ],
169
+ },
170
+ ],
171
+ };
172
+ }
173
+ async trigger() {
174
+ const triggerMode = this.getNodeParameter('triggerMode');
175
+ const filter = this.getNodeParameter('filter', {});
176
+ const options = this.getNodeParameter('options', {});
177
+ const credentials = (await this.getCredentials('zaloApi'));
178
+ const connectionManager = zalo_connection_manager_service_1.ZaloConnectionManager.getInstance();
179
+ const errorHandler = (0, error_handler_service_1.createDefaultErrorHandler)();
180
+ const accountId = credentials.accountId || 'default';
181
+ // Parse thread IDs filter
182
+ const threadIdFilter = filter.threadIds
183
+ ? filter.threadIds.split(',').map((id) => id.trim())
184
+ : [];
185
+ // Helper to check if message passes filter
186
+ const passesFilter = (message) => {
187
+ // Thread type filter
188
+ if (filter.threadType === 'user' && message.type !== zca_js_1.ThreadType.User) {
189
+ return false;
190
+ }
191
+ if (filter.threadType === 'group' && message.type !== zca_js_1.ThreadType.Group) {
192
+ return false;
193
+ }
194
+ // Self message filter
195
+ if (!filter.includeSelf && message.isSelf) {
196
+ return false;
197
+ }
198
+ // Thread ID filter
199
+ if (threadIdFilter.length > 0 && !threadIdFilter.includes(message.threadId)) {
200
+ return false;
201
+ }
202
+ return true;
203
+ };
204
+ // Helper to convert zca-js message to our format
205
+ const convertMessage = (message) => {
206
+ const data = message.data;
207
+ const content = typeof data.content === 'string' ? data.content : JSON.stringify(data.content);
208
+ return {
209
+ msgId: data.msgId,
210
+ threadId: message.threadId,
211
+ senderId: data.uidFrom,
212
+ senderName: data.dName,
213
+ content,
214
+ type: getMessageType(data.msgType),
215
+ timestamp: parseInt(data.ts, 10),
216
+ quote: data.quote
217
+ ? {
218
+ msgId: String(data.quote.globalMsgId),
219
+ content: data.quote.msg,
220
+ senderId: data.quote.ownerId,
221
+ }
222
+ : undefined,
223
+ };
224
+ };
225
+ // Helper to emit message to workflow
226
+ const emitMessage = (message) => {
227
+ this.emit([
228
+ this.helpers.returnJsonArray([message]),
229
+ ]);
230
+ };
231
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
232
+ let listener;
233
+ let pollingInterval;
234
+ let queue;
235
+ if (triggerMode === 'websocket') {
236
+ // WebSocket mode - real-time message reception
237
+ const api = await errorHandler.withRetry(() => connectionManager.connect(credentials));
238
+ listener = api.listener;
239
+ listener.on('message', (message) => {
240
+ if (passesFilter(message)) {
241
+ const converted = convertMessage(message);
242
+ emitMessage(converted);
243
+ }
244
+ });
245
+ listener.on('error', (error) => {
246
+ this.logger.error('Zalo WebSocket error:', { error });
247
+ });
248
+ listener.on('closed', (code, reason) => {
249
+ this.logger.info('Zalo WebSocket closed:', { code, reason });
250
+ });
251
+ listener.start({ retryOnClose: options.retryOnDisconnect ?? true });
252
+ }
253
+ else {
254
+ // Polling mode - poll from queue
255
+ const queueMode = this.getNodeParameter('queueMode');
256
+ const pollingIntervalMs = this.getNodeParameter('pollingInterval');
257
+ if (queueMode === 'redis') {
258
+ const redisUrl = this.getNodeParameter('redisUrl');
259
+ queue = new redis_queue_1.RedisQueue(redisUrl, 'zalo:trigger:', 86400);
260
+ }
261
+ else {
262
+ queue = new in_memory_queue_1.InMemoryQueue(options.maxQueueSize || 1000);
263
+ }
264
+ // Start polling
265
+ pollingInterval = setInterval(async () => {
266
+ try {
267
+ let message = await queue.pop(accountId);
268
+ while (message) {
269
+ emitMessage(message);
270
+ message = await queue.pop(accountId);
271
+ }
272
+ }
273
+ catch (error) {
274
+ this.logger.error('Polling error:', { error });
275
+ }
276
+ }, pollingIntervalMs);
277
+ }
278
+ // Return cleanup function
279
+ const closeFunction = async () => {
280
+ if (listener) {
281
+ listener.stop();
282
+ }
283
+ if (pollingInterval) {
284
+ clearInterval(pollingInterval);
285
+ }
286
+ if (queue) {
287
+ await queue.close();
288
+ }
289
+ };
290
+ return {
291
+ closeFunction,
292
+ };
293
+ }
294
+ }
295
+ exports.ZaloTrigger = ZaloTrigger;
296
+ function getMessageType(msgType) {
297
+ const typeMap = {
298
+ text: zalo_interface_1.ZaloMessageType.TEXT,
299
+ image: zalo_interface_1.ZaloMessageType.IMAGE,
300
+ video: zalo_interface_1.ZaloMessageType.VIDEO,
301
+ file: zalo_interface_1.ZaloMessageType.FILE,
302
+ sticker: zalo_interface_1.ZaloMessageType.STICKER,
303
+ gif: zalo_interface_1.ZaloMessageType.GIF,
304
+ voice: zalo_interface_1.ZaloMessageType.VOICE,
305
+ };
306
+ return typeMap[msgType.toLowerCase()] || zalo_interface_1.ZaloMessageType.TEXT;
307
+ }
308
+ //# sourceMappingURL=zalo-trigger.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zalo-trigger.node.js","sourceRoot":"","sources":["../../../src/nodes/ZaloTrigger/zalo-trigger.node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { IMessageQueue } from './queue.interface';
2
+ import { IZaloMessage } from '../interfaces/zalo.interface';
3
+ /**
4
+ * In-memory queue implementation
5
+ * Simple, no external dependencies, not persistent across restarts
6
+ */
7
+ export declare class InMemoryQueue implements IMessageQueue {
8
+ private queues;
9
+ private msgIds;
10
+ private maxSize;
11
+ constructor(maxSize?: number);
12
+ push(accountId: string, message: IZaloMessage): Promise<void>;
13
+ pop(accountId: string): Promise<IZaloMessage | null>;
14
+ peek(accountId: string, count?: number): Promise<IZaloMessage[]>;
15
+ size(accountId: string): Promise<number>;
16
+ clear(accountId: string): Promise<void>;
17
+ exists(accountId: string, msgId: string): Promise<boolean>;
18
+ close(): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=in-memory-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-queue.d.ts","sourceRoot":"","sources":["../../src/queues/in-memory-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,qBAAa,aAAc,YAAW,aAAa;IACjD,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,SAAO;IAIpB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB7D,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAepD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM5D,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InMemoryQueue = void 0;
4
+ /**
5
+ * In-memory queue implementation
6
+ * Simple, no external dependencies, not persistent across restarts
7
+ */
8
+ class InMemoryQueue {
9
+ constructor(maxSize = 1000) {
10
+ this.queues = new Map();
11
+ this.msgIds = new Map();
12
+ this.maxSize = maxSize;
13
+ }
14
+ async push(accountId, message) {
15
+ if (await this.exists(accountId, message.msgId)) {
16
+ return;
17
+ }
18
+ let queue = this.queues.get(accountId);
19
+ if (!queue) {
20
+ queue = [];
21
+ this.queues.set(accountId, queue);
22
+ }
23
+ if (queue.length >= this.maxSize) {
24
+ queue.shift();
25
+ }
26
+ queue.push(message);
27
+ let ids = this.msgIds.get(accountId);
28
+ if (!ids) {
29
+ ids = new Set();
30
+ this.msgIds.set(accountId, ids);
31
+ }
32
+ ids.add(message.msgId);
33
+ }
34
+ async pop(accountId) {
35
+ const queue = this.queues.get(accountId);
36
+ if (!queue || queue.length === 0) {
37
+ return null;
38
+ }
39
+ const message = queue.shift();
40
+ const ids = this.msgIds.get(accountId);
41
+ if (ids) {
42
+ ids.delete(message.msgId);
43
+ }
44
+ return message;
45
+ }
46
+ async peek(accountId, count = 10) {
47
+ const queue = this.queues.get(accountId);
48
+ if (!queue)
49
+ return [];
50
+ return queue.slice(0, count);
51
+ }
52
+ async size(accountId) {
53
+ return this.queues.get(accountId)?.length || 0;
54
+ }
55
+ async clear(accountId) {
56
+ this.queues.delete(accountId);
57
+ this.msgIds.delete(accountId);
58
+ }
59
+ async exists(accountId, msgId) {
60
+ return this.msgIds.get(accountId)?.has(msgId) || false;
61
+ }
62
+ async close() {
63
+ this.queues.clear();
64
+ this.msgIds.clear();
65
+ }
66
+ }
67
+ exports.InMemoryQueue = InMemoryQueue;
68
+ //# sourceMappingURL=in-memory-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory-queue.js","sourceRoot":"","sources":["../../src/queues/in-memory-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { IMessageQueue } from './queue.interface';
2
+ export { InMemoryQueue } from './in-memory-queue';
3
+ export { RedisQueue } from './redis-queue';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/queues/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisQueue = exports.InMemoryQueue = void 0;
4
+ var in_memory_queue_1 = require("./in-memory-queue");
5
+ Object.defineProperty(exports, "InMemoryQueue", { enumerable: true, get: function () { return in_memory_queue_1.InMemoryQueue; } });
6
+ var redis_queue_1 = require("./redis-queue");
7
+ Object.defineProperty(exports, "RedisQueue", { enumerable: true, get: function () { return redis_queue_1.RedisQueue; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/queues/index.ts"],"names":[],"mappings":";;;AACA,qDAAkD;AAAzC,gHAAA,aAAa,OAAA;AACtB,6CAA2C;AAAlC,yGAAA,UAAU,OAAA"}
@@ -0,0 +1,15 @@
1
+ import { IZaloMessage } from '../interfaces/zalo.interface';
2
+ /**
3
+ * Message queue interface
4
+ * Supports both InMemory and Redis implementations
5
+ */
6
+ export interface IMessageQueue {
7
+ push(accountId: string, message: IZaloMessage): Promise<void>;
8
+ pop(accountId: string): Promise<IZaloMessage | null>;
9
+ peek(accountId: string, count?: number): Promise<IZaloMessage[]>;
10
+ size(accountId: string): Promise<number>;
11
+ clear(accountId: string): Promise<void>;
12
+ exists(accountId: string, msgId: string): Promise<boolean>;
13
+ close(): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=queue.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.interface.d.ts","sourceRoot":"","sources":["../../src/queues/queue.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IACrD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=queue.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.interface.js","sourceRoot":"","sources":["../../src/queues/queue.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ import { IMessageQueue } from './queue.interface';
2
+ import { IZaloMessage } from '../interfaces/zalo.interface';
3
+ /**
4
+ * Redis-backed queue implementation
5
+ * Persistent, scalable, supports distributed n8n
6
+ */
7
+ export declare class RedisQueue implements IMessageQueue {
8
+ private redis;
9
+ private prefix;
10
+ private ttlSeconds;
11
+ constructor(redisUrl: string, prefix?: string, ttlSeconds?: number);
12
+ private queueKey;
13
+ private dedupKey;
14
+ push(accountId: string, message: IZaloMessage): Promise<void>;
15
+ pop(accountId: string): Promise<IZaloMessage | null>;
16
+ peek(accountId: string, count?: number): Promise<IZaloMessage[]>;
17
+ size(accountId: string): Promise<number>;
18
+ clear(accountId: string): Promise<void>;
19
+ exists(accountId: string, msgId: string): Promise<boolean>;
20
+ close(): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=redis-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-queue.d.ts","sourceRoot":"","sources":["../../src/queues/redis-queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC9C,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;gBAEf,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAgB,EAAE,UAAU,SAAQ;IAMxE,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,QAAQ;IAIV,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAe7D,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAYpD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM5D,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKxC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RedisQueue = void 0;
7
+ const ioredis_1 = __importDefault(require("ioredis"));
8
+ /**
9
+ * Redis-backed queue implementation
10
+ * Persistent, scalable, supports distributed n8n
11
+ */
12
+ class RedisQueue {
13
+ constructor(redisUrl, prefix = 'zalo:queue:', ttlSeconds = 86400) {
14
+ this.redis = new ioredis_1.default(redisUrl);
15
+ this.prefix = prefix;
16
+ this.ttlSeconds = ttlSeconds;
17
+ }
18
+ queueKey(accountId) {
19
+ return `${this.prefix}${accountId}`;
20
+ }
21
+ dedupKey(accountId) {
22
+ return `${this.prefix}dedup:${accountId}`;
23
+ }
24
+ async push(accountId, message) {
25
+ if (await this.exists(accountId, message.msgId)) {
26
+ return;
27
+ }
28
+ const key = this.queueKey(accountId);
29
+ const data = JSON.stringify(message);
30
+ await this.redis.rpush(key, data);
31
+ await this.redis.expire(key, this.ttlSeconds);
32
+ await this.redis.sadd(this.dedupKey(accountId), message.msgId);
33
+ await this.redis.expire(this.dedupKey(accountId), 3600);
34
+ }
35
+ async pop(accountId) {
36
+ const key = this.queueKey(accountId);
37
+ const data = await this.redis.lpop(key);
38
+ if (!data)
39
+ return null;
40
+ const message = JSON.parse(data);
41
+ await this.redis.srem(this.dedupKey(accountId), message.msgId);
42
+ return message;
43
+ }
44
+ async peek(accountId, count = 10) {
45
+ const key = this.queueKey(accountId);
46
+ const items = await this.redis.lrange(key, 0, count - 1);
47
+ return items.map((item) => JSON.parse(item));
48
+ }
49
+ async size(accountId) {
50
+ const key = this.queueKey(accountId);
51
+ return await this.redis.llen(key);
52
+ }
53
+ async clear(accountId) {
54
+ await this.redis.del(this.queueKey(accountId));
55
+ await this.redis.del(this.dedupKey(accountId));
56
+ }
57
+ async exists(accountId, msgId) {
58
+ return (await this.redis.sismember(this.dedupKey(accountId), msgId)) === 1;
59
+ }
60
+ async close() {
61
+ await this.redis.quit();
62
+ }
63
+ }
64
+ exports.RedisQueue = RedisQueue;
65
+ //# sourceMappingURL=redis-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-queue.js","sourceRoot":"","sources":["../../src/queues/redis-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { IErrorHandlerConfig } from '../interfaces/config.interface';
2
+ /**
3
+ * Error categories for classification
4
+ */
5
+ export declare enum ErrorCategory {
6
+ AUTH = "auth",
7
+ RATE_LIMIT = "rate_limit",
8
+ NETWORK = "network",
9
+ VALIDATION = "validation",
10
+ NOT_FOUND = "not_found",
11
+ PERMISSION = "permission",
12
+ SERVER = "server",
13
+ UNKNOWN = "unknown"
14
+ }
15
+ /**
16
+ * Classified error with metadata
17
+ */
18
+ export interface ClassifiedError {
19
+ original: Error;
20
+ category: ErrorCategory;
21
+ message: string;
22
+ retryable: boolean;
23
+ retryAfterMs?: number;
24
+ }
25
+ /**
26
+ * Error handler with classification and retry logic
27
+ */
28
+ export declare class ErrorHandler {
29
+ private config;
30
+ constructor(config?: Partial<IErrorHandlerConfig>);
31
+ /**
32
+ * Classify an error into category
33
+ */
34
+ classify(error: Error): ClassifiedError;
35
+ /**
36
+ * Execute with retry logic
37
+ */
38
+ withRetry<T>(fn: () => Promise<T>, options?: {
39
+ maxRetries?: number;
40
+ onRetry?: (error: ClassifiedError, attempt: number) => void;
41
+ }): Promise<T>;
42
+ /**
43
+ * Calculate exponential backoff delay
44
+ */
45
+ private calculateDelay;
46
+ /**
47
+ * Convert to n8n-friendly error
48
+ */
49
+ private toNodeError;
50
+ /**
51
+ * Sleep helper
52
+ */
53
+ private sleep;
54
+ /**
55
+ * Check if error is retryable
56
+ */
57
+ isRetryable(error: Error): boolean;
58
+ /**
59
+ * Get suggested wait time for error
60
+ */
61
+ getSuggestedWait(error: Error): number;
62
+ }
63
+ /**
64
+ * Create default error handler
65
+ */
66
+ export declare function createDefaultErrorHandler(): ErrorHandler;
67
+ //# sourceMappingURL=error-handler.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.service.d.ts","sourceRoot":"","sources":["../../src/services/error-handler.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE;;GAEG;AACH,oBAAY,aAAa;IACvB,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,OAAO,YAAY;IACnB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,UAAU,eAAe;IACzB,MAAM,WAAW;IACjB,OAAO,YAAY;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,KAAK,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAUjD;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,eAAe;IAuHvC;;OAEG;IACG,SAAS,CAAC,CAAC,EACf,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,GAC7F,OAAO,CAAC,CAAC,CAAC;IAwBb;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAKlC;;OAEG;IACH,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;CAIvC;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,YAAY,CAExD"}