@japofc/baileys 2.1.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/NOTICE.md +111 -0
- package/README.md +1254 -0
- package/WAProto/index.d.ts +9 -0
- package/WAProto/index.js +142276 -0
- package/engine-requirements.js +13 -0
- package/lib/Builders/A2UI.d.ts +242 -0
- package/lib/Builders/A2UI.js +308 -0
- package/lib/Builders/AIRich.d.ts +105 -0
- package/lib/Builders/AIRich.js +2286 -0
- package/lib/Builders/Button.d.ts +103 -0
- package/lib/Builders/Button.js +883 -0
- package/lib/Builders/ButtonV2.d.ts +28 -0
- package/lib/Builders/ButtonV2.js +144 -0
- package/lib/Builders/ButtonV3.d.ts +25 -0
- package/lib/Builders/ButtonV3.js +184 -0
- package/lib/Builders/Carousel.d.ts +22 -0
- package/lib/Builders/Carousel.js +111 -0
- package/lib/Builders/JapBaileys.d.ts +34 -0
- package/lib/Builders/JapBaileys.js +108 -0
- package/lib/Builders/Poll.d.ts +25 -0
- package/lib/Builders/Poll.js +128 -0
- package/lib/Builders/index.d.ts +17 -0
- package/lib/Builders/index.js +11 -0
- package/lib/Builders/shared.d.ts +67 -0
- package/lib/Builders/shared.js +652 -0
- package/lib/Defaults/index.d.ts +154 -0
- package/lib/Defaults/index.js +178 -0
- package/lib/Framework/Bot.d.ts +61 -0
- package/lib/Framework/Bot.js +248 -0
- package/lib/Framework/Context.d.ts +21 -0
- package/lib/Framework/Context.js +89 -0
- package/lib/Framework/MediaManager.d.ts +17 -0
- package/lib/Framework/MediaManager.js +151 -0
- package/lib/Framework/SessionManager.d.ts +13 -0
- package/lib/Framework/SessionManager.js +33 -0
- package/lib/Framework/StatsManager.d.ts +26 -0
- package/lib/Framework/StatsManager.js +119 -0
- package/lib/Framework/Store/SQLiteStore.d.ts +11 -0
- package/lib/Framework/Store/SQLiteStore.js +73 -0
- package/lib/Framework/index.d.ts +9 -0
- package/lib/Framework/index.js +10 -0
- package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
- package/lib/Signal/Group/ciphertext-message.js +11 -0
- package/lib/Signal/Group/group-session-builder.d.ts +7 -0
- package/lib/Signal/Group/group-session-builder.js +29 -0
- package/lib/Signal/Group/group_cipher.d.ts +10 -0
- package/lib/Signal/Group/group_cipher.js +81 -0
- package/lib/Signal/Group/index.d.ts +11 -0
- package/lib/Signal/Group/index.js +11 -0
- package/lib/Signal/Group/keyhelper.d.ts +6 -0
- package/lib/Signal/Group/keyhelper.js +17 -0
- package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
- package/lib/Signal/Group/sender-chain-key.js +25 -0
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +62 -0
- package/lib/Signal/Group/sender-key-message.d.ts +18 -0
- package/lib/Signal/Group/sender-key-message.js +65 -0
- package/lib/Signal/Group/sender-key-name.d.ts +11 -0
- package/lib/Signal/Group/sender-key-name.js +47 -0
- package/lib/Signal/Group/sender-key-record.d.ts +12 -0
- package/lib/Signal/Group/sender-key-record.js +40 -0
- package/lib/Signal/Group/sender-key-state.d.ts +16 -0
- package/lib/Signal/Group/sender-key-state.js +83 -0
- package/lib/Signal/Group/sender-message-key.d.ts +11 -0
- package/lib/Signal/Group/sender-message-key.js +25 -0
- package/lib/Signal/libsignal.d.ts +54 -0
- package/lib/Signal/libsignal.js +430 -0
- package/lib/Signal/lid-mapping.d.ts +20 -0
- package/lib/Signal/lid-mapping.js +276 -0
- package/lib/Socket/Client/index.d.ts +2 -0
- package/lib/Socket/Client/index.js +2 -0
- package/lib/Socket/Client/types.d.ts +5 -0
- package/lib/Socket/Client/types.js +10 -0
- package/lib/Socket/Client/websocket.d.ts +12 -0
- package/lib/Socket/Client/websocket.js +53 -0
- package/lib/Socket/business.d.ts +395 -0
- package/lib/Socket/business.js +379 -0
- package/lib/Socket/chats.d.ts +136 -0
- package/lib/Socket/chats.js +1327 -0
- package/lib/Socket/communities.d.ts +562 -0
- package/lib/Socket/communities.js +439 -0
- package/lib/Socket/dugong.d.ts +117 -0
- package/lib/Socket/dugong.js +798 -0
- package/lib/Socket/groups.d.ts +285 -0
- package/lib/Socket/groups.js +354 -0
- package/lib/Socket/index.d.ts +585 -0
- package/lib/Socket/index.js +52 -0
- package/lib/Socket/messages-recv.d.ts +333 -0
- package/lib/Socket/messages-recv.js +1781 -0
- package/lib/Socket/messages-send.d.ts +353 -0
- package/lib/Socket/messages-send.js +1524 -0
- package/lib/Socket/mex.d.ts +1 -0
- package/lib/Socket/mex.js +41 -0
- package/lib/Socket/newsletter.d.ts +286 -0
- package/lib/Socket/newsletter.js +364 -0
- package/lib/Socket/socket.d.ts +60 -0
- package/lib/Socket/socket.js +1012 -0
- package/lib/Socket/username.d.ts +82 -0
- package/lib/Socket/username.js +159 -0
- package/lib/Store/index.d.ts +3 -0
- package/lib/Store/index.js +3 -0
- package/lib/Store/make-in-memory-store.d.ts +62 -0
- package/lib/Store/make-in-memory-store.js +428 -0
- package/lib/Store/make-ordered-dictionary.d.ts +12 -0
- package/lib/Store/make-ordered-dictionary.js +78 -0
- package/lib/Store/object-repository.d.ts +10 -0
- package/lib/Store/object-repository.js +23 -0
- package/lib/Types/Auth.d.ts +117 -0
- package/lib/Types/Auth.js +1 -0
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Call.d.ts +15 -0
- package/lib/Types/Call.js +1 -0
- package/lib/Types/Chat.d.ts +124 -0
- package/lib/Types/Chat.js +7 -0
- package/lib/Types/Contact.d.ts +26 -0
- package/lib/Types/Contact.js +1 -0
- package/lib/Types/Events.d.ts +256 -0
- package/lib/Types/Events.js +1 -0
- package/lib/Types/GroupMetadata.d.ts +71 -0
- package/lib/Types/GroupMetadata.js +1 -0
- package/lib/Types/Label.d.ts +5 -0
- package/lib/Types/Label.js +24 -0
- package/lib/Types/LabelAssociation.d.ts +6 -0
- package/lib/Types/LabelAssociation.js +6 -0
- package/lib/Types/Message.d.ts +62 -0
- package/lib/Types/Message.js +17 -0
- package/lib/Types/Mex.d.ts +2 -0
- package/lib/Types/Mex.js +38 -0
- package/lib/Types/Product.d.ts +79 -0
- package/lib/Types/Product.js +1 -0
- package/lib/Types/RichType.d.ts +2 -0
- package/lib/Types/RichType.js +22 -0
- package/lib/Types/Signal.d.ts +87 -0
- package/lib/Types/Signal.js +1 -0
- package/lib/Types/Socket.d.ts +138 -0
- package/lib/Types/Socket.js +1 -0
- package/lib/Types/State.d.ts +8 -0
- package/lib/Types/State.js +55 -0
- package/lib/Types/USync.d.ts +26 -0
- package/lib/Types/index.d.ts +68 -0
- package/lib/Types/index.js +27 -0
- package/lib/Utils/MessageBuilder.d.ts +2 -0
- package/lib/Utils/MessageBuilder.js +2 -0
- package/lib/Utils/PersistentStore.d.ts +60 -0
- package/lib/Utils/PersistentStore.js +592 -0
- package/lib/Utils/anti-delete.d.ts +74 -0
- package/lib/Utils/anti-delete.js +221 -0
- package/lib/Utils/auth-secure.d.ts +86 -0
- package/lib/Utils/auth-secure.js +764 -0
- package/lib/Utils/auth-utils.d.ts +57 -0
- package/lib/Utils/auth-utils.js +306 -0
- package/lib/Utils/auto-reply.d.ts +47 -0
- package/lib/Utils/auto-reply.js +157 -0
- package/lib/Utils/baileys-event-stream.d.ts +8 -0
- package/lib/Utils/baileys-event-stream.js +62 -0
- package/lib/Utils/browser-utils.d.ts +8 -0
- package/lib/Utils/browser-utils.js +27 -0
- package/lib/Utils/business.d.ts +49 -0
- package/lib/Utils/business.js +239 -0
- package/lib/Utils/button-helper-utils.d.ts +53 -0
- package/lib/Utils/button-helper-utils.js +312 -0
- package/lib/Utils/button-sender.d.ts +54 -0
- package/lib/Utils/button-sender.js +822 -0
- package/lib/Utils/chat-control.d.ts +159 -0
- package/lib/Utils/chat-control.js +230 -0
- package/lib/Utils/chat-history-helpers.d.ts +21 -0
- package/lib/Utils/chat-history-helpers.js +70 -0
- package/lib/Utils/chat-utils.d.ts +407 -0
- package/lib/Utils/chat-utils.js +885 -0
- package/lib/Utils/companion-reg-client-utils.d.ts +4 -0
- package/lib/Utils/companion-reg-client-utils.js +39 -0
- package/lib/Utils/crypto.d.ts +41 -0
- package/lib/Utils/crypto.js +147 -0
- package/lib/Utils/decode-wa-message.d.ts +83 -0
- package/lib/Utils/decode-wa-message.js +316 -0
- package/lib/Utils/event-buffer.d.ts +12 -0
- package/lib/Utils/event-buffer.js +635 -0
- package/lib/Utils/generics.d.ts +69 -0
- package/lib/Utils/generics.js +438 -0
- package/lib/Utils/history-share.d.ts +11 -0
- package/lib/Utils/history-share.js +70 -0
- package/lib/Utils/history.d.ts +90 -0
- package/lib/Utils/history.js +146 -0
- package/lib/Utils/humanizer.d.ts +12 -0
- package/lib/Utils/humanizer.js +73 -0
- package/lib/Utils/identity-change-handler.d.ts +13 -0
- package/lib/Utils/identity-change-handler.js +49 -0
- package/lib/Utils/index.d.ts +57 -0
- package/lib/Utils/index.js +56 -0
- package/lib/Utils/jid-tools.d.ts +6 -0
- package/lib/Utils/jid-tools.js +77 -0
- package/lib/Utils/link-preview.d.ts +12 -0
- package/lib/Utils/link-preview.js +84 -0
- package/lib/Utils/logger.d.ts +4 -0
- package/lib/Utils/logger.js +2 -0
- package/lib/Utils/lt-hash.d.ts +12 -0
- package/lib/Utils/lt-hash.js +26 -0
- package/lib/Utils/make-mutex.d.ts +6 -0
- package/lib/Utils/make-mutex.js +32 -0
- package/lib/Utils/media-messages.d.ts +18 -0
- package/lib/Utils/media-messages.js +70 -0
- package/lib/Utils/media-set.d.ts +13 -0
- package/lib/Utils/media-set.js +171 -0
- package/lib/Utils/message-kind.d.ts +32 -0
- package/lib/Utils/message-kind.js +136 -0
- package/lib/Utils/message-retry-manager.d.ts +79 -0
- package/lib/Utils/message-retry-manager.js +264 -0
- package/lib/Utils/message-search.d.ts +44 -0
- package/lib/Utils/message-search.js +188 -0
- package/lib/Utils/messages-media.d.ts +135 -0
- package/lib/Utils/messages-media.js +868 -0
- package/lib/Utils/messages.d.ts +44 -0
- package/lib/Utils/messages.js +2326 -0
- package/lib/Utils/meta-ai.d.ts +13 -0
- package/lib/Utils/meta-ai.js +74 -0
- package/lib/Utils/mini-app.d.ts +35 -0
- package/lib/Utils/mini-app.js +213 -0
- package/lib/Utils/noise-handler.d.ts +20 -0
- package/lib/Utils/noise-handler.js +200 -0
- package/lib/Utils/offline-node-processor.d.ts +9 -0
- package/lib/Utils/offline-node-processor.js +39 -0
- package/lib/Utils/past-participants.d.ts +14 -0
- package/lib/Utils/past-participants.js +40 -0
- package/lib/Utils/pre-key-manager.d.ts +25 -0
- package/lib/Utils/pre-key-manager.js +105 -0
- package/lib/Utils/process-message.d.ts +82 -0
- package/lib/Utils/process-message.js +808 -0
- package/lib/Utils/qr-render.d.ts +59 -0
- package/lib/Utils/qr-render.js +179 -0
- package/lib/Utils/qrcodegen.d.ts +79 -0
- package/lib/Utils/qrcodegen.js +848 -0
- package/lib/Utils/reporting-utils.d.ts +12 -0
- package/lib/Utils/reporting-utils.js +257 -0
- package/lib/Utils/rich-message-utils.d.ts +48 -0
- package/lib/Utils/rich-message-utils.js +444 -0
- package/lib/Utils/router.d.ts +37 -0
- package/lib/Utils/router.js +165 -0
- package/lib/Utils/scheduled-posts.d.ts +30 -0
- package/lib/Utils/scheduled-posts.js +110 -0
- package/lib/Utils/scheduling.d.ts +42 -0
- package/lib/Utils/scheduling.js +139 -0
- package/lib/Utils/signal.d.ts +82 -0
- package/lib/Utils/signal.js +200 -0
- package/lib/Utils/stanza-ack.d.ts +16 -0
- package/lib/Utils/stanza-ack.js +37 -0
- package/lib/Utils/status.d.ts +50 -0
- package/lib/Utils/status.js +107 -0
- package/lib/Utils/stickerpack.d.ts +51 -0
- package/lib/Utils/stickerpack.js +274 -0
- package/lib/Utils/sync-action-utils.d.ts +2 -0
- package/lib/Utils/sync-action-utils.js +48 -0
- package/lib/Utils/tag.d.ts +12 -0
- package/lib/Utils/tag.js +44 -0
- package/lib/Utils/tc-token-utils.d.ts +29 -0
- package/lib/Utils/tc-token-utils.js +162 -0
- package/lib/Utils/templates.d.ts +76 -0
- package/lib/Utils/templates.js +150 -0
- package/lib/Utils/transcribe.d.ts +12 -0
- package/lib/Utils/transcribe.js +107 -0
- package/lib/Utils/use-cache-manager-auth-state.d.ts +13 -0
- package/lib/Utils/use-cache-manager-auth-state.js +81 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +10 -0
- package/lib/Utils/use-multi-file-auth-state.js +166 -0
- package/lib/Utils/use-single-file-auth-state.d.ts +10 -0
- package/lib/Utils/use-single-file-auth-state.js +113 -0
- package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
- package/lib/Utils/use-sqlite-auth-state.js +169 -0
- package/lib/Utils/validate-connection.d.ts +42 -0
- package/lib/Utils/validate-connection.js +198 -0
- package/lib/Utils/vcard.d.ts +58 -0
- package/lib/Utils/vcard.js +104 -0
- package/lib/Utils/voice-note.d.ts +15 -0
- package/lib/Utils/voice-note.js +63 -0
- package/lib/VoIP/audio-feeder.d.ts +18 -0
- package/lib/VoIP/audio-feeder.js +160 -0
- package/lib/VoIP/call-recorder.d.ts +13 -0
- package/lib/VoIP/call-recorder.js +73 -0
- package/lib/VoIP/index.d.ts +86 -0
- package/lib/VoIP/index.js +611 -0
- package/lib/VoIP/relay-transport.d.ts +43 -0
- package/lib/VoIP/relay-transport.js +563 -0
- package/lib/VoIP/signaling.d.ts +26 -0
- package/lib/VoIP/signaling.js +662 -0
- package/lib/VoIP/types.d.ts +69 -0
- package/lib/VoIP/types.js +17 -0
- package/lib/VoIP/wasm-engine.d.ts +120 -0
- package/lib/VoIP/wasm-engine.js +1358 -0
- package/lib/VoIP/worker-bootstrap.d.ts +4 -0
- package/lib/VoIP/worker-bootstrap.js +1046 -0
- package/lib/WABinary/constants.d.ts +61 -0
- package/lib/WABinary/constants.js +1466 -0
- package/lib/WABinary/decode.d.ts +9 -0
- package/lib/WABinary/decode.js +261 -0
- package/lib/WABinary/encode.d.ts +2 -0
- package/lib/WABinary/encode.js +219 -0
- package/lib/WABinary/generic-utils.d.ts +74 -0
- package/lib/WABinary/generic-utils.js +276 -0
- package/lib/WABinary/index.d.ts +5 -0
- package/lib/WABinary/index.js +5 -0
- package/lib/WABinary/jid-utils.d.ts +28 -0
- package/lib/WABinary/jid-utils.js +95 -0
- package/lib/WABinary/types.d.ts +19 -0
- package/lib/WABinary/types.js +1 -0
- package/lib/WAM/BinaryInfo.d.ts +7 -0
- package/lib/WAM/BinaryInfo.js +9 -0
- package/lib/WAM/constants.d.ts +34926 -0
- package/lib/WAM/constants.js +22852 -0
- package/lib/WAM/encode.d.ts +1 -0
- package/lib/WAM/encode.js +149 -0
- package/lib/WAM/index.d.ts +3 -0
- package/lib/WAM/index.js +3 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +36 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +51 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +29 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +62 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +9 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +24 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +38 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +14 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
- package/lib/WAUSync/Protocols/index.d.ts +7 -0
- package/lib/WAUSync/Protocols/index.js +7 -0
- package/lib/WAUSync/USyncQuery.d.ts +20 -0
- package/lib/WAUSync/USyncQuery.js +121 -0
- package/lib/WAUSync/USyncUser.d.ts +16 -0
- package/lib/WAUSync/USyncUser.js +30 -0
- package/lib/WAUSync/index.d.ts +3 -0
- package/lib/WAUSync/index.js +3 -0
- package/lib/assets/wasm/loader.d.ts +5 -0
- package/lib/assets/wasm/loader.js +5 -0
- package/lib/assets/wasm/whatsapp.wasm +0 -0
- package/lib/assets/wasm/worker-modules.d.ts +5 -0
- package/lib/assets/wasm/worker-modules.js +273 -0
- package/lib/index.d.ts +18 -0
- package/lib/index.js +23 -0
- package/package.json +180 -0
- package/postinstall-banner.js +82 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { MediaManager } from './MediaManager.js';
|
|
2
|
+
|
|
3
|
+
// JAP@Framework --- message context helper: wraps a WAMessage with reply,
|
|
4
|
+
// react, session, and media helpers so command handlers don't have to touch
|
|
5
|
+
// the raw socket API.
|
|
6
|
+
//
|
|
7
|
+
// Kept from upstream's fix pass:
|
|
8
|
+
// - text getter also reads imageMessage/videoMessage/documentMessage
|
|
9
|
+
// captions, so a command sent as an image caption still matches
|
|
10
|
+
// - reply()/react()/replySticker()/replyVoiceNote() throw when remoteJid is
|
|
11
|
+
// missing instead of silently no-op'ing, so a handler can't believe a
|
|
12
|
+
// reply went out when it never did
|
|
13
|
+
export class Context {
|
|
14
|
+
constructor(bot, message) {
|
|
15
|
+
this.bot = bot;
|
|
16
|
+
this.message = message;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get remoteJid() {
|
|
20
|
+
return this.message.key.remoteJid;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Text content, including image/video/document captions so caption-only commands still match. */
|
|
24
|
+
get text() {
|
|
25
|
+
return (this.message.message?.conversation ||
|
|
26
|
+
this.message.message?.extendedTextMessage?.text ||
|
|
27
|
+
this.message.message?.imageMessage?.caption ||
|
|
28
|
+
this.message.message?.videoMessage?.caption ||
|
|
29
|
+
this.message.message?.documentMessage?.caption ||
|
|
30
|
+
undefined);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get quoted() {
|
|
34
|
+
return this.message.message?.extendedTextMessage?.contextInfo?.quotedMessage;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
session() {
|
|
38
|
+
return this.bot.sessions?.get(this.remoteJid || '');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setSession(data) {
|
|
42
|
+
this.bot.sessions?.set(this.remoteJid || '', data);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
updateSession(updater) {
|
|
46
|
+
this.bot.sessions?.update(this.remoteJid || '', updater);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
clearSession() {
|
|
50
|
+
this.bot.sessions?.delete(this.remoteJid || '');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async reply(content, options) {
|
|
54
|
+
if (!this.remoteJid)
|
|
55
|
+
throw new Error('Cannot reply: remoteJid is undefined');
|
|
56
|
+
await this.bot.sendMessage(this.remoteJid, {
|
|
57
|
+
...content
|
|
58
|
+
}, {
|
|
59
|
+
quoted: this.message,
|
|
60
|
+
...options
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async react(emoji) {
|
|
65
|
+
if (!this.remoteJid)
|
|
66
|
+
throw new Error('Cannot react: remoteJid is undefined');
|
|
67
|
+
await this.bot.sendMessage(this.remoteJid, {
|
|
68
|
+
react: { text: emoji, key: this.message.key }
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async replySticker(inputPathOrBuffer, metadata) {
|
|
73
|
+
if (!this.remoteJid)
|
|
74
|
+
throw new Error('Cannot reply: remoteJid is undefined');
|
|
75
|
+
const buffer = await MediaManager.convertToSticker(inputPathOrBuffer, metadata);
|
|
76
|
+
await this.reply({ sticker: buffer });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async replyVoiceNote(inputPathOrBuffer) {
|
|
80
|
+
if (!this.remoteJid)
|
|
81
|
+
throw new Error('Cannot reply: remoteJid is undefined');
|
|
82
|
+
const buffer = await MediaManager.convertToVoiceNote(inputPathOrBuffer);
|
|
83
|
+
await this.reply({
|
|
84
|
+
audio: buffer,
|
|
85
|
+
mimetype: 'audio/ogg; codecs=opus',
|
|
86
|
+
ptt: true
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface StickerMetadata {
|
|
2
|
+
packname?: string;
|
|
3
|
+
author?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** Image/video → WebP sticker and audio → OGG Opus voice-note conversion. */
|
|
7
|
+
export class MediaManager {
|
|
8
|
+
/** Generate a temp file path with a given extension. */
|
|
9
|
+
static getTempFile(ext: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Convert image/video to a WebP sticker buffer.
|
|
12
|
+
* packname/author EXIF needs the optional `node-webpmux` peer dep.
|
|
13
|
+
*/
|
|
14
|
+
static convertToSticker(inputPathOrBuffer: string | Buffer, metadata?: StickerMetadata): Promise<Buffer>;
|
|
15
|
+
/** Convert audio to OGG Opus voice-note format (mono, 16kHz, VOIP mode). */
|
|
16
|
+
static convertToVoiceNote(inputPathOrBuffer: string | Buffer): Promise<Buffer>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { randomBytes } from 'crypto';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
|
|
6
|
+
// JAP@Framework --- media conversion helpers: image/video → WebP stickers
|
|
7
|
+
// (with optional packname/author EXIF), audio → OGG Opus voice notes.
|
|
8
|
+
//
|
|
9
|
+
// JAP@Fix vs upstream: original hard-`require()`'d `node-webpmux` and
|
|
10
|
+
// pulled in `ffmpeg-static` (bundles a per-platform ffmpeg binary) alongside
|
|
11
|
+
// `fluent-ffmpeg`. `fluent-ffmpeg` is already an optional peer dep in this
|
|
12
|
+
// fork, lazy-loaded via the getFfmpeg() pattern established in
|
|
13
|
+
// Utils/MessageBuilder.js (15-08-26) — reused verbatim here instead of
|
|
14
|
+
// re-introducing a static import or a second ffmpeg-binary dependency.
|
|
15
|
+
// `node-webpmux` is lazy-loaded the same way, and only when packname/author
|
|
16
|
+
// metadata is actually requested.
|
|
17
|
+
let _ffmpeg;
|
|
18
|
+
const getFfmpeg = async () => {
|
|
19
|
+
if (_ffmpeg === undefined) {
|
|
20
|
+
_ffmpeg = await import('fluent-ffmpeg').then((m) => m.default ?? m).catch(() => null);
|
|
21
|
+
}
|
|
22
|
+
if (!_ffmpeg)
|
|
23
|
+
throw new Error('fluent-ffmpeg is required for sticker/voice-note conversion. Install it with: npm i fluent-ffmpeg');
|
|
24
|
+
return _ffmpeg;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
let _webpmux;
|
|
28
|
+
const getWebpmux = async () => {
|
|
29
|
+
if (_webpmux === undefined) {
|
|
30
|
+
_webpmux = await import('node-webpmux').then((m) => m.default ?? m).catch(() => null);
|
|
31
|
+
}
|
|
32
|
+
if (!_webpmux)
|
|
33
|
+
throw new Error('node-webpmux is required for sticker packname/author metadata. Install it with: npm i node-webpmux (conversion without metadata does not need this package)');
|
|
34
|
+
return _webpmux;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export class MediaManager {
|
|
38
|
+
/** Generate a temp file path with a given extension */
|
|
39
|
+
static getTempFile(ext) {
|
|
40
|
+
return path.join(os.tmpdir(), `baileys-fw-${randomBytes(8).toString('hex')}.${ext}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Convert image or video to a WebP sticker buffer.
|
|
45
|
+
* Applies packname/author EXIF metadata when provided (requires the
|
|
46
|
+
* optional `node-webpmux` peer dependency — only loaded if metadata is given).
|
|
47
|
+
*/
|
|
48
|
+
static async convertToSticker(inputPathOrBuffer, metadata) {
|
|
49
|
+
const ffmpegLib = await getFfmpeg();
|
|
50
|
+
const tempInput = MediaManager.getTempFile('in');
|
|
51
|
+
const tempOutput = MediaManager.getTempFile('webp');
|
|
52
|
+
try {
|
|
53
|
+
if (Buffer.isBuffer(inputPathOrBuffer)) {
|
|
54
|
+
await fs.promises.writeFile(tempInput, inputPathOrBuffer);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
await fs.promises.copyFile(inputPathOrBuffer, tempInput);
|
|
58
|
+
}
|
|
59
|
+
await new Promise((resolve, reject) => {
|
|
60
|
+
ffmpegLib(tempInput)
|
|
61
|
+
.outputOptions([
|
|
62
|
+
'-vcodec', 'libwebp',
|
|
63
|
+
'-vf', 'scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=white@0',
|
|
64
|
+
'-loop', '0',
|
|
65
|
+
'-preset', 'default',
|
|
66
|
+
'-an', '-vsync', '0',
|
|
67
|
+
'-t', '00:00:05'
|
|
68
|
+
])
|
|
69
|
+
.output(tempOutput)
|
|
70
|
+
.on('end', () => resolve())
|
|
71
|
+
.on('error', (err) => reject(err))
|
|
72
|
+
.run();
|
|
73
|
+
});
|
|
74
|
+
const webpBuffer = await fs.promises.readFile(tempOutput);
|
|
75
|
+
if (metadata?.packname || metadata?.author) {
|
|
76
|
+
// EXIF header: fixed 22-byte TIFF/IFD preamble (magic + one IFD
|
|
77
|
+
// entry pointing at the WhatsApp tag 0x0741) followed by a
|
|
78
|
+
// little-endian payload length and a little-endian offset to
|
|
79
|
+
// where the payload begins (always 22, the header's own size).
|
|
80
|
+
const exifJson = JSON.stringify({
|
|
81
|
+
'sticker-pack-id': `com.jap.sticker.${randomBytes(4).toString('hex')}`,
|
|
82
|
+
'sticker-pack-name': metadata.packname || '',
|
|
83
|
+
'sticker-pack-publisher': metadata.author || '',
|
|
84
|
+
emojis: ['🤖']
|
|
85
|
+
});
|
|
86
|
+
const exifBytes = Buffer.from(exifJson, 'utf8');
|
|
87
|
+
const exifHeader = Buffer.from([
|
|
88
|
+
0x49, 0x49, 0x2a, 0x00, // TIFF byte order (little-endian) + magic number
|
|
89
|
+
0x08, 0x00, 0x00, 0x00, // offset to first IFD
|
|
90
|
+
0x01, 0x00, // number of IFD entries
|
|
91
|
+
0x41, 0x57, 0x07, 0x00, // tag 0x0741 (WhatsApp), type 0x0007 (undefined)
|
|
92
|
+
0x00, 0x00, 0x00, 0x00, // payload length placeholder — filled below
|
|
93
|
+
0x16, 0x00, 0x00, 0x00 // offset to payload data (fixed: 22 = header size)
|
|
94
|
+
]);
|
|
95
|
+
exifHeader.writeUInt32LE(exifBytes.length, 14);
|
|
96
|
+
const fullExif = Buffer.concat([exifHeader, exifBytes]);
|
|
97
|
+
const webpmux = await getWebpmux();
|
|
98
|
+
const img = new webpmux.Image();
|
|
99
|
+
await img.load(webpBuffer);
|
|
100
|
+
img.exif = fullExif;
|
|
101
|
+
return await img.save(null);
|
|
102
|
+
}
|
|
103
|
+
return webpBuffer;
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
await fs.promises.unlink(tempInput).catch(() => { });
|
|
107
|
+
await fs.promises.unlink(tempOutput).catch(() => { });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Convert audio to OGG Opus voice note format.
|
|
113
|
+
* Mono, 16kHz, VOIP application mode — required by WA for PTT playback.
|
|
114
|
+
*/
|
|
115
|
+
static async convertToVoiceNote(inputPathOrBuffer) {
|
|
116
|
+
const ffmpegLib = await getFfmpeg();
|
|
117
|
+
const tempInput = MediaManager.getTempFile('in');
|
|
118
|
+
const tempOutput = MediaManager.getTempFile('ogg');
|
|
119
|
+
try {
|
|
120
|
+
if (Buffer.isBuffer(inputPathOrBuffer)) {
|
|
121
|
+
await fs.promises.writeFile(tempInput, inputPathOrBuffer);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
await fs.promises.copyFile(inputPathOrBuffer, tempInput);
|
|
125
|
+
}
|
|
126
|
+
await new Promise((resolve, reject) => {
|
|
127
|
+
ffmpegLib(tempInput)
|
|
128
|
+
.inputOptions(['-y'])
|
|
129
|
+
.outputOptions([
|
|
130
|
+
'-c:a', 'libopus',
|
|
131
|
+
'-ac', '1', // mono channel (required by WA)
|
|
132
|
+
'-ar', '16000', // 16kHz sample rate
|
|
133
|
+
'-application', 'voip',
|
|
134
|
+
'-b:a', '32k',
|
|
135
|
+
'-compression_level', '10',
|
|
136
|
+
'-vbr', 'on'
|
|
137
|
+
])
|
|
138
|
+
.format('ogg')
|
|
139
|
+
.output(tempOutput)
|
|
140
|
+
.on('end', () => resolve())
|
|
141
|
+
.on('error', (err) => reject(err))
|
|
142
|
+
.run();
|
|
143
|
+
});
|
|
144
|
+
return await fs.promises.readFile(tempOutput);
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await fs.promises.unlink(tempInput).catch(() => { });
|
|
148
|
+
await fs.promises.unlink(tempOutput).catch(() => { });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SQLiteStore } from './Store/SQLiteStore.js';
|
|
2
|
+
|
|
3
|
+
/** Per-JID session CRUD backed by a SQLiteStore. */
|
|
4
|
+
export class SessionManager {
|
|
5
|
+
constructor(store: SQLiteStore);
|
|
6
|
+
store: SQLiteStore;
|
|
7
|
+
key(jid: string): string;
|
|
8
|
+
get(jid: string): any;
|
|
9
|
+
set(jid: string, data: any): void;
|
|
10
|
+
update(jid: string, updater: (prev: any) => any): void;
|
|
11
|
+
delete(jid: string): void;
|
|
12
|
+
has(jid: string): boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// JAP@Framework --- per-JID session CRUD backed by SQLiteStore. Unchanged logic
|
|
2
|
+
// from upstream; only the SQLiteStore instance it wraps is now created via
|
|
3
|
+
// an async factory (see Store/SQLiteStore.js).
|
|
4
|
+
export class SessionManager {
|
|
5
|
+
constructor(store) {
|
|
6
|
+
this.store = store;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
key(jid) {
|
|
10
|
+
return `session_${jid}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get(jid) {
|
|
14
|
+
return this.store.get(this.key(jid));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set(jid, data) {
|
|
18
|
+
this.store.set(this.key(jid), data);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
update(jid, updater) {
|
|
22
|
+
const prev = this.get(jid);
|
|
23
|
+
this.set(jid, updater(prev));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
delete(jid) {
|
|
27
|
+
this.store.del(this.key(jid));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
has(jid) {
|
|
31
|
+
return this.get(jid) !== undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface StatRow {
|
|
2
|
+
jid: string;
|
|
3
|
+
count: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface GhostEntry {
|
|
7
|
+
jid: string;
|
|
8
|
+
isTotalGhost: boolean;
|
|
9
|
+
lastActive?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Group activity tracking: message/sticker counts, leaderboards, ghost detection. */
|
|
13
|
+
export class StatsManager {
|
|
14
|
+
constructor(db: any, groupMetaFn: (groupJid: string) => Promise<any>);
|
|
15
|
+
/** Async factory (better-sqlite3 is lazy-loaded). Replaces `new StatsManager(dbPath, …)`. */
|
|
16
|
+
static create(dbPath: string, groupMetaFn: (groupJid: string) => Promise<any>): Promise<StatsManager>;
|
|
17
|
+
/** Record a message observation for stats. */
|
|
18
|
+
observeMessage(groupJid: string, userJid: string, isSticker?: boolean): void;
|
|
19
|
+
/** Top message senders for a group. */
|
|
20
|
+
getTopUsers(groupJid: string, limit?: number): StatRow[];
|
|
21
|
+
/** Top sticker senders for a group. */
|
|
22
|
+
getTopStickers(groupJid: string, limit?: number): StatRow[];
|
|
23
|
+
/** Detect inactive members ("ghosts"). Throws Boom(503) when disconnected. */
|
|
24
|
+
getGhosts(groupJid: string, socketConnected: boolean, inactiveDays?: number): Promise<GhostEntry[]>;
|
|
25
|
+
close(): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { jidNormalizedUser } from '../WABinary/index.js';
|
|
3
|
+
|
|
4
|
+
// JAP@Framework --- group activity tracking: message counts, sticker counts,
|
|
5
|
+
// leaderboards, ghost (inactive member) detection.
|
|
6
|
+
//
|
|
7
|
+
// Kept from upstream's P0-P3 pass:
|
|
8
|
+
// - all participant JIDs normalized via jidNormalizedUser() before storing/
|
|
9
|
+
// querying, so PN/LID/device (:0, :42) variants resolve to the same row
|
|
10
|
+
// - getTopUsers/getTopStickers guard limit to a positive integer
|
|
11
|
+
// - getGhosts throws Boom(503) instead of a bare Error when the socket
|
|
12
|
+
// isn't connected, so callers can branch on statusCode
|
|
13
|
+
//
|
|
14
|
+
// JAP@Fix vs upstream: same issue as SQLiteStore — `better-sqlite3` was a
|
|
15
|
+
// hard top-level import. Reused the lazy loadBetterSqlite3() pattern and
|
|
16
|
+
// moved construction behind an async `StatsManager.create()` factory.
|
|
17
|
+
async function loadBetterSqlite3() {
|
|
18
|
+
try {
|
|
19
|
+
const mod = (await import('better-sqlite3'));
|
|
20
|
+
return mod.default ?? mod;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
const helpful = new Error('`better-sqlite3` is required for the Framework StatsManager. Install it as a peer dependency: `npm install better-sqlite3` (or `yarn add better-sqlite3`).');
|
|
24
|
+
helpful.cause = err;
|
|
25
|
+
throw helpful;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class StatsManager {
|
|
30
|
+
constructor(db, groupMetaFn) {
|
|
31
|
+
this.db = db;
|
|
32
|
+
this.groupMetaFn = groupMetaFn;
|
|
33
|
+
this.db.exec(`
|
|
34
|
+
CREATE TABLE IF NOT EXISTS group_stats (
|
|
35
|
+
group_jid TEXT NOT NULL,
|
|
36
|
+
user_jid TEXT NOT NULL,
|
|
37
|
+
msg_count INTEGER NOT NULL DEFAULT 0,
|
|
38
|
+
sticker_count INTEGER NOT NULL DEFAULT 0,
|
|
39
|
+
last_active INTEGER NOT NULL,
|
|
40
|
+
PRIMARY KEY (group_jid, user_jid)
|
|
41
|
+
)
|
|
42
|
+
`);
|
|
43
|
+
this.insertStmt = this.db.prepare(`
|
|
44
|
+
INSERT INTO group_stats (group_jid, user_jid, msg_count, sticker_count, last_active)
|
|
45
|
+
VALUES (?, ?, ?, ?, ?)
|
|
46
|
+
ON CONFLICT(group_jid, user_jid) DO UPDATE SET
|
|
47
|
+
msg_count = msg_count + excluded.msg_count,
|
|
48
|
+
sticker_count = sticker_count + excluded.sticker_count,
|
|
49
|
+
last_active = excluded.last_active
|
|
50
|
+
`);
|
|
51
|
+
this.getStatsStmt = this.db.prepare('SELECT user_jid, msg_count, sticker_count, last_active FROM group_stats WHERE group_jid = ?');
|
|
52
|
+
this.getTopMsgStmt = (limit) => this.db.prepare(`SELECT user_jid AS jid, msg_count AS count FROM group_stats WHERE group_jid = ? ORDER BY msg_count DESC LIMIT ${limit}`);
|
|
53
|
+
this.getTopStickerStmt = (limit) => this.db.prepare(`SELECT user_jid AS jid, sticker_count AS count FROM group_stats WHERE group_jid = ? ORDER BY sticker_count DESC LIMIT ${limit}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** JAP@Port: replaces the old synchronous `new StatsManager(dbPath, groupMetaFn)`. */
|
|
57
|
+
static async create(dbPath, groupMetaFn) {
|
|
58
|
+
const Database = await loadBetterSqlite3();
|
|
59
|
+
return new StatsManager(new Database(dbPath), groupMetaFn);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Record a message observation for stats. Normalizes both JIDs before storing. */
|
|
63
|
+
observeMessage(groupJid, userJid, isSticker) {
|
|
64
|
+
const normalizedGroupJid = jidNormalizedUser(groupJid);
|
|
65
|
+
const normalizedUserJid = jidNormalizedUser(userJid);
|
|
66
|
+
const msgCount = 1;
|
|
67
|
+
const stickerCount = isSticker ? 1 : 0;
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
this.insertStmt.run(normalizedGroupJid, normalizedUserJid, msgCount, stickerCount, now);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Top message senders for a group. */
|
|
73
|
+
getTopUsers(groupJid, limit = 10) {
|
|
74
|
+
const safeLimit = Math.max(1, Math.floor(limit));
|
|
75
|
+
const normalizedGroupJid = jidNormalizedUser(groupJid);
|
|
76
|
+
return this.getTopMsgStmt(safeLimit).all(normalizedGroupJid);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Top sticker senders for a group. */
|
|
80
|
+
getTopStickers(groupJid, limit = 10) {
|
|
81
|
+
const safeLimit = Math.max(1, Math.floor(limit));
|
|
82
|
+
const normalizedGroupJid = jidNormalizedUser(groupJid);
|
|
83
|
+
return this.getTopStickerStmt(safeLimit).all(normalizedGroupJid);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Detect inactive members ("ghosts") in a group. */
|
|
87
|
+
async getGhosts(groupJid, socketConnected, inactiveDays = 30) {
|
|
88
|
+
if (!socketConnected) {
|
|
89
|
+
throw new Boom('Socket not connected — cannot fetch group metadata for ghost detection', {
|
|
90
|
+
statusCode: 503
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const normalizedGroupJid = jidNormalizedUser(groupJid);
|
|
94
|
+
const cutoff = Date.now() - inactiveDays * 24 * 60 * 60 * 1000;
|
|
95
|
+
const rows = this.getStatsStmt.all(normalizedGroupJid);
|
|
96
|
+
const statsMap = new Map();
|
|
97
|
+
for (const row of rows) {
|
|
98
|
+
statsMap.set(jidNormalizedUser(row.user_jid), row.last_active);
|
|
99
|
+
}
|
|
100
|
+
const groupMeta = await this.groupMetaFn(groupJid);
|
|
101
|
+
return groupMeta.participants
|
|
102
|
+
.map(p => {
|
|
103
|
+
const normalizedJid = jidNormalizedUser(p.id);
|
|
104
|
+
const lastActive = statsMap.get(normalizedJid);
|
|
105
|
+
if (!lastActive) {
|
|
106
|
+
return { jid: normalizedJid, isTotalGhost: true };
|
|
107
|
+
}
|
|
108
|
+
if (lastActive < cutoff) {
|
|
109
|
+
return { jid: normalizedJid, isTotalGhost: false, lastActive };
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
})
|
|
113
|
+
.filter((g) => g !== null);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
close() {
|
|
117
|
+
this.db.close();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Generic key-value store backed by better-sqlite3 (lazy-loaded). */
|
|
2
|
+
export class SQLiteStore {
|
|
3
|
+
constructor(db: any);
|
|
4
|
+
/** Async factory — await this instead of `new SQLiteStore(dbPath)`. */
|
|
5
|
+
static create(dbPath: string): Promise<SQLiteStore>;
|
|
6
|
+
get(key: string): any;
|
|
7
|
+
/** `undefined`/`null` values delete the key. */
|
|
8
|
+
set(key: string, value: any): void;
|
|
9
|
+
del(key: string): void;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// JAP@Framework --- generic key-value store backed by better-sqlite3. Used by
|
|
2
|
+
// SessionManager to persist per-JID session state to disk instead of RAM.
|
|
3
|
+
//
|
|
4
|
+
// JAP@Fix vs upstream: `better-sqlite3` was a hard top-level `import`, which
|
|
5
|
+
// would crash the whole Framework import at module-load time for anyone who
|
|
6
|
+
// hasn't installed it (it's an optional peer dep in this fork, same as
|
|
7
|
+
// use-sqlite-auth-state). Switched to the lazy `loadBetterSqlite3()` loader
|
|
8
|
+
// already used by Utils/use-sqlite-auth-state.js, and moved construction
|
|
9
|
+
// behind an async `SQLiteStore.create()` factory since the loader is async.
|
|
10
|
+
async function loadBetterSqlite3() {
|
|
11
|
+
try {
|
|
12
|
+
const mod = (await import('better-sqlite3'));
|
|
13
|
+
return mod.default ?? mod;
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
const helpful = new Error('`better-sqlite3` is required for the Framework SQLiteStore. Install it as a peer dependency: `npm install better-sqlite3` (or `yarn add better-sqlite3`).');
|
|
17
|
+
helpful.cause = err;
|
|
18
|
+
throw helpful;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class SQLiteStore {
|
|
23
|
+
constructor(db) {
|
|
24
|
+
this.db = db;
|
|
25
|
+
this.db.exec(`
|
|
26
|
+
CREATE TABLE IF NOT EXISTS kv_store (
|
|
27
|
+
key TEXT PRIMARY KEY,
|
|
28
|
+
value TEXT NOT NULL
|
|
29
|
+
)
|
|
30
|
+
`);
|
|
31
|
+
this.getStmt = this.db.prepare('SELECT value FROM kv_store WHERE key = ?');
|
|
32
|
+
this.setStmt = this.db.prepare('INSERT INTO kv_store (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value');
|
|
33
|
+
this.delStmt = this.db.prepare('DELETE FROM kv_store WHERE key = ?');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** JAP@Port: replaces the old synchronous `new SQLiteStore(dbPath)` — await this instead. */
|
|
37
|
+
static async create(dbPath) {
|
|
38
|
+
const Database = await loadBetterSqlite3();
|
|
39
|
+
return new SQLiteStore(new Database(dbPath));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get(key) {
|
|
43
|
+
const row = this.getStmt.get(key);
|
|
44
|
+
if (!row)
|
|
45
|
+
return undefined;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(row.value);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Fallback for legacy non-JSON rows (migration safety)
|
|
51
|
+
return row.value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
set(key, value) {
|
|
56
|
+
// guard undefined/null — delegate to del so callers don't need to check
|
|
57
|
+
if (value === undefined || value === null) {
|
|
58
|
+
this.del(key);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// always JSON.stringify — raw string storage breaks round-trip for
|
|
62
|
+
// values that are valid JSON (numbers, booleans, JSON objects serialized as strings)
|
|
63
|
+
this.setStmt.run(key, JSON.stringify(value));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
del(key) {
|
|
67
|
+
this.delStmt.run(key);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
close() {
|
|
71
|
+
this.db.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Bot, resolveSocketVersionConfig } from './Bot.js';
|
|
2
|
+
export { Context } from './Context.js';
|
|
3
|
+
export { MediaManager } from './MediaManager.js';
|
|
4
|
+
export { SessionManager } from './SessionManager.js';
|
|
5
|
+
export { StatsManager } from './StatsManager.js';
|
|
6
|
+
export { SQLiteStore } from './Store/SQLiteStore.js';
|
|
7
|
+
export type { BotConfig, BotMiddleware, BotCommandHandler } from './Bot.js';
|
|
8
|
+
export type { StickerMetadata } from './MediaManager.js';
|
|
9
|
+
export type { StatRow, GhostEntry } from './StatsManager.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// JAP@Port --- Enterprise Bot Framework exports.
|
|
2
|
+
// Design notes: SQLiteStore/StatsManager are lazy-loaded (see
|
|
3
|
+
// Store/SQLiteStore.js and StatsManager.js), MediaManager spawns the system
|
|
4
|
+
// `ffmpeg` binary instead of bundling fluent-ffmpeg/ffmpeg-static.
|
|
5
|
+
export { Bot, resolveSocketVersionConfig } from './Bot.js';
|
|
6
|
+
export { Context } from './Context.js';
|
|
7
|
+
export { MediaManager } from './MediaManager.js';
|
|
8
|
+
export { SessionManager } from './SessionManager.js';
|
|
9
|
+
export { StatsManager } from './StatsManager.js';
|
|
10
|
+
export { SQLiteStore } from './Store/SQLiteStore.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export class CiphertextMessage {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.UNSUPPORTED_VERSION = 1;
|
|
4
|
+
this.CURRENT_VERSION = 3;
|
|
5
|
+
this.WHISPER_TYPE = 2;
|
|
6
|
+
this.PREKEY_TYPE = 3;
|
|
7
|
+
this.SENDERKEY_TYPE = 4;
|
|
8
|
+
this.SENDERKEY_DISTRIBUTION_TYPE = 5;
|
|
9
|
+
this.ENCRYPTED_MESSAGE_OVERHEAD = 53;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export class GroupSessionBuilder {
|
|
2
|
+
constructor(senderKeyStore: any);
|
|
3
|
+
senderKeyStore: any;
|
|
4
|
+
process(senderKeyName: any, senderKeyDistributionMessage: any): Promise<void>;
|
|
5
|
+
create(senderKeyName: any): Promise<SenderKeyDistributionMessage>;
|
|
6
|
+
}
|
|
7
|
+
import { SenderKeyDistributionMessage } from './sender-key-distribution-message.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as keyhelper from './keyhelper.js';
|
|
2
|
+
import { SenderKeyDistributionMessage } from './sender-key-distribution-message.js';
|
|
3
|
+
import { SenderKeyName } from './sender-key-name.js';
|
|
4
|
+
import { SenderKeyRecord } from './sender-key-record.js';
|
|
5
|
+
export class GroupSessionBuilder {
|
|
6
|
+
constructor(senderKeyStore) {
|
|
7
|
+
this.senderKeyStore = senderKeyStore;
|
|
8
|
+
}
|
|
9
|
+
async process(senderKeyName, senderKeyDistributionMessage) {
|
|
10
|
+
const senderKeyRecord = await this.senderKeyStore.loadSenderKey(senderKeyName);
|
|
11
|
+
senderKeyRecord.addSenderKeyState(senderKeyDistributionMessage.getId(), senderKeyDistributionMessage.getIteration(), senderKeyDistributionMessage.getChainKey(), senderKeyDistributionMessage.getSignatureKey());
|
|
12
|
+
await this.senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord);
|
|
13
|
+
}
|
|
14
|
+
async create(senderKeyName) {
|
|
15
|
+
const senderKeyRecord = await this.senderKeyStore.loadSenderKey(senderKeyName);
|
|
16
|
+
if (senderKeyRecord.isEmpty()) {
|
|
17
|
+
const keyId = keyhelper.generateSenderKeyId();
|
|
18
|
+
const senderKey = keyhelper.generateSenderKey();
|
|
19
|
+
const signingKey = keyhelper.generateSenderSigningKey();
|
|
20
|
+
senderKeyRecord.setSenderKeyState(keyId, 0, senderKey, signingKey);
|
|
21
|
+
await this.senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord);
|
|
22
|
+
}
|
|
23
|
+
const state = senderKeyRecord.getSenderKeyState();
|
|
24
|
+
if (!state) {
|
|
25
|
+
throw new Error('No session state available');
|
|
26
|
+
}
|
|
27
|
+
return new SenderKeyDistributionMessage(state.getKeyId(), state.getSenderChainKey().getIteration(), state.getSenderChainKey().getSeed(), state.getSigningKeyPublic());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export class GroupCipher {
|
|
2
|
+
constructor(senderKeyStore: any, senderKeyName: any);
|
|
3
|
+
senderKeyStore: any;
|
|
4
|
+
senderKeyName: any;
|
|
5
|
+
encrypt(paddedPlaintext: any): Promise<any>;
|
|
6
|
+
decrypt(senderKeyMessageBytes: any): Promise<any>;
|
|
7
|
+
getSenderKey(senderKeyState: any, iteration: any): any;
|
|
8
|
+
getPlainText(iv: any, key: any, ciphertext: any): Promise<any>;
|
|
9
|
+
getCipherText(iv: any, key: any, plaintext: any): Promise<any>;
|
|
10
|
+
}
|