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.
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/bridge/zalo-bridge.d.ts +46 -0
- package/dist/bridge/zalo-bridge.d.ts.map +1 -0
- package/dist/bridge/zalo-bridge.js +213 -0
- package/dist/bridge/zalo-bridge.js.map +1 -0
- package/dist/credentials/zalo-api.credentials.d.ts +8 -0
- package/dist/credentials/zalo-api.credentials.d.ts.map +1 -0
- package/dist/credentials/zalo-api.credentials.js +82 -0
- package/dist/credentials/zalo-api.credentials.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/auth.interface.d.ts +33 -0
- package/dist/interfaces/auth.interface.d.ts.map +1 -0
- package/dist/interfaces/auth.interface.js +3 -0
- package/dist/interfaces/auth.interface.js.map +1 -0
- package/dist/interfaces/config.interface.d.ts +37 -0
- package/dist/interfaces/config.interface.d.ts.map +1 -0
- package/dist/interfaces/config.interface.js +3 -0
- package/dist/interfaces/config.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +4 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +20 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/zalo.interface.d.ts +74 -0
- package/dist/interfaces/zalo.interface.d.ts.map +1 -0
- package/dist/interfaces/zalo.interface.js +14 -0
- package/dist/interfaces/zalo.interface.js.map +1 -0
- package/dist/nodes/ZaloManage/zalo-manage.node.d.ts +6 -0
- package/dist/nodes/ZaloManage/zalo-manage.node.d.ts.map +1 -0
- package/dist/nodes/ZaloManage/zalo-manage.node.js +426 -0
- package/dist/nodes/ZaloManage/zalo-manage.node.js.map +1 -0
- package/dist/nodes/ZaloSend/zalo-send.node.d.ts +6 -0
- package/dist/nodes/ZaloSend/zalo-send.node.d.ts.map +1 -0
- package/dist/nodes/ZaloSend/zalo-send.node.js +538 -0
- package/dist/nodes/ZaloSend/zalo-send.node.js.map +1 -0
- package/dist/nodes/ZaloTrigger/zalo-trigger.node.d.ts +6 -0
- package/dist/nodes/ZaloTrigger/zalo-trigger.node.d.ts.map +1 -0
- package/dist/nodes/ZaloTrigger/zalo-trigger.node.js +308 -0
- package/dist/nodes/ZaloTrigger/zalo-trigger.node.js.map +1 -0
- package/dist/queues/in-memory-queue.d.ts +20 -0
- package/dist/queues/in-memory-queue.d.ts.map +1 -0
- package/dist/queues/in-memory-queue.js +68 -0
- package/dist/queues/in-memory-queue.js.map +1 -0
- package/dist/queues/index.d.ts +4 -0
- package/dist/queues/index.d.ts.map +1 -0
- package/dist/queues/index.js +8 -0
- package/dist/queues/index.js.map +1 -0
- package/dist/queues/queue.interface.d.ts +15 -0
- package/dist/queues/queue.interface.d.ts.map +1 -0
- package/dist/queues/queue.interface.js +3 -0
- package/dist/queues/queue.interface.js.map +1 -0
- package/dist/queues/redis-queue.d.ts +22 -0
- package/dist/queues/redis-queue.d.ts.map +1 -0
- package/dist/queues/redis-queue.js +65 -0
- package/dist/queues/redis-queue.js.map +1 -0
- package/dist/services/error-handler.service.d.ts +67 -0
- package/dist/services/error-handler.service.d.ts.map +1 -0
- package/dist/services/error-handler.service.js +201 -0
- package/dist/services/error-handler.service.js.map +1 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +13 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/rate-limiter.service.d.ts +68 -0
- package/dist/services/rate-limiter.service.d.ts.map +1 -0
- package/dist/services/rate-limiter.service.js +149 -0
- package/dist/services/rate-limiter.service.js.map +1 -0
- package/dist/services/zalo-connection-manager.service.d.ts +85 -0
- package/dist/services/zalo-connection-manager.service.d.ts.map +1 -0
- package/dist/services/zalo-connection-manager.service.js +243 -0
- package/dist/services/zalo-connection-manager.service.js.map +1 -0
- package/dist/utils/auth-helpers.d.ts +25 -0
- package/dist/utils/auth-helpers.d.ts.map +1 -0
- package/dist/utils/auth-helpers.js +66 -0
- package/dist/utils/auth-helpers.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorHandler = exports.ErrorCategory = void 0;
|
|
4
|
+
exports.createDefaultErrorHandler = createDefaultErrorHandler;
|
|
5
|
+
/**
|
|
6
|
+
* Error categories for classification
|
|
7
|
+
*/
|
|
8
|
+
var ErrorCategory;
|
|
9
|
+
(function (ErrorCategory) {
|
|
10
|
+
ErrorCategory["AUTH"] = "auth";
|
|
11
|
+
ErrorCategory["RATE_LIMIT"] = "rate_limit";
|
|
12
|
+
ErrorCategory["NETWORK"] = "network";
|
|
13
|
+
ErrorCategory["VALIDATION"] = "validation";
|
|
14
|
+
ErrorCategory["NOT_FOUND"] = "not_found";
|
|
15
|
+
ErrorCategory["PERMISSION"] = "permission";
|
|
16
|
+
ErrorCategory["SERVER"] = "server";
|
|
17
|
+
ErrorCategory["UNKNOWN"] = "unknown";
|
|
18
|
+
})(ErrorCategory || (exports.ErrorCategory = ErrorCategory = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Error handler with classification and retry logic
|
|
21
|
+
*/
|
|
22
|
+
class ErrorHandler {
|
|
23
|
+
constructor(config) {
|
|
24
|
+
this.config = {
|
|
25
|
+
maxRetries: 3,
|
|
26
|
+
baseDelayMs: 1000,
|
|
27
|
+
maxDelayMs: 30000,
|
|
28
|
+
retryableErrors: ['NETWORK', 'RATE_LIMIT', 'SERVER', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'],
|
|
29
|
+
...config,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Classify an error into category
|
|
34
|
+
*/
|
|
35
|
+
classify(error) {
|
|
36
|
+
const message = error.message?.toLowerCase() || '';
|
|
37
|
+
const name = error.name?.toLowerCase() || '';
|
|
38
|
+
// Authentication errors
|
|
39
|
+
if (message.includes('unauthorized') ||
|
|
40
|
+
message.includes('invalid cookie') ||
|
|
41
|
+
message.includes('session expired') ||
|
|
42
|
+
message.includes('login required') ||
|
|
43
|
+
message.includes('auth')) {
|
|
44
|
+
return {
|
|
45
|
+
original: error,
|
|
46
|
+
category: ErrorCategory.AUTH,
|
|
47
|
+
message: 'Authentication failed. Please check credentials.',
|
|
48
|
+
retryable: false,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Rate limit errors
|
|
52
|
+
if (message.includes('rate limit') ||
|
|
53
|
+
message.includes('too many requests') ||
|
|
54
|
+
message.includes('429') ||
|
|
55
|
+
message.includes('spam')) {
|
|
56
|
+
return {
|
|
57
|
+
original: error,
|
|
58
|
+
category: ErrorCategory.RATE_LIMIT,
|
|
59
|
+
message: 'Rate limited. Will retry after delay.',
|
|
60
|
+
retryable: true,
|
|
61
|
+
retryAfterMs: this.config.maxDelayMs,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Network errors
|
|
65
|
+
if (message.includes('network') ||
|
|
66
|
+
message.includes('timeout') ||
|
|
67
|
+
message.includes('etimedout') ||
|
|
68
|
+
message.includes('econnreset') ||
|
|
69
|
+
message.includes('econnrefused') ||
|
|
70
|
+
message.includes('socket') ||
|
|
71
|
+
name.includes('fetch')) {
|
|
72
|
+
return {
|
|
73
|
+
original: error,
|
|
74
|
+
category: ErrorCategory.NETWORK,
|
|
75
|
+
message: 'Network error. Will retry.',
|
|
76
|
+
retryable: true,
|
|
77
|
+
retryAfterMs: this.config.baseDelayMs,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// Validation errors
|
|
81
|
+
if (message.includes('invalid') ||
|
|
82
|
+
message.includes('validation') ||
|
|
83
|
+
message.includes('required') ||
|
|
84
|
+
message.includes('missing')) {
|
|
85
|
+
return {
|
|
86
|
+
original: error,
|
|
87
|
+
category: ErrorCategory.VALIDATION,
|
|
88
|
+
message: `Validation error: ${error.message}`,
|
|
89
|
+
retryable: false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// Not found errors
|
|
93
|
+
if (message.includes('not found') ||
|
|
94
|
+
message.includes('404') ||
|
|
95
|
+
message.includes('does not exist')) {
|
|
96
|
+
return {
|
|
97
|
+
original: error,
|
|
98
|
+
category: ErrorCategory.NOT_FOUND,
|
|
99
|
+
message: 'Resource not found.',
|
|
100
|
+
retryable: false,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// Permission errors
|
|
104
|
+
if (message.includes('permission') ||
|
|
105
|
+
message.includes('forbidden') ||
|
|
106
|
+
message.includes('403') ||
|
|
107
|
+
message.includes('access denied')) {
|
|
108
|
+
return {
|
|
109
|
+
original: error,
|
|
110
|
+
category: ErrorCategory.PERMISSION,
|
|
111
|
+
message: 'Permission denied.',
|
|
112
|
+
retryable: false,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Server errors
|
|
116
|
+
if (message.includes('500') || message.includes('server error') || message.includes('503')) {
|
|
117
|
+
return {
|
|
118
|
+
original: error,
|
|
119
|
+
category: ErrorCategory.SERVER,
|
|
120
|
+
message: 'Server error. Will retry.',
|
|
121
|
+
retryable: true,
|
|
122
|
+
retryAfterMs: this.config.baseDelayMs * 2,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Unknown errors
|
|
126
|
+
return {
|
|
127
|
+
original: error,
|
|
128
|
+
category: ErrorCategory.UNKNOWN,
|
|
129
|
+
message: error.message || 'Unknown error occurred.',
|
|
130
|
+
retryable: false,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Execute with retry logic
|
|
135
|
+
*/
|
|
136
|
+
async withRetry(fn, options) {
|
|
137
|
+
const maxRetries = options?.maxRetries ?? this.config.maxRetries;
|
|
138
|
+
let lastError = null;
|
|
139
|
+
for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
|
|
140
|
+
try {
|
|
141
|
+
return await fn();
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
lastError = this.classify(error);
|
|
145
|
+
if (!lastError.retryable || attempt > maxRetries) {
|
|
146
|
+
throw this.toNodeError(lastError);
|
|
147
|
+
}
|
|
148
|
+
options?.onRetry?.(lastError, attempt);
|
|
149
|
+
const delay = this.calculateDelay(attempt, lastError.retryAfterMs);
|
|
150
|
+
await this.sleep(delay);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
throw this.toNodeError(lastError);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Calculate exponential backoff delay
|
|
157
|
+
*/
|
|
158
|
+
calculateDelay(attempt, baseDelay) {
|
|
159
|
+
const base = baseDelay || this.config.baseDelayMs;
|
|
160
|
+
const exponentialDelay = base * Math.pow(2, attempt - 1);
|
|
161
|
+
const jitter = Math.random() * 1000;
|
|
162
|
+
return Math.min(exponentialDelay + jitter, this.config.maxDelayMs);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Convert to n8n-friendly error
|
|
166
|
+
*/
|
|
167
|
+
toNodeError(classified) {
|
|
168
|
+
const error = new Error(classified.message);
|
|
169
|
+
error.name = `Zalo${classified.category.charAt(0).toUpperCase() + classified.category.slice(1)}Error`;
|
|
170
|
+
error.cause = classified.original;
|
|
171
|
+
return error;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Sleep helper
|
|
175
|
+
*/
|
|
176
|
+
sleep(ms) {
|
|
177
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Check if error is retryable
|
|
181
|
+
*/
|
|
182
|
+
isRetryable(error) {
|
|
183
|
+
const classified = this.classify(error);
|
|
184
|
+
return classified.retryable;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get suggested wait time for error
|
|
188
|
+
*/
|
|
189
|
+
getSuggestedWait(error) {
|
|
190
|
+
const classified = this.classify(error);
|
|
191
|
+
return classified.retryAfterMs || this.config.baseDelayMs;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.ErrorHandler = ErrorHandler;
|
|
195
|
+
/**
|
|
196
|
+
* Create default error handler
|
|
197
|
+
*/
|
|
198
|
+
function createDefaultErrorHandler() {
|
|
199
|
+
return new ErrorHandler();
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=error-handler.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.service.js","sourceRoot":"","sources":["../../src/services/error-handler.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ZaloConnectionManager } from './zalo-connection-manager.service';
|
|
2
|
+
export { RateLimiter, createDefaultRateLimiter } from './rate-limiter.service';
|
|
3
|
+
export { ErrorHandler, ErrorCategory, createDefaultErrorHandler, type ClassifiedError, } from './error-handler.service';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EACL,YAAY,EACZ,aAAa,EACb,yBAAyB,EACzB,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDefaultErrorHandler = exports.ErrorCategory = exports.ErrorHandler = exports.createDefaultRateLimiter = exports.RateLimiter = exports.ZaloConnectionManager = void 0;
|
|
4
|
+
var zalo_connection_manager_service_1 = require("./zalo-connection-manager.service");
|
|
5
|
+
Object.defineProperty(exports, "ZaloConnectionManager", { enumerable: true, get: function () { return zalo_connection_manager_service_1.ZaloConnectionManager; } });
|
|
6
|
+
var rate_limiter_service_1 = require("./rate-limiter.service");
|
|
7
|
+
Object.defineProperty(exports, "RateLimiter", { enumerable: true, get: function () { return rate_limiter_service_1.RateLimiter; } });
|
|
8
|
+
Object.defineProperty(exports, "createDefaultRateLimiter", { enumerable: true, get: function () { return rate_limiter_service_1.createDefaultRateLimiter; } });
|
|
9
|
+
var error_handler_service_1 = require("./error-handler.service");
|
|
10
|
+
Object.defineProperty(exports, "ErrorHandler", { enumerable: true, get: function () { return error_handler_service_1.ErrorHandler; } });
|
|
11
|
+
Object.defineProperty(exports, "ErrorCategory", { enumerable: true, get: function () { return error_handler_service_1.ErrorCategory; } });
|
|
12
|
+
Object.defineProperty(exports, "createDefaultErrorHandler", { enumerable: true, get: function () { return error_handler_service_1.createDefaultErrorHandler; } });
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":";;;AAAA,qFAA0E;AAAjE,wIAAA,qBAAqB,OAAA;AAC9B,+DAA+E;AAAtE,mHAAA,WAAW,OAAA;AAAE,gIAAA,wBAAwB,OAAA;AAC9C,iEAKiC;AAJ/B,qHAAA,YAAY,OAAA;AACZ,sHAAA,aAAa,OAAA;AACb,kIAAA,yBAAyB,OAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { IRateLimitConfig } from '../interfaces/config.interface';
|
|
2
|
+
/**
|
|
3
|
+
* Rate limiter with configurable random delay
|
|
4
|
+
* Supports in-memory and Redis modes for distributed rate limiting
|
|
5
|
+
*/
|
|
6
|
+
export declare class RateLimiter {
|
|
7
|
+
private mode;
|
|
8
|
+
private minDelayMs;
|
|
9
|
+
private maxDelayMs;
|
|
10
|
+
private redis?;
|
|
11
|
+
private lastSendTime;
|
|
12
|
+
private prefix;
|
|
13
|
+
constructor(config: IRateLimitConfig);
|
|
14
|
+
/**
|
|
15
|
+
* Wait for rate limit and acquire send slot
|
|
16
|
+
* Returns the delay that was applied
|
|
17
|
+
*/
|
|
18
|
+
acquire(accountId: string): Promise<number>;
|
|
19
|
+
/**
|
|
20
|
+
* Check if can send immediately (without waiting)
|
|
21
|
+
*/
|
|
22
|
+
canSend(accountId: string): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Get time until next send is allowed
|
|
25
|
+
*/
|
|
26
|
+
getWaitTime(accountId: string): Promise<number>;
|
|
27
|
+
/**
|
|
28
|
+
* Reset rate limit for account
|
|
29
|
+
*/
|
|
30
|
+
reset(accountId: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Reset all rate limits
|
|
33
|
+
*/
|
|
34
|
+
resetAll(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Close Redis connection if used
|
|
37
|
+
*/
|
|
38
|
+
close(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Get random delay between min and max
|
|
41
|
+
*/
|
|
42
|
+
private getRandomDelay;
|
|
43
|
+
/**
|
|
44
|
+
* Get last send time for account
|
|
45
|
+
*/
|
|
46
|
+
private getLastSendTime;
|
|
47
|
+
/**
|
|
48
|
+
* Set last send time for account
|
|
49
|
+
*/
|
|
50
|
+
private setLastSendTime;
|
|
51
|
+
/**
|
|
52
|
+
* Sleep for specified milliseconds
|
|
53
|
+
*/
|
|
54
|
+
private sleep;
|
|
55
|
+
/**
|
|
56
|
+
* Get current config
|
|
57
|
+
*/
|
|
58
|
+
getConfig(): {
|
|
59
|
+
mode: string;
|
|
60
|
+
minDelayMs: number;
|
|
61
|
+
maxDelayMs: number;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create rate limiter with default config (1-5s random delay)
|
|
66
|
+
*/
|
|
67
|
+
export declare function createDefaultRateLimiter(redisUrl?: string): RateLimiter;
|
|
68
|
+
//# sourceMappingURL=rate-limiter.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.service.d.ts","sourceRoot":"","sources":["../../src/services/rate-limiter.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAElE;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,EAAE,gBAAgB;IAUpC;;;OAGG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBjD;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMlD;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMrD;;OAEG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ7C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAW/B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;YACW,eAAe;IAQ7B;;OAEG;YACW,eAAe;IAS7B;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,SAAS,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;CAOtE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,CAOvE"}
|
|
@@ -0,0 +1,149 @@
|
|
|
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.RateLimiter = void 0;
|
|
7
|
+
exports.createDefaultRateLimiter = createDefaultRateLimiter;
|
|
8
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
9
|
+
/**
|
|
10
|
+
* Rate limiter with configurable random delay
|
|
11
|
+
* Supports in-memory and Redis modes for distributed rate limiting
|
|
12
|
+
*/
|
|
13
|
+
class RateLimiter {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.lastSendTime = new Map();
|
|
16
|
+
this.prefix = 'zalo:ratelimit:';
|
|
17
|
+
this.mode = config.mode;
|
|
18
|
+
this.minDelayMs = config.minDelayMs;
|
|
19
|
+
this.maxDelayMs = config.maxDelayMs;
|
|
20
|
+
if (config.mode === 'redis' && config.redisUrl) {
|
|
21
|
+
this.redis = new ioredis_1.default(config.redisUrl);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Wait for rate limit and acquire send slot
|
|
26
|
+
* Returns the delay that was applied
|
|
27
|
+
*/
|
|
28
|
+
async acquire(accountId) {
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
const lastSend = await this.getLastSendTime(accountId);
|
|
31
|
+
const elapsed = now - lastSend;
|
|
32
|
+
// Calculate random delay between min and max
|
|
33
|
+
const targetDelay = this.getRandomDelay();
|
|
34
|
+
// Calculate remaining wait time
|
|
35
|
+
const remainingWait = Math.max(0, targetDelay - elapsed);
|
|
36
|
+
if (remainingWait > 0) {
|
|
37
|
+
await this.sleep(remainingWait);
|
|
38
|
+
}
|
|
39
|
+
// Update last send time
|
|
40
|
+
await this.setLastSendTime(accountId, Date.now());
|
|
41
|
+
return remainingWait;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if can send immediately (without waiting)
|
|
45
|
+
*/
|
|
46
|
+
async canSend(accountId) {
|
|
47
|
+
const lastSend = await this.getLastSendTime(accountId);
|
|
48
|
+
const elapsed = Date.now() - lastSend;
|
|
49
|
+
return elapsed >= this.minDelayMs;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get time until next send is allowed
|
|
53
|
+
*/
|
|
54
|
+
async getWaitTime(accountId) {
|
|
55
|
+
const lastSend = await this.getLastSendTime(accountId);
|
|
56
|
+
const elapsed = Date.now() - lastSend;
|
|
57
|
+
return Math.max(0, this.minDelayMs - elapsed);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Reset rate limit for account
|
|
61
|
+
*/
|
|
62
|
+
async reset(accountId) {
|
|
63
|
+
if (this.mode === 'redis' && this.redis) {
|
|
64
|
+
await this.redis.del(`${this.prefix}${accountId}`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.lastSendTime.delete(accountId);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Reset all rate limits
|
|
72
|
+
*/
|
|
73
|
+
async resetAll() {
|
|
74
|
+
if (this.mode === 'redis' && this.redis) {
|
|
75
|
+
const keys = await this.redis.keys(`${this.prefix}*`);
|
|
76
|
+
if (keys.length > 0) {
|
|
77
|
+
await this.redis.del(...keys);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.lastSendTime.clear();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Close Redis connection if used
|
|
86
|
+
*/
|
|
87
|
+
async close() {
|
|
88
|
+
if (this.redis) {
|
|
89
|
+
await this.redis.quit();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get random delay between min and max
|
|
94
|
+
*/
|
|
95
|
+
getRandomDelay() {
|
|
96
|
+
return Math.floor(Math.random() * (this.maxDelayMs - this.minDelayMs + 1)) + this.minDelayMs;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get last send time for account
|
|
100
|
+
*/
|
|
101
|
+
async getLastSendTime(accountId) {
|
|
102
|
+
if (this.mode === 'redis' && this.redis) {
|
|
103
|
+
const value = await this.redis.get(`${this.prefix}${accountId}`);
|
|
104
|
+
return value ? parseInt(value, 10) : 0;
|
|
105
|
+
}
|
|
106
|
+
return this.lastSendTime.get(accountId) || 0;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Set last send time for account
|
|
110
|
+
*/
|
|
111
|
+
async setLastSendTime(accountId, time) {
|
|
112
|
+
if (this.mode === 'redis' && this.redis) {
|
|
113
|
+
// Store with 1 hour TTL
|
|
114
|
+
await this.redis.set(`${this.prefix}${accountId}`, time.toString(), 'EX', 3600);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.lastSendTime.set(accountId, time);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Sleep for specified milliseconds
|
|
122
|
+
*/
|
|
123
|
+
sleep(ms) {
|
|
124
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get current config
|
|
128
|
+
*/
|
|
129
|
+
getConfig() {
|
|
130
|
+
return {
|
|
131
|
+
mode: this.mode,
|
|
132
|
+
minDelayMs: this.minDelayMs,
|
|
133
|
+
maxDelayMs: this.maxDelayMs,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.RateLimiter = RateLimiter;
|
|
138
|
+
/**
|
|
139
|
+
* Create rate limiter with default config (1-5s random delay)
|
|
140
|
+
*/
|
|
141
|
+
function createDefaultRateLimiter(redisUrl) {
|
|
142
|
+
return new RateLimiter({
|
|
143
|
+
mode: redisUrl ? 'redis' : 'memory',
|
|
144
|
+
minDelayMs: 1000,
|
|
145
|
+
maxDelayMs: 5000,
|
|
146
|
+
redisUrl,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=rate-limiter.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.service.js","sourceRoot":"","sources":["../../src/services/rate-limiter.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { API } from 'zca-js';
|
|
2
|
+
import { IZaloApiAuth } from '../interfaces/auth.interface';
|
|
3
|
+
import { IConnectionConfig } from '../interfaces/config.interface';
|
|
4
|
+
/**
|
|
5
|
+
* Singleton manager for multi-account Zalo connections
|
|
6
|
+
* Handles connection lifecycle, health checks, and auto-reconnect
|
|
7
|
+
*/
|
|
8
|
+
export declare class ZaloConnectionManager {
|
|
9
|
+
private static instance;
|
|
10
|
+
private connections;
|
|
11
|
+
private config;
|
|
12
|
+
private healthCheckInterval?;
|
|
13
|
+
private constructor();
|
|
14
|
+
static getInstance(config?: Partial<IConnectionConfig>): ZaloConnectionManager;
|
|
15
|
+
/**
|
|
16
|
+
* Connect to Zalo account using credentials
|
|
17
|
+
*/
|
|
18
|
+
connect(auth: IZaloApiAuth): Promise<API>;
|
|
19
|
+
/**
|
|
20
|
+
* Parse auth to zca-js Credentials format
|
|
21
|
+
*/
|
|
22
|
+
private parseCredentials;
|
|
23
|
+
/**
|
|
24
|
+
* Parse cookie string (from browser) to Cookie array
|
|
25
|
+
*/
|
|
26
|
+
private parseCookieString;
|
|
27
|
+
/**
|
|
28
|
+
* Get existing connection by account ID
|
|
29
|
+
*/
|
|
30
|
+
getConnection(accountId: string): API | null;
|
|
31
|
+
/**
|
|
32
|
+
* Get connection by auth credentials
|
|
33
|
+
*/
|
|
34
|
+
getConnectionByAuth(auth: IZaloApiAuth): API | null;
|
|
35
|
+
/**
|
|
36
|
+
* Disconnect specific account
|
|
37
|
+
*/
|
|
38
|
+
disconnect(accountId: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Disconnect all accounts
|
|
41
|
+
*/
|
|
42
|
+
disconnectAll(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if account is connected
|
|
45
|
+
*/
|
|
46
|
+
isConnected(accountId: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Get all connected account IDs
|
|
49
|
+
*/
|
|
50
|
+
getConnectedAccounts(): string[];
|
|
51
|
+
/**
|
|
52
|
+
* Get account ID from auth credentials
|
|
53
|
+
* Uses accountId if provided, otherwise generates from cookie hash
|
|
54
|
+
*/
|
|
55
|
+
private getAccountId;
|
|
56
|
+
/**
|
|
57
|
+
* Start periodic health checks
|
|
58
|
+
*/
|
|
59
|
+
private startHealthCheck;
|
|
60
|
+
/**
|
|
61
|
+
* Stop health checks
|
|
62
|
+
*/
|
|
63
|
+
private stopHealthCheck;
|
|
64
|
+
/**
|
|
65
|
+
* Check all connections and reconnect if needed
|
|
66
|
+
*/
|
|
67
|
+
private checkConnections;
|
|
68
|
+
/**
|
|
69
|
+
* Attempt to reconnect an account
|
|
70
|
+
*/
|
|
71
|
+
reconnect(auth: IZaloApiAuth): Promise<API | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Get connection stats
|
|
74
|
+
*/
|
|
75
|
+
getStats(): {
|
|
76
|
+
totalConnections: number;
|
|
77
|
+
activeConnections: number;
|
|
78
|
+
accounts: {
|
|
79
|
+
id: string;
|
|
80
|
+
isConnected: boolean;
|
|
81
|
+
lastActivity: number;
|
|
82
|
+
}[];
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=zalo-connection-manager.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zalo-connection-manager.service.d.ts","sourceRoot":"","sources":["../../src/services/zalo-connection-manager.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,GAAG,EAAiC,MAAM,QAAQ,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAWnE;;;GAGG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAwB;IAC/C,OAAO,CAAC,WAAW,CAA0C;IAC7D,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,mBAAmB,CAAC,CAAiB;IAE7C,OAAO;IAUP,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,qBAAqB;IAO9E;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC;IAgC/C;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAS5C;;OAEG;IACH,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,GAAG,GAAG,IAAI;IAInD;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIvC;;OAEG;IACH,oBAAoB,IAAI,MAAM,EAAE;IAMhC;;;OAGG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;YACW,gBAAgB;IAa9B;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAoBxD;;OAEG;IACH,QAAQ,IAAI;QACV,gBAAgB,EAAE,MAAM,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,QAAQ,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,OAAO,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KACxE;CAaF"}
|