@roidev/kachina-md 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 +461 -0
- package/lib/client/Client.js +257 -0
- package/lib/handlers/PluginHandler.js +190 -0
- package/lib/helpers/database.js +117 -0
- package/lib/helpers/index.js +74 -0
- package/lib/helpers/logger.js +66 -0
- package/lib/helpers/serialize.js +120 -0
- package/lib/helpers/sticker.js +72 -0
- package/lib/index.js +30 -0
- package/package.json +67 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { downloadMediaMessage, getContentType } from 'baileys';
|
|
2
|
+
import { fileTypeFromBuffer } from 'file-type';
|
|
3
|
+
|
|
4
|
+
export async function serialize(msg, sock) {
|
|
5
|
+
if (!msg) return msg;
|
|
6
|
+
|
|
7
|
+
const m = {};
|
|
8
|
+
|
|
9
|
+
// Basic info
|
|
10
|
+
m.key = msg.key;
|
|
11
|
+
m.chat = msg.key.remoteJid;
|
|
12
|
+
m.fromMe = msg.key.fromMe;
|
|
13
|
+
m.id = msg.key.id;
|
|
14
|
+
m.isGroup = m.chat.endsWith('@g.us');
|
|
15
|
+
m.sender = m.isGroup ? msg.key.participant : m.chat;
|
|
16
|
+
m.pushName = msg.pushName || '';
|
|
17
|
+
|
|
18
|
+
// Message type
|
|
19
|
+
const type = getContentType(msg.message);
|
|
20
|
+
m.type = type;
|
|
21
|
+
m.message = msg.message;
|
|
22
|
+
|
|
23
|
+
// Get message body
|
|
24
|
+
m.body = getBody(msg.message);
|
|
25
|
+
|
|
26
|
+
// Get quoted message
|
|
27
|
+
const quoted = msg.message?.[type]?.contextInfo?.quotedMessage;
|
|
28
|
+
if (quoted) {
|
|
29
|
+
m.quoted = await serialize({
|
|
30
|
+
key: {
|
|
31
|
+
remoteJid: m.chat,
|
|
32
|
+
fromMe: msg.message[type].contextInfo.participant === sock.user.id,
|
|
33
|
+
id: msg.message[type].contextInfo.stanzaId,
|
|
34
|
+
participant: msg.message[type].contextInfo.participant
|
|
35
|
+
},
|
|
36
|
+
message: quoted,
|
|
37
|
+
pushName: msg.message[type].contextInfo.pushName || ''
|
|
38
|
+
}, sock);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Media info
|
|
42
|
+
if (type && msg.message[type]) {
|
|
43
|
+
const msgContent = msg.message[type];
|
|
44
|
+
m.caption = msgContent.caption || '';
|
|
45
|
+
m.mimetype = msgContent.mimetype || '';
|
|
46
|
+
m.fileSize = msgContent.fileLength || msgContent.fileSha256 || 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Mentions
|
|
50
|
+
m.mentions = msg.message?.[type]?.contextInfo?.mentionedJid || [];
|
|
51
|
+
|
|
52
|
+
// Helper methods
|
|
53
|
+
m.reply = async (text, options = {}) => {
|
|
54
|
+
return await sock.sendMessage(m.chat, { text, ...options }, { quoted: msg });
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
m.react = async (emoji) => {
|
|
58
|
+
return await sock.sendMessage(m.chat, {
|
|
59
|
+
react: { text: emoji, key: m.key }
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
m.download = async () => {
|
|
64
|
+
if (!msg.message) return null;
|
|
65
|
+
try {
|
|
66
|
+
const buffer = await downloadMediaMessage(msg, 'buffer', {});
|
|
67
|
+
return buffer;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Download error:', error);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
m.delete = async () => {
|
|
75
|
+
return await sock.sendMessage(m.chat, { delete: m.key });
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
m.forward = async (jid, options = {}) => {
|
|
79
|
+
return await sock.sendMessage(jid, { forward: msg }, options);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
m.copyNForward = async (jid, options = {}) => {
|
|
83
|
+
return await sock.copyNForward(jid, msg, options);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return m;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getBody(message) {
|
|
90
|
+
if (!message) return '';
|
|
91
|
+
|
|
92
|
+
const type = getContentType(message);
|
|
93
|
+
if (!type) return '';
|
|
94
|
+
|
|
95
|
+
const content = message[type];
|
|
96
|
+
|
|
97
|
+
// Text messages
|
|
98
|
+
if (type === 'conversation') return content;
|
|
99
|
+
if (type === 'extendedTextMessage') return content.text;
|
|
100
|
+
|
|
101
|
+
// Button responses
|
|
102
|
+
if (type === 'buttonsResponseMessage') return content.selectedButtonId;
|
|
103
|
+
if (type === 'templateButtonReplyMessage') return content.selectedId;
|
|
104
|
+
if (type === 'listResponseMessage') return content.singleSelectReply?.selectedRowId;
|
|
105
|
+
if (type === 'interactiveResponseMessage') {
|
|
106
|
+
try {
|
|
107
|
+
const response = JSON.parse(content.nativeFlowResponseMessage?.paramsJson || '{}');
|
|
108
|
+
return response.id || '';
|
|
109
|
+
} catch {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Media messages with caption
|
|
115
|
+
if (content.caption) return content.caption;
|
|
116
|
+
|
|
117
|
+
return '';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export default serialize;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Sticker, StickerTypes } from 'wa-sticker-formatter';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create sticker from image/video buffer
|
|
5
|
+
* @param {Buffer} buffer - Image or video buffer
|
|
6
|
+
* @param {Object} options - Sticker options
|
|
7
|
+
* @returns {Promise<Buffer>} Sticker buffer
|
|
8
|
+
*/
|
|
9
|
+
export async function createSticker(buffer, options = {}) {
|
|
10
|
+
const sticker = new Sticker(buffer, {
|
|
11
|
+
pack: options.pack || 'Sticker',
|
|
12
|
+
author: options.author || 'Kachina Bot',
|
|
13
|
+
type: options.type || StickerTypes.DEFAULT,
|
|
14
|
+
categories: options.categories || [],
|
|
15
|
+
id: options.id || '',
|
|
16
|
+
quality: options.quality || 50,
|
|
17
|
+
background: options.background || 'transparent'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return await sticker.toBuffer();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create full sticker (no crop)
|
|
25
|
+
*/
|
|
26
|
+
export async function createFullSticker(buffer, options = {}) {
|
|
27
|
+
return await createSticker(buffer, {
|
|
28
|
+
...options,
|
|
29
|
+
type: StickerTypes.FULL
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create cropped sticker
|
|
35
|
+
*/
|
|
36
|
+
export async function createCroppedSticker(buffer, options = {}) {
|
|
37
|
+
return await createSticker(buffer, {
|
|
38
|
+
...options,
|
|
39
|
+
type: StickerTypes.CROPPED
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Create circle sticker
|
|
45
|
+
*/
|
|
46
|
+
export async function createCircleSticker(buffer, options = {}) {
|
|
47
|
+
return await createSticker(buffer, {
|
|
48
|
+
...options,
|
|
49
|
+
type: StickerTypes.CIRCLE
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create rounded sticker
|
|
55
|
+
*/
|
|
56
|
+
export async function createRoundedSticker(buffer, options = {}) {
|
|
57
|
+
return await createSticker(buffer, {
|
|
58
|
+
...options,
|
|
59
|
+
type: StickerTypes.ROUNDED
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { StickerTypes };
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
createSticker,
|
|
67
|
+
createFullSticker,
|
|
68
|
+
createCroppedSticker,
|
|
69
|
+
createCircleSticker,
|
|
70
|
+
createRoundedSticker,
|
|
71
|
+
StickerTypes
|
|
72
|
+
};
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Main exports
|
|
2
|
+
export { Client } from './client/Client.js';
|
|
3
|
+
export { PluginHandler } from './handlers/PluginHandler.js';
|
|
4
|
+
|
|
5
|
+
// Helpers
|
|
6
|
+
export {
|
|
7
|
+
serialize,
|
|
8
|
+
Database,
|
|
9
|
+
Logger,
|
|
10
|
+
createSticker,
|
|
11
|
+
createFullSticker,
|
|
12
|
+
createCroppedSticker,
|
|
13
|
+
createCircleSticker,
|
|
14
|
+
createRoundedSticker,
|
|
15
|
+
StickerTypes,
|
|
16
|
+
sleep,
|
|
17
|
+
formatTime,
|
|
18
|
+
formatBytes,
|
|
19
|
+
parseCommand,
|
|
20
|
+
isUrl,
|
|
21
|
+
extractUrls,
|
|
22
|
+
randomString,
|
|
23
|
+
randomNumber,
|
|
24
|
+
pickRandom,
|
|
25
|
+
chunk
|
|
26
|
+
} from './helpers/index.js';
|
|
27
|
+
|
|
28
|
+
// Default export
|
|
29
|
+
import { Client } from './client/Client.js';
|
|
30
|
+
export default Client;
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@roidev/kachina-md",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "WhatsApp Bot Framework - Simple, Fast, and Modular",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "node build.js",
|
|
9
|
+
"test": "node examples/basic-bot.js",
|
|
10
|
+
"prepublishOnly": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"whatsapp",
|
|
14
|
+
"bot",
|
|
15
|
+
"baileys",
|
|
16
|
+
"wa-bot",
|
|
17
|
+
"whatsapp-bot",
|
|
18
|
+
"framework",
|
|
19
|
+
"kachina"
|
|
20
|
+
],
|
|
21
|
+
"author": "Roynaldi",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/your-username/kachina-core.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/your-username/kachina-core/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/your-username/kachina-core#readme",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@hapi/boom": "^10.0.1",
|
|
33
|
+
"axios": "^1.6.0",
|
|
34
|
+
"baileys": "npm:@whiskeysockets/baileys@latest",
|
|
35
|
+
"chalk": "^5.3.0",
|
|
36
|
+
"file-type": "^18.7.0",
|
|
37
|
+
"fs-extra": "^11.2.0",
|
|
38
|
+
"lowdb": "^7.0.1",
|
|
39
|
+
"node-cache": "^5.1.2",
|
|
40
|
+
"pino": "^8.16.0",
|
|
41
|
+
"qrcode-terminal": "^0.12.0",
|
|
42
|
+
"sharp": "^0.33.0",
|
|
43
|
+
"wa-sticker-formatter": "^4.4.4"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"gradient-string": "^2.0.2"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=16.0.0"
|
|
50
|
+
},
|
|
51
|
+
"exports": {
|
|
52
|
+
".": {
|
|
53
|
+
"import": "./lib/index.js"
|
|
54
|
+
},
|
|
55
|
+
"./plugins": {
|
|
56
|
+
"import": "./lib/plugins/index.js"
|
|
57
|
+
},
|
|
58
|
+
"./helpers": {
|
|
59
|
+
"import": "./lib/helpers/index.js"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"files": [
|
|
63
|
+
"lib/**/*",
|
|
64
|
+
"README.md",
|
|
65
|
+
"LICENSE"
|
|
66
|
+
]
|
|
67
|
+
}
|