@kangwifi-pro/waliwa 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 +600 -0
- package/dist/advanced/features.d.ts +211 -0
- package/dist/advanced/features.d.ts.map +1 -0
- package/dist/advanced/features.js +671 -0
- package/dist/advanced/features.js.map +1 -0
- package/dist/auth/auth-state.d.ts +89 -0
- package/dist/auth/auth-state.d.ts.map +1 -0
- package/dist/auth/auth-state.js +330 -0
- package/dist/auth/auth-state.js.map +1 -0
- package/dist/auth/pairing-code.d.ts +78 -0
- package/dist/auth/pairing-code.d.ts.map +1 -0
- package/dist/auth/pairing-code.js +191 -0
- package/dist/auth/pairing-code.js.map +1 -0
- package/dist/auth/qr-code.d.ts +60 -0
- package/dist/auth/qr-code.d.ts.map +1 -0
- package/dist/auth/qr-code.js +151 -0
- package/dist/auth/qr-code.js.map +1 -0
- package/dist/calls/handler.d.ts +61 -0
- package/dist/calls/handler.d.ts.map +1 -0
- package/dist/calls/handler.js +117 -0
- package/dist/calls/handler.js.map +1 -0
- package/dist/core/binary.d.ts +74 -0
- package/dist/core/binary.d.ts.map +1 -0
- package/dist/core/binary.js +448 -0
- package/dist/core/binary.js.map +1 -0
- package/dist/core/crypto.d.ts +60 -0
- package/dist/core/crypto.d.ts.map +1 -0
- package/dist/core/crypto.js +170 -0
- package/dist/core/crypto.js.map +1 -0
- package/dist/core/noise.d.ts +106 -0
- package/dist/core/noise.d.ts.map +1 -0
- package/dist/core/noise.js +307 -0
- package/dist/core/noise.js.map +1 -0
- package/dist/events/emitter.d.ts +44 -0
- package/dist/events/emitter.d.ts.map +1 -0
- package/dist/events/emitter.js +79 -0
- package/dist/events/emitter.js.map +1 -0
- package/dist/features/index.d.ts +342 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +755 -0
- package/dist/features/index.js.map +1 -0
- package/dist/fixes/index.d.ts +333 -0
- package/dist/fixes/index.d.ts.map +1 -0
- package/dist/fixes/index.js +762 -0
- package/dist/fixes/index.js.map +1 -0
- package/dist/groups/management.d.ts +86 -0
- package/dist/groups/management.d.ts.map +1 -0
- package/dist/groups/management.js +443 -0
- package/dist/groups/management.js.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +236 -0
- package/dist/index.js.map +1 -0
- package/dist/messages/media.d.ts +93 -0
- package/dist/messages/media.d.ts.map +1 -0
- package/dist/messages/media.js +252 -0
- package/dist/messages/media.js.map +1 -0
- package/dist/messages/message-encoder.d.ts +70 -0
- package/dist/messages/message-encoder.d.ts.map +1 -0
- package/dist/messages/message-encoder.js +453 -0
- package/dist/messages/message-encoder.js.map +1 -0
- package/dist/messages/send.d.ts +101 -0
- package/dist/messages/send.d.ts.map +1 -0
- package/dist/messages/send.js +409 -0
- package/dist/messages/send.js.map +1 -0
- package/dist/recovery/index.d.ts +125 -0
- package/dist/recovery/index.d.ts.map +1 -0
- package/dist/recovery/index.js +584 -0
- package/dist/recovery/index.js.map +1 -0
- package/dist/skdm/index.d.ts +220 -0
- package/dist/skdm/index.d.ts.map +1 -0
- package/dist/skdm/index.js +600 -0
- package/dist/skdm/index.js.map +1 -0
- package/dist/socket/hybrid.d.ts +118 -0
- package/dist/socket/hybrid.d.ts.map +1 -0
- package/dist/socket/hybrid.js +352 -0
- package/dist/socket/hybrid.js.map +1 -0
- package/dist/socket/wa-socket.d.ts +300 -0
- package/dist/socket/wa-socket.d.ts.map +1 -0
- package/dist/socket/wa-socket.js +1094 -0
- package/dist/socket/wa-socket.js.map +1 -0
- package/dist/socket/ws-socket.d.ts +96 -0
- package/dist/socket/ws-socket.d.ts.map +1 -0
- package/dist/socket/ws-socket.js +302 -0
- package/dist/socket/ws-socket.js.map +1 -0
- package/dist/types/index.d.ts +444 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/jid.d.ts +46 -0
- package/dist/utils/jid.d.ts.map +1 -0
- package/dist/utils/jid.js +152 -0
- package/dist/utils/jid.js.map +1 -0
- package/dist/utils/logger.d.ts +45 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +79 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/retry.d.ts +43 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +175 -0
- package/dist/utils/retry.js.map +1 -0
- package/docs/API.md +745 -0
- package/docs/ARCHITECTURE.md +307 -0
- package/docs/BAILEYS_FIXES.md +360 -0
- package/docs/FEATURES.md +532 -0
- package/docs/PROTOCOL.md +489 -0
- package/docs/RECOVERY.md +409 -0
- package/docs/SKDM.md +233 -0
- package/examples/ai-bot/index.ts +479 -0
- package/examples/ai-bot/package.json +17 -0
- package/examples/echo-bot/index.ts +171 -0
- package/examples/echo-bot/package.json +18 -0
- package/examples/group-bot/index.ts +557 -0
- package/examples/group-bot/package.json +17 -0
- package/examples/rest-gateway/index.ts +499 -0
- package/examples/rest-gateway/package.json +19 -0
- package/package.json +75 -0
- package/src/advanced/features.ts +817 -0
- package/src/auth/auth-state.ts +342 -0
- package/src/auth/pairing-code.ts +246 -0
- package/src/auth/qr-code.ts +191 -0
- package/src/calls/handler.ts +153 -0
- package/src/core/binary.ts +464 -0
- package/src/core/crypto.ts +189 -0
- package/src/core/noise.ts +406 -0
- package/src/events/emitter.ts +88 -0
- package/src/features/index.ts +921 -0
- package/src/fixes/index.ts +882 -0
- package/src/groups/management.ts +497 -0
- package/src/index.ts +274 -0
- package/src/messages/media.ts +372 -0
- package/src/messages/message-encoder.ts +520 -0
- package/src/messages/send.ts +521 -0
- package/src/recovery/index.ts +704 -0
- package/src/skdm/index.ts +693 -0
- package/src/socket/hybrid.ts +414 -0
- package/src/socket/wa-socket.ts +1347 -0
- package/src/socket/ws-socket.ts +355 -0
- package/src/types/index.ts +457 -0
- package/src/utils/jid.ts +156 -0
- package/src/utils/logger.ts +84 -0
- package/src/utils/retry.ts +205 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waliwa - Retry & throttle utilities
|
|
3
|
+
* Implementasi efficient untuk retry exponential backoff dan rate limiting
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getRandomBytes } from '../core/crypto.js';
|
|
7
|
+
|
|
8
|
+
// ============== Retry ==============
|
|
9
|
+
|
|
10
|
+
export interface RetryOptions {
|
|
11
|
+
retries?: number;
|
|
12
|
+
minTimeout?: number;
|
|
13
|
+
maxTimeout?: number;
|
|
14
|
+
factor?: number;
|
|
15
|
+
randomize?: boolean;
|
|
16
|
+
onFailedAttempt?: (error: Error, attempt: number) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Exponential backoff retry dengan jitter
|
|
21
|
+
*/
|
|
22
|
+
export async function retry<T>(
|
|
23
|
+
fn: () => Promise<T>,
|
|
24
|
+
options: RetryOptions = {}
|
|
25
|
+
): Promise<T> {
|
|
26
|
+
const {
|
|
27
|
+
retries = 5,
|
|
28
|
+
minTimeout = 500,
|
|
29
|
+
maxTimeout = 30000,
|
|
30
|
+
factor = 2,
|
|
31
|
+
randomize = true,
|
|
32
|
+
onFailedAttempt
|
|
33
|
+
} = options;
|
|
34
|
+
|
|
35
|
+
let attempt = 0;
|
|
36
|
+
let lastError: Error;
|
|
37
|
+
|
|
38
|
+
while (attempt <= retries) {
|
|
39
|
+
try {
|
|
40
|
+
return await fn();
|
|
41
|
+
} catch (err) {
|
|
42
|
+
lastError = err as Error;
|
|
43
|
+
attempt++;
|
|
44
|
+
if (attempt > retries) {
|
|
45
|
+
throw lastError;
|
|
46
|
+
}
|
|
47
|
+
if (onFailedAttempt) {
|
|
48
|
+
onFailedAttempt(lastError, attempt);
|
|
49
|
+
}
|
|
50
|
+
// Exponential backoff dengan jitter
|
|
51
|
+
let delay = minTimeout * Math.pow(factor, attempt - 1);
|
|
52
|
+
if (randomize) {
|
|
53
|
+
const jitter = (getRandomBytes(1)[0] / 255) * 0.3;
|
|
54
|
+
delay = delay * (1 + jitter);
|
|
55
|
+
}
|
|
56
|
+
delay = Math.min(delay, maxTimeout);
|
|
57
|
+
await sleep(delay);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw lastError!;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function sleep(ms: number): Promise<void> {
|
|
64
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============== Throttle / Rate Limiter ==============
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Token bucket rate limiter - RAM-efficient (single object per limiter)
|
|
71
|
+
*/
|
|
72
|
+
export class RateLimiter {
|
|
73
|
+
private tokens: number;
|
|
74
|
+
private lastRefill: number;
|
|
75
|
+
private readonly maxTokens: number;
|
|
76
|
+
private readonly refillRate: number; // tokens per ms
|
|
77
|
+
private readonly queue: Array<{ resolve: () => void; reject: (err: Error) => void }> = [];
|
|
78
|
+
private processing: boolean = false;
|
|
79
|
+
|
|
80
|
+
constructor(maxTokensPerSecond: number) {
|
|
81
|
+
this.maxTokens = maxTokensPerSecond;
|
|
82
|
+
this.tokens = maxTokensPerSecond;
|
|
83
|
+
this.refillRate = maxTokensPerSecond / 1000;
|
|
84
|
+
this.lastRefill = Date.now();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private refill(): void {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const elapsed = now - this.lastRefill;
|
|
90
|
+
this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
|
|
91
|
+
this.lastRefill = now;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async acquire(): Promise<void> {
|
|
95
|
+
this.refill();
|
|
96
|
+
if (this.tokens >= 1) {
|
|
97
|
+
this.tokens -= 1;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Queue
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
this.queue.push({ resolve, reject });
|
|
103
|
+
this.processQueue();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private processQueue(): void {
|
|
108
|
+
if (this.processing) return;
|
|
109
|
+
this.processing = true;
|
|
110
|
+
const tick = () => {
|
|
111
|
+
this.refill();
|
|
112
|
+
while (this.queue.length > 0 && this.tokens >= 1) {
|
|
113
|
+
this.tokens -= 1;
|
|
114
|
+
const item = this.queue.shift()!;
|
|
115
|
+
item.resolve();
|
|
116
|
+
}
|
|
117
|
+
if (this.queue.length > 0) {
|
|
118
|
+
setTimeout(tick, 50);
|
|
119
|
+
} else {
|
|
120
|
+
this.processing = false;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
tick();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Destroy limiter dan reject semua queued requests */
|
|
127
|
+
destroy(): void {
|
|
128
|
+
while (this.queue.length > 0) {
|
|
129
|
+
const item = this.queue.shift()!;
|
|
130
|
+
item.reject(new Error('Rate limiter destroyed'));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ============== Debounce ==============
|
|
136
|
+
|
|
137
|
+
export function debounce<T extends (...args: any[]) => void>(
|
|
138
|
+
fn: T,
|
|
139
|
+
wait: number
|
|
140
|
+
): (...args: Parameters<T>) => void {
|
|
141
|
+
let timeout: NodeJS.Timeout | null = null;
|
|
142
|
+
return (...args: Parameters<T>) => {
|
|
143
|
+
if (timeout) clearTimeout(timeout);
|
|
144
|
+
timeout = setTimeout(() => fn(...args), wait);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ============== Throttle (leading edge) ==============
|
|
149
|
+
|
|
150
|
+
export function throttle<T extends (...args: any[]) => void>(
|
|
151
|
+
fn: T,
|
|
152
|
+
wait: number
|
|
153
|
+
): (...args: Parameters<T>) => void {
|
|
154
|
+
let lastCall = 0;
|
|
155
|
+
let timeout: NodeJS.Timeout | null = null;
|
|
156
|
+
return (...args: Parameters<T>) => {
|
|
157
|
+
const now = Date.now();
|
|
158
|
+
const remaining = wait - (now - lastCall);
|
|
159
|
+
if (remaining <= 0) {
|
|
160
|
+
if (timeout) {
|
|
161
|
+
clearTimeout(timeout);
|
|
162
|
+
timeout = null;
|
|
163
|
+
}
|
|
164
|
+
lastCall = now;
|
|
165
|
+
fn(...args);
|
|
166
|
+
} else if (!timeout) {
|
|
167
|
+
timeout = setTimeout(() => {
|
|
168
|
+
lastCall = Date.now();
|
|
169
|
+
timeout = null;
|
|
170
|
+
fn(...args);
|
|
171
|
+
}, remaining);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ============== Promise Queue (sequential execution) ==============
|
|
177
|
+
|
|
178
|
+
export class PromiseQueue {
|
|
179
|
+
private queue: Array<() => Promise<void>> = [];
|
|
180
|
+
private running: boolean = false;
|
|
181
|
+
|
|
182
|
+
async add<T>(fn: () => Promise<T>): Promise<T> {
|
|
183
|
+
return new Promise<T>((resolve, reject) => {
|
|
184
|
+
this.queue.push(async () => {
|
|
185
|
+
try {
|
|
186
|
+
const result = await fn();
|
|
187
|
+
resolve(result);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
reject(err);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
this.process();
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private async process(): Promise<void> {
|
|
197
|
+
if (this.running) return;
|
|
198
|
+
this.running = true;
|
|
199
|
+
while (this.queue.length > 0) {
|
|
200
|
+
const task = this.queue.shift()!;
|
|
201
|
+
await task();
|
|
202
|
+
}
|
|
203
|
+
this.running = false;
|
|
204
|
+
}
|
|
205
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"noImplicitAny": true,
|
|
14
|
+
"strictNullChecks": true,
|
|
15
|
+
"strictFunctionTypes": true,
|
|
16
|
+
"noUnusedLocals": false,
|
|
17
|
+
"noUnusedParameters": false,
|
|
18
|
+
"noImplicitReturns": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true,
|
|
20
|
+
"esModuleInterop": true,
|
|
21
|
+
"allowSyntheticDefaultImports": true,
|
|
22
|
+
"forceConsistentCasingInFileNames": true,
|
|
23
|
+
"skipLibCheck": true,
|
|
24
|
+
"resolveJsonModule": true,
|
|
25
|
+
"experimentalDecorators": true,
|
|
26
|
+
"emitDecoratorMetadata": true
|
|
27
|
+
},
|
|
28
|
+
"include": ["src/**/*.ts"],
|
|
29
|
+
"exclude": ["node_modules", "dist", "examples", "**/*.test.ts"]
|
|
30
|
+
}
|