rynkai 0.1.3 → 0.1.5
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/README.md +51 -2
- package/dist/core/Middleware.test.d.ts +2 -0
- package/dist/core/Middleware.test.d.ts.map +1 -0
- package/dist/core/Middleware.test.js +60 -0
- package/dist/core/Middleware.test.js.map +1 -0
- package/dist/core/RateLimiter.test.d.ts +2 -0
- package/dist/core/RateLimiter.test.d.ts.map +1 -0
- package/dist/core/RateLimiter.test.js +52 -0
- package/dist/core/RateLimiter.test.js.map +1 -0
- package/dist/core/SendQueue.test.d.ts +2 -0
- package/dist/core/SendQueue.test.d.ts.map +1 -0
- package/dist/core/SendQueue.test.js +60 -0
- package/dist/core/SendQueue.test.js.map +1 -0
- package/dist/message/MessageBuilder.d.ts +28 -0
- package/dist/message/MessageBuilder.d.ts.map +1 -1
- package/dist/message/MessageBuilder.js +44 -0
- package/dist/message/MessageBuilder.js.map +1 -1
- package/dist/message/MessageParser.d.ts.map +1 -1
- package/dist/message/MessageParser.js +2 -0
- package/dist/message/MessageParser.js.map +1 -1
- package/dist/message/MessageParser.test.d.ts +2 -0
- package/dist/message/MessageParser.test.d.ts.map +1 -0
- package/dist/message/MessageParser.test.js +85 -0
- package/dist/message/MessageParser.test.js.map +1 -0
- package/dist/plugin/PluginLoader.test.d.ts +2 -0
- package/dist/plugin/PluginLoader.test.d.ts.map +1 -0
- package/dist/plugin/PluginLoader.test.js +82 -0
- package/dist/plugin/PluginLoader.test.js.map +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -89,6 +89,44 @@ bot.on('group-participants-update', ({ groupId, action, participants }) => {
|
|
|
89
89
|
});
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
## Interactive messages (button, list, poll)
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { MessageBuilder } from 'rynkai';
|
|
96
|
+
|
|
97
|
+
// Poll
|
|
98
|
+
await bot.send(chatId, MessageBuilder.poll('Makan apa nanti?', ['Nasi goreng', 'Mie ayam', 'Sate'], 1));
|
|
99
|
+
|
|
100
|
+
// Buttons
|
|
101
|
+
await bot.send(
|
|
102
|
+
chatId,
|
|
103
|
+
MessageBuilder.buttons(
|
|
104
|
+
'Pilih menu:',
|
|
105
|
+
[
|
|
106
|
+
{ id: 'menu_profile', text: 'Profil' },
|
|
107
|
+
{ id: 'menu_shop', text: 'Shop' },
|
|
108
|
+
],
|
|
109
|
+
'Bot Footer'
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// List
|
|
114
|
+
await bot.send(
|
|
115
|
+
chatId,
|
|
116
|
+
MessageBuilder.list('Pilih kategori:', 'Buka Menu', [
|
|
117
|
+
{
|
|
118
|
+
title: 'Kategori Utama',
|
|
119
|
+
rows: [
|
|
120
|
+
{ id: 'cat_weapon', title: 'Senjata', description: 'Lihat semua senjata' },
|
|
121
|
+
{ id: 'cat_armor', title: 'Armor', description: 'Lihat semua armor' },
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
])
|
|
125
|
+
);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
> Catatan: dukungan `buttons()` dan `list()` bervariasi antar versi WhatsApp client — beberapa versi terbaru membatasi tombol non-template dari akun biasa. Tes dulu di device tujuan sebelum diandalkan penuh di production; `poll()` jauh lebih stabil karena native feature WhatsApp.
|
|
129
|
+
|
|
92
130
|
## Download media
|
|
93
131
|
|
|
94
132
|
```ts
|
|
@@ -176,6 +214,15 @@ const bot = new Client({
|
|
|
176
214
|
bot.on('pairingCode', (code) => console.log('Kode pairing:', code));
|
|
177
215
|
```
|
|
178
216
|
|
|
217
|
+
## Testing
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npm test # run sekali
|
|
221
|
+
npm run test:watch # mode watch
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Test coverage saat ini: `MessageParser`, `PluginLoader` (termasuk cooldown), `RateLimiter`, `Middleware` (compose/onion), `SendQueue`.
|
|
225
|
+
|
|
179
226
|
## Status
|
|
180
227
|
|
|
181
228
|
Masih tahap awal (0.1.0). Yang sudah ada:
|
|
@@ -190,7 +237,9 @@ Masih tahap awal (0.1.0). Yang sudah ada:
|
|
|
190
237
|
- [x] Message send queue dengan throttle (anti rate-limit WA)
|
|
191
238
|
- [x] Presence helper (`sendTyping`, `sendPresence`)
|
|
192
239
|
- [x] Group helpers (metadata, add/remove/promote/demote, join-leave event)
|
|
240
|
+
- [x] Interactive messages (button, list, poll)
|
|
241
|
+
- [x] Test suite (MessageParser, PluginLoader, RateLimiter, Middleware, SendQueue)
|
|
193
242
|
|
|
194
243
|
Belum ada (rencana selanjutnya):
|
|
195
|
-
- [ ]
|
|
196
|
-
- [ ]
|
|
244
|
+
- [ ] CLI scaffold (`npx create-rynkai-bot`)
|
|
245
|
+
- [ ] GitHub Actions CI (auto build+test tiap push)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Middleware.test.d.ts","sourceRoot":"","sources":["../../src/core/Middleware.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const Middleware_1 = require("./Middleware");
|
|
5
|
+
function fakeCtx() {
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
(0, vitest_1.describe)('compose (middleware onion model)', () => {
|
|
9
|
+
(0, vitest_1.it)('menjalankan middleware sesuai urutan pendaftaran, lalu final handler', async () => {
|
|
10
|
+
const order = [];
|
|
11
|
+
const dispatch = (0, Middleware_1.compose)([
|
|
12
|
+
async (_ctx, next) => {
|
|
13
|
+
order.push('mw1-before');
|
|
14
|
+
await next();
|
|
15
|
+
order.push('mw1-after');
|
|
16
|
+
},
|
|
17
|
+
async (_ctx, next) => {
|
|
18
|
+
order.push('mw2-before');
|
|
19
|
+
await next();
|
|
20
|
+
order.push('mw2-after');
|
|
21
|
+
},
|
|
22
|
+
], async () => {
|
|
23
|
+
order.push('final');
|
|
24
|
+
});
|
|
25
|
+
await dispatch(fakeCtx());
|
|
26
|
+
(0, vitest_1.expect)(order).toEqual(['mw1-before', 'mw2-before', 'final', 'mw2-after', 'mw1-after']);
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)('final handler tidak jalan kalau middleware tidak memanggil next()', async () => {
|
|
29
|
+
const final = vitest_1.vi.fn();
|
|
30
|
+
const dispatch = (0, Middleware_1.compose)([
|
|
31
|
+
async () => {
|
|
32
|
+
// sengaja tidak panggil next()
|
|
33
|
+
},
|
|
34
|
+
], final);
|
|
35
|
+
await dispatch(fakeCtx());
|
|
36
|
+
(0, vitest_1.expect)(final).not.toHaveBeenCalled();
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.it)('jalan langsung ke final kalau tidak ada middleware', async () => {
|
|
39
|
+
const final = vitest_1.vi.fn();
|
|
40
|
+
const dispatch = (0, Middleware_1.compose)([], final);
|
|
41
|
+
await dispatch(fakeCtx());
|
|
42
|
+
(0, vitest_1.expect)(final).toHaveBeenCalledOnce();
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.it)('melempar error kalau next() dipanggil lebih dari sekali oleh middleware yang sama', async () => {
|
|
45
|
+
const dispatch = (0, Middleware_1.compose)([
|
|
46
|
+
async (_ctx, next) => {
|
|
47
|
+
await next();
|
|
48
|
+
await next(); // ini harus error
|
|
49
|
+
},
|
|
50
|
+
], async () => { });
|
|
51
|
+
await (0, vitest_1.expect)(dispatch(fakeCtx())).rejects.toThrow('next() dipanggil lebih dari sekali');
|
|
52
|
+
});
|
|
53
|
+
(0, vitest_1.it)('error dari middleware/final ter-propagate ke pemanggil dispatch', async () => {
|
|
54
|
+
const dispatch = (0, Middleware_1.compose)([], async () => {
|
|
55
|
+
throw new Error('gagal di final');
|
|
56
|
+
});
|
|
57
|
+
await (0, vitest_1.expect)(dispatch(fakeCtx())).rejects.toThrow('gagal di final');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=Middleware.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Middleware.test.js","sourceRoot":"","sources":["../../src/core/Middleware.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiter.test.d.ts","sourceRoot":"","sources":["../../src/core/RateLimiter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const RateLimiter_1 = require("./RateLimiter");
|
|
5
|
+
(0, vitest_1.describe)('RateLimiter', () => {
|
|
6
|
+
(0, vitest_1.beforeEach)(() => {
|
|
7
|
+
vitest_1.vi.useFakeTimers();
|
|
8
|
+
});
|
|
9
|
+
(0, vitest_1.afterEach)(() => {
|
|
10
|
+
vitest_1.vi.useRealTimers();
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)('mengizinkan request selama masih di bawah max', () => {
|
|
13
|
+
const limiter = new RateLimiter_1.RateLimiter({ max: 3, windowMs: 60_000 });
|
|
14
|
+
const user = 'userA';
|
|
15
|
+
(0, vitest_1.expect)(limiter.consume(user)).toBe(true);
|
|
16
|
+
(0, vitest_1.expect)(limiter.consume(user)).toBe(true);
|
|
17
|
+
(0, vitest_1.expect)(limiter.consume(user)).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
(0, vitest_1.it)('menolak request setelah melebihi max dalam satu window', () => {
|
|
20
|
+
const limiter = new RateLimiter_1.RateLimiter({ max: 2, windowMs: 60_000 });
|
|
21
|
+
const user = 'userA';
|
|
22
|
+
limiter.consume(user);
|
|
23
|
+
limiter.consume(user);
|
|
24
|
+
(0, vitest_1.expect)(limiter.consume(user)).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
(0, vitest_1.it)('reset otomatis setelah window berakhir', () => {
|
|
27
|
+
const limiter = new RateLimiter_1.RateLimiter({ max: 1, windowMs: 1000 });
|
|
28
|
+
const user = 'userA';
|
|
29
|
+
(0, vitest_1.expect)(limiter.consume(user)).toBe(true);
|
|
30
|
+
(0, vitest_1.expect)(limiter.consume(user)).toBe(false);
|
|
31
|
+
vitest_1.vi.advanceTimersByTime(1001);
|
|
32
|
+
(0, vitest_1.expect)(limiter.consume(user)).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)('tidak saling mempengaruhi antar user berbeda', () => {
|
|
35
|
+
const limiter = new RateLimiter_1.RateLimiter({ max: 1, windowMs: 60_000 });
|
|
36
|
+
(0, vitest_1.expect)(limiter.consume('userA')).toBe(true);
|
|
37
|
+
(0, vitest_1.expect)(limiter.consume('userB')).toBe(true);
|
|
38
|
+
(0, vitest_1.expect)(limiter.consume('userA')).toBe(false);
|
|
39
|
+
(0, vitest_1.expect)(limiter.consume('userB')).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)('retryAfter mengembalikan 0 kalau user belum pernah request', () => {
|
|
42
|
+
const limiter = new RateLimiter_1.RateLimiter({ max: 1, windowMs: 60_000 });
|
|
43
|
+
(0, vitest_1.expect)(limiter.retryAfter('userBaru')).toBe(0);
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)('retryAfter mengembalikan sisa detik yang mendekati window', () => {
|
|
46
|
+
const limiter = new RateLimiter_1.RateLimiter({ max: 1, windowMs: 10_000 });
|
|
47
|
+
limiter.consume('userA');
|
|
48
|
+
vitest_1.vi.advanceTimersByTime(4000);
|
|
49
|
+
(0, vitest_1.expect)(limiter.retryAfter('userA')).toBe(6);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=RateLimiter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiter.test.js","sourceRoot":"","sources":["../../src/core/RateLimiter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SendQueue.test.d.ts","sourceRoot":"","sources":["../../src/core/SendQueue.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const SendQueue_1 = require("./SendQueue");
|
|
5
|
+
(0, vitest_1.describe)('SendQueue', () => {
|
|
6
|
+
(0, vitest_1.beforeEach)(() => {
|
|
7
|
+
vitest_1.vi.useFakeTimers();
|
|
8
|
+
});
|
|
9
|
+
(0, vitest_1.afterEach)(() => {
|
|
10
|
+
vitest_1.vi.useRealTimers();
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.it)('menjalankan task dan resolve dengan hasilnya', async () => {
|
|
13
|
+
const queue = new SendQueue_1.SendQueue({ intervalMs: 100 });
|
|
14
|
+
const result = await queue.push(async () => 'hasil');
|
|
15
|
+
(0, vitest_1.expect)(result).toBe('hasil');
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.it)('menjalankan task secara berurutan (FIFO) dengan jeda antar task', async () => {
|
|
18
|
+
const queue = new SendQueue_1.SendQueue({ intervalMs: 100 });
|
|
19
|
+
const order = [];
|
|
20
|
+
const p1 = queue.push(async () => {
|
|
21
|
+
order.push(1);
|
|
22
|
+
});
|
|
23
|
+
const p2 = queue.push(async () => {
|
|
24
|
+
order.push(2);
|
|
25
|
+
});
|
|
26
|
+
const p3 = queue.push(async () => {
|
|
27
|
+
order.push(3);
|
|
28
|
+
});
|
|
29
|
+
await vitest_1.vi.runAllTimersAsync();
|
|
30
|
+
await Promise.all([p1, p2, p3]);
|
|
31
|
+
(0, vitest_1.expect)(order).toEqual([1, 2, 3]);
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)('reject promise kalau task melempar error, tapi tidak menghentikan antrian', async () => {
|
|
34
|
+
const queue = new SendQueue_1.SendQueue({ intervalMs: 10 });
|
|
35
|
+
const order = [];
|
|
36
|
+
const p1 = queue.push(async () => {
|
|
37
|
+
throw new Error('task 1 gagal');
|
|
38
|
+
});
|
|
39
|
+
p1.catch(() => { }); // pasang handler segera, cegah warning unhandled rejection dari Node
|
|
40
|
+
const p2 = queue.push(async () => {
|
|
41
|
+
order.push('task2 jalan');
|
|
42
|
+
});
|
|
43
|
+
await vitest_1.vi.runAllTimersAsync();
|
|
44
|
+
await (0, vitest_1.expect)(p1).rejects.toThrow('task 1 gagal');
|
|
45
|
+
await (0, vitest_1.expect)(p2).resolves.toBeUndefined();
|
|
46
|
+
(0, vitest_1.expect)(order).toEqual(['task2 jalan']);
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.it)('pending mencerminkan jumlah task yang masih menunggu', async () => {
|
|
49
|
+
const queue = new SendQueue_1.SendQueue({ intervalMs: 1000 });
|
|
50
|
+
queue.push(async () => { });
|
|
51
|
+
queue.push(async () => { });
|
|
52
|
+
const thirdTask = queue.push(async () => { });
|
|
53
|
+
// task pertama langsung mulai diproses, sisanya nunggu di antrian
|
|
54
|
+
(0, vitest_1.expect)(queue.pending).toBeGreaterThanOrEqual(1);
|
|
55
|
+
await vitest_1.vi.runAllTimersAsync();
|
|
56
|
+
await thirdTask;
|
|
57
|
+
(0, vitest_1.expect)(queue.pending).toBe(0);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=SendQueue.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SendQueue.test.js","sourceRoot":"","sources":["../../src/core/SendQueue.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,5 +21,33 @@ export declare const MessageBuilder: {
|
|
|
21
21
|
document(source: Buffer | {
|
|
22
22
|
url: string;
|
|
23
23
|
}, fileName: string, mimetype?: string): AnyMessageContent;
|
|
24
|
+
/**
|
|
25
|
+
* Poll bawaan WhatsApp. `selectableCount` = 1 berarti single-choice,
|
|
26
|
+
* lebih dari 1 berarti user boleh pilih banyak opsi.
|
|
27
|
+
*/
|
|
28
|
+
poll(name: string, options: string[], selectableCount?: number): AnyMessageContent;
|
|
29
|
+
/**
|
|
30
|
+
* Pesan dengan tombol quick-reply. Catatan: fitur ini pakai buttonsMessage
|
|
31
|
+
* lama Baileys — beberapa versi WhatsApp client sudah membatasi/menyembunyikan
|
|
32
|
+
* tombol non-template dari bisnis biasa. Tes dulu di device tujuan sebelum
|
|
33
|
+
* diandalkan penuh; kalau tidak muncul, fallback ke MessageBuilder.text()
|
|
34
|
+
* dengan opsi bernomor + baca via plugin command.
|
|
35
|
+
*/
|
|
36
|
+
buttons(text: string, buttons: {
|
|
37
|
+
id: string;
|
|
38
|
+
text: string;
|
|
39
|
+
}[], footer?: string): AnyMessageContent;
|
|
40
|
+
/**
|
|
41
|
+
* Pesan list (menu dropdown). Sama seperti buttons(), dukungannya
|
|
42
|
+
* bervariasi antar versi WhatsApp — tes dulu sebelum diandalkan penuh.
|
|
43
|
+
*/
|
|
44
|
+
list(text: string, buttonText: string, sections: {
|
|
45
|
+
title: string;
|
|
46
|
+
rows: {
|
|
47
|
+
id: string;
|
|
48
|
+
title: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
}[];
|
|
51
|
+
}[], footer?: string): AnyMessageContent;
|
|
24
52
|
};
|
|
25
53
|
//# sourceMappingURL=MessageBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageBuilder.d.ts","sourceRoot":"","sources":["../../src/message/MessageBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;;GAIG;AACH,eAAO,MAAM,cAAc;eACd,MAAM,GAAG,iBAAiB;kBAIvB,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,YAAY,MAAM,GAAG,iBAAiB;kBAI9D,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,YAAY,MAAM,GAAG,iBAAiB;kBAI9D,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,kBAAgB,iBAAiB;oBAIvD,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,iBAAiB;qBAI3C,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,YAAY,MAAM,sBAA0C,iBAAiB;
|
|
1
|
+
{"version":3,"file":"MessageBuilder.d.ts","sourceRoot":"","sources":["../../src/message/MessageBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;;GAIG;AACH,eAAO,MAAM,cAAc;eACd,MAAM,GAAG,iBAAiB;kBAIvB,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,YAAY,MAAM,GAAG,iBAAiB;kBAI9D,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,YAAY,MAAM,GAAG,iBAAiB;kBAI9D,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,kBAAgB,iBAAiB;oBAIvD,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,iBAAiB;qBAI3C,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,YAAY,MAAM,sBAA0C,iBAAiB;IAItH;;;OAGG;eACQ,MAAM,WAAW,MAAM,EAAE,6BAAwB,iBAAiB;IAU7E;;;;;;OAMG;kBACW,MAAM,WAAW;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,WAAW,MAAM,GAAG,iBAAiB;IAalG;;;OAGG;eAEK,MAAM,cACA,MAAM,YACR;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,EAAE,WACjF,MAAM,GACd,iBAAiB;CAQrB,CAAC"}
|
|
@@ -25,5 +25,49 @@ exports.MessageBuilder = {
|
|
|
25
25
|
document(source, fileName, mimetype = 'application/octet-stream') {
|
|
26
26
|
return { document: source, fileName, mimetype };
|
|
27
27
|
},
|
|
28
|
+
/**
|
|
29
|
+
* Poll bawaan WhatsApp. `selectableCount` = 1 berarti single-choice,
|
|
30
|
+
* lebih dari 1 berarti user boleh pilih banyak opsi.
|
|
31
|
+
*/
|
|
32
|
+
poll(name, options, selectableCount = 1) {
|
|
33
|
+
return {
|
|
34
|
+
poll: {
|
|
35
|
+
name,
|
|
36
|
+
values: options,
|
|
37
|
+
selectableCount,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
/**
|
|
42
|
+
* Pesan dengan tombol quick-reply. Catatan: fitur ini pakai buttonsMessage
|
|
43
|
+
* lama Baileys — beberapa versi WhatsApp client sudah membatasi/menyembunyikan
|
|
44
|
+
* tombol non-template dari bisnis biasa. Tes dulu di device tujuan sebelum
|
|
45
|
+
* diandalkan penuh; kalau tidak muncul, fallback ke MessageBuilder.text()
|
|
46
|
+
* dengan opsi bernomor + baca via plugin command.
|
|
47
|
+
*/
|
|
48
|
+
buttons(text, buttons, footer) {
|
|
49
|
+
return {
|
|
50
|
+
text,
|
|
51
|
+
footer,
|
|
52
|
+
buttons: buttons.map((b) => ({
|
|
53
|
+
buttonId: b.id,
|
|
54
|
+
buttonText: { displayText: b.text },
|
|
55
|
+
type: 1,
|
|
56
|
+
})),
|
|
57
|
+
headerType: 1,
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Pesan list (menu dropdown). Sama seperti buttons(), dukungannya
|
|
62
|
+
* bervariasi antar versi WhatsApp — tes dulu sebelum diandalkan penuh.
|
|
63
|
+
*/
|
|
64
|
+
list(text, buttonText, sections, footer) {
|
|
65
|
+
return {
|
|
66
|
+
text,
|
|
67
|
+
footer,
|
|
68
|
+
buttonText,
|
|
69
|
+
sections,
|
|
70
|
+
};
|
|
71
|
+
},
|
|
28
72
|
};
|
|
29
73
|
//# sourceMappingURL=MessageBuilder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageBuilder.js","sourceRoot":"","sources":["../../src/message/MessageBuilder.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACU,QAAA,cAAc,GAAG;IAC5B,IAAI,CAAC,IAAY;QACf,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,MAAgC,EAAE,OAAgB;QACtD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,MAAgC,EAAE,OAAgB;QACtD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,MAAgC,EAAE,GAAG,GAAG,KAAK;QACjD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IACvD,CAAC;IAED,OAAO,CAAC,MAAgC;QACtC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAC,MAAgC,EAAE,QAAgB,EAAE,QAAQ,GAAG,0BAA0B;QAChG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAClD,CAAC;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"MessageBuilder.js","sourceRoot":"","sources":["../../src/message/MessageBuilder.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACU,QAAA,cAAc,GAAG;IAC5B,IAAI,CAAC,IAAY;QACf,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,MAAgC,EAAE,OAAgB;QACtD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,MAAgC,EAAE,OAAgB;QACtD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,MAAgC,EAAE,GAAG,GAAG,KAAK;QACjD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IACvD,CAAC;IAED,OAAO,CAAC,MAAgC;QACtC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAC,MAAgC,EAAE,QAAgB,EAAE,QAAQ,GAAG,0BAA0B;QAChG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,IAAY,EAAE,OAAiB,EAAE,eAAe,GAAG,CAAC;QACvD,OAAO;YACL,IAAI,EAAE;gBACJ,IAAI;gBACJ,MAAM,EAAE,OAAO;gBACf,eAAe;aAChB;SACF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,IAAY,EAAE,OAAuC,EAAE,MAAe;QAC5E,OAAO;YACL,IAAI;YACJ,MAAM;YACN,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC3B,QAAQ,EAAE,CAAC,CAAC,EAAE;gBACd,UAAU,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE;gBACnC,IAAI,EAAE,CAAC;aACR,CAAC,CAAC;YACH,UAAU,EAAE,CAAC;SACO,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,IAAI,CACF,IAAY,EACZ,UAAkB,EAClB,QAA0F,EAC1F,MAAe;QAEf,OAAO;YACL,IAAI;YACJ,MAAM;YACN,UAAU;YACV,QAAQ;SACY,CAAC;IACzB,CAAC;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageParser.d.ts","sourceRoot":"","sources":["../../src/message/MessageParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAyB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"MessageParser.d.ts","sourceRoot":"","sources":["../../src/message/MessageParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAyB,MAAM,UAAU,CAAC;AAoDzE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,eAAe,GAAG,iBAAiB,CAiB1E"}
|
|
@@ -26,6 +26,8 @@ function detectType(msg) {
|
|
|
26
26
|
return 'contact';
|
|
27
27
|
if (msg.reactionMessage)
|
|
28
28
|
return 'reaction';
|
|
29
|
+
if (msg.pollCreationMessage || msg.pollCreationMessageV2 || msg.pollCreationMessageV3)
|
|
30
|
+
return 'poll';
|
|
29
31
|
return 'unknown';
|
|
30
32
|
}
|
|
31
33
|
/** Ambil teks dari berbagai kemungkinan lokasi (conversation, caption, dst) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageParser.js","sourceRoot":"","sources":["../../src/message/MessageParser.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"MessageParser.js","sourceRoot":"","sources":["../../src/message/MessageParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageParser.test.d.ts","sourceRoot":"","sources":["../../src/message/MessageParser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const MessageParser_1 = require("./MessageParser");
|
|
5
|
+
function fakeRaw(overrides = {}) {
|
|
6
|
+
return {
|
|
7
|
+
key: {
|
|
8
|
+
id: 'MSG1',
|
|
9
|
+
remoteJid: '628123456789@s.whatsapp.net',
|
|
10
|
+
fromMe: false,
|
|
11
|
+
},
|
|
12
|
+
message: {
|
|
13
|
+
conversation: 'halo bot',
|
|
14
|
+
},
|
|
15
|
+
messageTimestamp: 1700000000,
|
|
16
|
+
...overrides,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
(0, vitest_1.describe)('parseMessage', () => {
|
|
20
|
+
(0, vitest_1.it)('parse pesan text biasa dari chat pribadi', () => {
|
|
21
|
+
const result = (0, MessageParser_1.parseMessage)(fakeRaw());
|
|
22
|
+
(0, vitest_1.expect)(result.id).toBe('MSG1');
|
|
23
|
+
(0, vitest_1.expect)(result.chatId).toBe('628123456789@s.whatsapp.net');
|
|
24
|
+
(0, vitest_1.expect)(result.sender).toBe('628123456789@s.whatsapp.net');
|
|
25
|
+
(0, vitest_1.expect)(result.isGroup).toBe(false);
|
|
26
|
+
(0, vitest_1.expect)(result.type).toBe('text');
|
|
27
|
+
(0, vitest_1.expect)(result.text).toBe('halo bot');
|
|
28
|
+
(0, vitest_1.expect)(result.fromMe).toBe(false);
|
|
29
|
+
(0, vitest_1.expect)(result.quoted).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.it)('deteksi pesan dari grup dan ambil sender dari participant', () => {
|
|
32
|
+
const raw = fakeRaw({
|
|
33
|
+
key: {
|
|
34
|
+
id: 'MSG2',
|
|
35
|
+
remoteJid: '120363000000000000@g.us',
|
|
36
|
+
participant: '628999999999@s.whatsapp.net',
|
|
37
|
+
fromMe: false,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const result = (0, MessageParser_1.parseMessage)(raw);
|
|
41
|
+
(0, vitest_1.expect)(result.isGroup).toBe(true);
|
|
42
|
+
(0, vitest_1.expect)(result.chatId).toBe('120363000000000000@g.us');
|
|
43
|
+
(0, vitest_1.expect)(result.sender).toBe('628999999999@s.whatsapp.net');
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)('ambil caption sebagai text untuk pesan image', () => {
|
|
46
|
+
const raw = fakeRaw({
|
|
47
|
+
message: { imageMessage: { caption: 'lihat ini' } },
|
|
48
|
+
});
|
|
49
|
+
const result = (0, MessageParser_1.parseMessage)(raw);
|
|
50
|
+
(0, vitest_1.expect)(result.type).toBe('image');
|
|
51
|
+
(0, vitest_1.expect)(result.text).toBe('lihat ini');
|
|
52
|
+
});
|
|
53
|
+
(0, vitest_1.it)('return type unknown kalau tidak ada field message yang dikenali', () => {
|
|
54
|
+
const raw = fakeRaw({ message: {} });
|
|
55
|
+
const result = (0, MessageParser_1.parseMessage)(raw);
|
|
56
|
+
(0, vitest_1.expect)(result.type).toBe('unknown');
|
|
57
|
+
(0, vitest_1.expect)(result.text).toBe('');
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)('parse pesan reply/quoted dengan benar', () => {
|
|
60
|
+
const raw = fakeRaw({
|
|
61
|
+
message: {
|
|
62
|
+
extendedTextMessage: {
|
|
63
|
+
text: 'balasanku',
|
|
64
|
+
contextInfo: {
|
|
65
|
+
stanzaId: 'ORIGINAL1',
|
|
66
|
+
participant: '628111111111@s.whatsapp.net',
|
|
67
|
+
quotedMessage: { conversation: 'pesan asli' },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
const result = (0, MessageParser_1.parseMessage)(raw);
|
|
73
|
+
(0, vitest_1.expect)(result.text).toBe('balasanku');
|
|
74
|
+
(0, vitest_1.expect)(result.quoted).not.toBeNull();
|
|
75
|
+
(0, vitest_1.expect)(result.quoted?.id).toBe('ORIGINAL1');
|
|
76
|
+
(0, vitest_1.expect)(result.quoted?.text).toBe('pesan asli');
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)('fallback ke timestamp sekarang kalau messageTimestamp kosong', () => {
|
|
79
|
+
const raw = fakeRaw({ messageTimestamp: undefined });
|
|
80
|
+
const before = Math.floor(Date.now() / 1000);
|
|
81
|
+
const result = (0, MessageParser_1.parseMessage)(raw);
|
|
82
|
+
(0, vitest_1.expect)(result.timestamp).toBeGreaterThanOrEqual(before);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=MessageParser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageParser.test.js","sourceRoot":"","sources":["../../src/message/MessageParser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PluginLoader.test.d.ts","sourceRoot":"","sources":["../../src/plugin/PluginLoader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const PluginLoader_1 = require("./PluginLoader");
|
|
5
|
+
function fakeContext(sender = 'user1@s.whatsapp.net') {
|
|
6
|
+
return {
|
|
7
|
+
client: {},
|
|
8
|
+
message: { sender },
|
|
9
|
+
args: [],
|
|
10
|
+
reply: vitest_1.vi.fn(async () => { }),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
(0, vitest_1.describe)('PluginLoader', () => {
|
|
14
|
+
let loader;
|
|
15
|
+
(0, vitest_1.beforeEach)(() => {
|
|
16
|
+
loader = new PluginLoader_1.PluginLoader();
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.it)('register & find plugin berdasarkan command', () => {
|
|
19
|
+
const plugin = { name: 'ping', command: 'ping', execute: vitest_1.vi.fn() };
|
|
20
|
+
loader.register(plugin);
|
|
21
|
+
(0, vitest_1.expect)(loader.find('ping')).toBe(plugin);
|
|
22
|
+
(0, vitest_1.expect)(loader.find('PING')).toBe(plugin); // case-insensitive
|
|
23
|
+
(0, vitest_1.expect)(loader.find('tidak-ada')).toBeUndefined();
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.it)('register plugin dengan multiple command alias', () => {
|
|
26
|
+
const plugin = { name: 'hello', command: ['hello', 'hi'], execute: vitest_1.vi.fn() };
|
|
27
|
+
loader.register(plugin);
|
|
28
|
+
(0, vitest_1.expect)(loader.find('hello')).toBe(plugin);
|
|
29
|
+
(0, vitest_1.expect)(loader.find('hi')).toBe(plugin);
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.it)('execute menjalankan plugin yang cocok dan return true', async () => {
|
|
32
|
+
const execute = vitest_1.vi.fn();
|
|
33
|
+
loader.register({ name: 'ping', command: 'ping', execute });
|
|
34
|
+
const ctx = fakeContext();
|
|
35
|
+
const handled = await loader.execute('ping', ctx);
|
|
36
|
+
(0, vitest_1.expect)(handled).toBe(true);
|
|
37
|
+
(0, vitest_1.expect)(execute).toHaveBeenCalledWith(ctx);
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.it)('execute return false kalau tidak ada plugin yang cocok', async () => {
|
|
40
|
+
const ctx = fakeContext();
|
|
41
|
+
const handled = await loader.execute('tidak-ada', ctx);
|
|
42
|
+
(0, vitest_1.expect)(handled).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.it)('list() tidak duplikat walau plugin punya banyak alias command', () => {
|
|
45
|
+
loader.register({ name: 'hello', command: ['hello', 'hi', 'hey'], execute: vitest_1.vi.fn() });
|
|
46
|
+
(0, vitest_1.expect)(loader.list()).toHaveLength(1);
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.describe)('cooldown', () => {
|
|
49
|
+
(0, vitest_1.beforeEach)(() => {
|
|
50
|
+
vitest_1.vi.useFakeTimers();
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.afterEach)(() => {
|
|
53
|
+
vitest_1.vi.useRealTimers();
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)('blokir eksekusi kedua dalam window cooldown & kasih tau sisa waktu', async () => {
|
|
56
|
+
const execute = vitest_1.vi.fn();
|
|
57
|
+
loader.register({ name: 'heal', command: 'heal', cooldown: 10, execute });
|
|
58
|
+
const ctx = fakeContext('userA');
|
|
59
|
+
await loader.execute('heal', ctx); // panggilan pertama, lolos
|
|
60
|
+
await loader.execute('heal', ctx); // panggilan kedua, kena cooldown
|
|
61
|
+
(0, vitest_1.expect)(execute).toHaveBeenCalledTimes(1);
|
|
62
|
+
(0, vitest_1.expect)(ctx.reply).toHaveBeenCalledWith(vitest_1.expect.stringContaining('Tunggu'));
|
|
63
|
+
});
|
|
64
|
+
(0, vitest_1.it)('boleh eksekusi lagi setelah cooldown habis', async () => {
|
|
65
|
+
const execute = vitest_1.vi.fn();
|
|
66
|
+
loader.register({ name: 'heal', command: 'heal', cooldown: 10, execute });
|
|
67
|
+
const ctx = fakeContext('userA');
|
|
68
|
+
await loader.execute('heal', ctx);
|
|
69
|
+
vitest_1.vi.advanceTimersByTime(10_001);
|
|
70
|
+
await loader.execute('heal', ctx);
|
|
71
|
+
(0, vitest_1.expect)(execute).toHaveBeenCalledTimes(2);
|
|
72
|
+
});
|
|
73
|
+
(0, vitest_1.it)('cooldown per-user, tidak saling mempengaruhi antar user berbeda', async () => {
|
|
74
|
+
const execute = vitest_1.vi.fn();
|
|
75
|
+
loader.register({ name: 'heal', command: 'heal', cooldown: 10, execute });
|
|
76
|
+
await loader.execute('heal', fakeContext('userA'));
|
|
77
|
+
await loader.execute('heal', fakeContext('userB'));
|
|
78
|
+
(0, vitest_1.expect)(execute).toHaveBeenCalledTimes(2);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
//# sourceMappingURL=PluginLoader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PluginLoader.test.js","sourceRoot":"","sources":["../../src/plugin/PluginLoader.test.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { WASocket, AuthenticationState, proto } from '@whiskeysockets/baileys';
|
|
2
2
|
/** Jenis pesan yang sudah dinormalisasi, dipakai di seluruh library (bukan raw proto Baileys) */
|
|
3
|
-
export type NormalizedMessageType = 'text' | 'image' | 'video' | 'audio' | 'sticker' | 'document' | 'location' | 'contact' | 'reaction' | 'unknown';
|
|
3
|
+
export type NormalizedMessageType = 'text' | 'image' | 'video' | 'audio' | 'sticker' | 'document' | 'location' | 'contact' | 'reaction' | 'poll' | 'unknown';
|
|
4
4
|
export interface NormalizedMessage {
|
|
5
5
|
/** ID unik pesan dari WhatsApp */
|
|
6
6
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEpF,iGAAiG;AACjG,MAAM,MAAM,qBAAqB,GAC7B,MAAM,GACN,OAAO,GACP,OAAO,GACP,OAAO,GACP,SAAS,GACT,UAAU,GACV,UAAU,GACV,SAAS,GACT,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,EAAE,OAAO,CAAC;IAChB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,uGAAuG;IACvG,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IACjD,iFAAiF;IACjF,GAAG,EAAE,KAAK,CAAC,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,IAAI,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAC5C,8EAA8E;IAC9E,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,mDAAmD;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,QAAQ,CAAC;IACjB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,uEAAuE;IACvE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,WAAW,CAAC,EAAE;QACZ,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IACpE;;;OAGG;IACH,SAAS,CAAC,EAAE;QACV,yCAAyC;QACzC,GAAG,EAAE,MAAM,CAAC;QACZ,qCAAqC;QACrC,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,2FAA2F;IAC3F,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEpF,iGAAiG;AACjG,MAAM,MAAM,qBAAqB,GAC7B,MAAM,GACN,OAAO,GACP,OAAO,GACP,OAAO,GACP,SAAS,GACT,UAAU,GACV,UAAU,GACV,SAAS,GACT,UAAU,GACV,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,EAAE,OAAO,CAAC;IAChB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,uGAAuG;IACvG,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC;IACjD,iFAAiF;IACjF,GAAG,EAAE,KAAK,CAAC,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,IAAI,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAC5C,8EAA8E;IAC9E,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,mDAAmD;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,QAAQ,CAAC;IACjB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,uEAAuE;IACvE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,WAAW,CAAC,EAAE;QACZ,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IACpE;;;OAGG;IACH,SAAS,CAAC,EAAE;QACV,yCAAyC;QACzC,GAAG,EAAE,MAAM,CAAC;QACZ,qCAAqC;QACrC,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,2FAA2F;IAC3F,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rynkai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Clean, typed wrapper around Baileys with built-in plugin system and pluggable session store — for building WhatsApp bots fast.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc -p tsconfig.json",
|
|
10
10
|
"dev": "ts-node-dev --respawn --transpile-only src/index.ts",
|
|
11
|
-
"
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"prepublishOnly": "npm run build && npm test"
|
|
12
14
|
},
|
|
13
15
|
"keywords": [
|
|
14
16
|
"whatsapp",
|
|
@@ -43,7 +45,8 @@
|
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"typescript": "^5.5.4",
|
|
45
47
|
"ts-node-dev": "^2.0.0",
|
|
46
|
-
"@types/node": "^20.14.0"
|
|
48
|
+
"@types/node": "^20.14.0",
|
|
49
|
+
"vitest": "^2.1.0"
|
|
47
50
|
},
|
|
48
51
|
"files": [
|
|
49
52
|
"dist"
|