@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,162 @@
|
|
|
1
|
+
import { getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidMetaAI, isLidUser, isPnUser, jidNormalizedUser } from '../WABinary/index.js';
|
|
2
|
+
// Same phone-number pattern as WABinary's isJidBot, applied against the user
|
|
3
|
+
// part so the check is invariant to @c.us ↔ @s.whatsapp.net normalization.
|
|
4
|
+
const BOT_PHONE_REGEX = /^1313555\d{4}$|^131655500\d{2}$/;
|
|
5
|
+
/**
|
|
6
|
+
* Mirrors WA Web's `Wid.isRegularUser()` (user ∧ ¬PSA ∧ ¬Bot). Used to gate tctoken
|
|
7
|
+
* storage against malformed notifications — WA Web filters server-side but we
|
|
8
|
+
* defend here for parity with `WAWebSetTcTokenChatAction.handleIncomingTcToken`.
|
|
9
|
+
* Works for both pre- and post-normalized JIDs (`@c.us` vs `@s.whatsapp.net`).
|
|
10
|
+
*/
|
|
11
|
+
function isRegularUser(jid) {
|
|
12
|
+
if (!jid)
|
|
13
|
+
return false;
|
|
14
|
+
const user = jid.split('@')[0] ?? '';
|
|
15
|
+
if (user === '0')
|
|
16
|
+
return false; // PSA
|
|
17
|
+
if (BOT_PHONE_REGEX.test(user))
|
|
18
|
+
return false; // Bot by phone pattern
|
|
19
|
+
if (isJidMetaAI(jid))
|
|
20
|
+
return false; // MetaAI (@bot server)
|
|
21
|
+
return !!(isPnUser(jid) || isLidUser(jid) || isHostedPnUser(jid) || isHostedLidUser(jid) || jid.endsWith('@c.us'));
|
|
22
|
+
}
|
|
23
|
+
const TC_TOKEN_BUCKET_DURATION = 604800; // 7 days
|
|
24
|
+
const TC_TOKEN_NUM_BUCKETS = 4; // ~28-day rolling window
|
|
25
|
+
/** Sentinel key under `tctoken` store holding a JSON array of tracked storage JIDs for cross-session pruning. */
|
|
26
|
+
export const TC_TOKEN_INDEX_KEY = '__index';
|
|
27
|
+
/** Read the persisted tctoken JID index and return its entries (never contains the sentinel key itself). */
|
|
28
|
+
export async function readTcTokenIndex(keys) {
|
|
29
|
+
const data = await keys.get('tctoken', [TC_TOKEN_INDEX_KEY]);
|
|
30
|
+
const entry = data[TC_TOKEN_INDEX_KEY];
|
|
31
|
+
if (!entry?.token?.length)
|
|
32
|
+
return [];
|
|
33
|
+
try {
|
|
34
|
+
const parsed = JSON.parse(Buffer.from(entry.token).toString());
|
|
35
|
+
if (!Array.isArray(parsed))
|
|
36
|
+
return [];
|
|
37
|
+
return parsed.filter((j) => typeof j === 'string' && j.length > 0 && j !== TC_TOKEN_INDEX_KEY);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Build a SignalDataSet fragment that writes the merged index (persisted ∪ added) under the sentinel key. */
|
|
44
|
+
export async function buildMergedTcTokenIndexWrite(keys, addedJids) {
|
|
45
|
+
const persisted = await readTcTokenIndex(keys);
|
|
46
|
+
const merged = new Set(persisted);
|
|
47
|
+
for (const jid of addedJids) {
|
|
48
|
+
if (jid && jid !== TC_TOKEN_INDEX_KEY)
|
|
49
|
+
merged.add(jid);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
[TC_TOKEN_INDEX_KEY]: { token: Buffer.from(JSON.stringify([...merged])) }
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// WA Web has separate sender/receiver AB props for these but they're identical today
|
|
56
|
+
export function isTcTokenExpired(timestamp) {
|
|
57
|
+
if (timestamp === null || timestamp === undefined)
|
|
58
|
+
return true;
|
|
59
|
+
const ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp;
|
|
60
|
+
if (isNaN(ts))
|
|
61
|
+
return true;
|
|
62
|
+
const now = Math.floor(Date.now() / 1000);
|
|
63
|
+
const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
|
|
64
|
+
const cutoffBucket = currentBucket - (TC_TOKEN_NUM_BUCKETS - 1);
|
|
65
|
+
const cutoffTimestamp = cutoffBucket * TC_TOKEN_BUCKET_DURATION;
|
|
66
|
+
return ts < cutoffTimestamp;
|
|
67
|
+
}
|
|
68
|
+
export function shouldSendNewTcToken(senderTimestamp) {
|
|
69
|
+
if (senderTimestamp === undefined)
|
|
70
|
+
return true;
|
|
71
|
+
const now = Math.floor(Date.now() / 1000);
|
|
72
|
+
const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
|
|
73
|
+
const senderBucket = Math.floor(senderTimestamp / TC_TOKEN_BUCKET_DURATION);
|
|
74
|
+
return currentBucket > senderBucket;
|
|
75
|
+
}
|
|
76
|
+
/** Resolve JID to LID for tctoken storage (WA Web stores under LID) */
|
|
77
|
+
export async function resolveTcTokenJid(jid, getLIDForPN) {
|
|
78
|
+
if (isLidUser(jid))
|
|
79
|
+
return jid;
|
|
80
|
+
const lid = await getLIDForPN(jid);
|
|
81
|
+
return lid ?? jid;
|
|
82
|
+
}
|
|
83
|
+
/** Resolve target JID for issuing privacy token based on AB prop 14303 */
|
|
84
|
+
export async function resolveIssuanceJid(jid, issueToLid, getLIDForPN, getPNForLID) {
|
|
85
|
+
if (issueToLid) {
|
|
86
|
+
if (isLidUser(jid))
|
|
87
|
+
return jid;
|
|
88
|
+
const lid = await getLIDForPN(jid);
|
|
89
|
+
return lid ?? jid;
|
|
90
|
+
}
|
|
91
|
+
if (!isLidUser(jid))
|
|
92
|
+
return jid;
|
|
93
|
+
if (getPNForLID) {
|
|
94
|
+
const pn = await getPNForLID(jid);
|
|
95
|
+
return pn ?? jid;
|
|
96
|
+
}
|
|
97
|
+
return jid;
|
|
98
|
+
}
|
|
99
|
+
export async function buildTcTokenFromJid({ authState, jid, baseContent = [], getLIDForPN }) {
|
|
100
|
+
try {
|
|
101
|
+
const storageJid = await resolveTcTokenJid(jid, getLIDForPN);
|
|
102
|
+
const tcTokenData = await authState.keys.get('tctoken', [storageJid]);
|
|
103
|
+
const entry = tcTokenData?.[storageJid];
|
|
104
|
+
const tcTokenBuffer = entry?.token;
|
|
105
|
+
if (!tcTokenBuffer?.length || isTcTokenExpired(entry?.timestamp)) {
|
|
106
|
+
if (tcTokenBuffer) {
|
|
107
|
+
// Preserve senderTimestamp so shouldSendNewTcToken() keeps its dedupe state
|
|
108
|
+
// after we drop the unusable peer token. Only wipe the record entirely when
|
|
109
|
+
// there's nothing worth keeping.
|
|
110
|
+
const cleared = entry?.senderTimestamp !== undefined
|
|
111
|
+
? { token: Buffer.alloc(0), senderTimestamp: entry.senderTimestamp }
|
|
112
|
+
: null;
|
|
113
|
+
await authState.keys.set({ tctoken: { [storageJid]: cleared } });
|
|
114
|
+
}
|
|
115
|
+
return baseContent.length > 0 ? baseContent : undefined;
|
|
116
|
+
}
|
|
117
|
+
baseContent.push({
|
|
118
|
+
tag: 'tctoken',
|
|
119
|
+
attrs: {},
|
|
120
|
+
content: tcTokenBuffer
|
|
121
|
+
});
|
|
122
|
+
return baseContent;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
return baseContent.length > 0 ? baseContent : undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export async function storeTcTokensFromIqResult({ result, fallbackJid, keys, getLIDForPN, onNewJidStored }) {
|
|
129
|
+
const tokensNode = getBinaryNodeChild(result, 'tokens');
|
|
130
|
+
if (!tokensNode)
|
|
131
|
+
return;
|
|
132
|
+
const tokenNodes = getBinaryNodeChildren(tokensNode, 'token');
|
|
133
|
+
for (const tokenNode of tokenNodes) {
|
|
134
|
+
if (tokenNode.attrs.type !== 'trusted_contact' || !(tokenNode.content instanceof Uint8Array)) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
// In notifications tokenNode.attrs.jid is your own device JID, not the sender's
|
|
138
|
+
const rawJid = jidNormalizedUser(fallbackJid || tokenNode.attrs.jid);
|
|
139
|
+
if (!isRegularUser(rawJid))
|
|
140
|
+
continue;
|
|
141
|
+
const storageJid = await resolveTcTokenJid(rawJid, getLIDForPN);
|
|
142
|
+
const existingTcData = await keys.get('tctoken', [storageJid]);
|
|
143
|
+
const existingEntry = existingTcData[storageJid];
|
|
144
|
+
const existingTs = existingEntry?.timestamp ? Number(existingEntry.timestamp) : 0;
|
|
145
|
+
const incomingTs = tokenNode.attrs.t ? Number(tokenNode.attrs.t) : 0;
|
|
146
|
+
// timestamp-less tokens would be immediately expired
|
|
147
|
+
if (!incomingTs)
|
|
148
|
+
continue;
|
|
149
|
+
if (existingTs > 0 && existingTs > incomingTs)
|
|
150
|
+
continue;
|
|
151
|
+
await keys.set({
|
|
152
|
+
tctoken: {
|
|
153
|
+
[storageJid]: {
|
|
154
|
+
...existingEntry,
|
|
155
|
+
token: Buffer.from(tokenNode.content),
|
|
156
|
+
timestamp: tokenNode.attrs.t
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
onNewJidStored?.(storageJid);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export interface TemplateVariable {
|
|
2
|
+
name: string;
|
|
3
|
+
defaultValue?: string;
|
|
4
|
+
required: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface MessageTemplate {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
content: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
category?: string;
|
|
12
|
+
variables: TemplateVariable[];
|
|
13
|
+
createdAt: Date;
|
|
14
|
+
updatedAt: Date;
|
|
15
|
+
}
|
|
16
|
+
export type TemplateData = Record<string, string | number | undefined | null>;
|
|
17
|
+
export declare class TemplateManager {
|
|
18
|
+
private templates;
|
|
19
|
+
private generateId;
|
|
20
|
+
private extractVariables;
|
|
21
|
+
create(options: {
|
|
22
|
+
id?: string;
|
|
23
|
+
name: string;
|
|
24
|
+
content: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
category?: string;
|
|
27
|
+
}): MessageTemplate;
|
|
28
|
+
get(id: string): MessageTemplate | undefined;
|
|
29
|
+
getByName(name: string): MessageTemplate | undefined;
|
|
30
|
+
getAll(): MessageTemplate[];
|
|
31
|
+
getByCategory(category: string): MessageTemplate[];
|
|
32
|
+
update(id: string, updates: Partial<MessageTemplate>): MessageTemplate | undefined;
|
|
33
|
+
delete(id: string): boolean;
|
|
34
|
+
renderContent(content: string, data?: TemplateData): string;
|
|
35
|
+
render(id: string, data?: TemplateData): string;
|
|
36
|
+
validate(id: string, data: TemplateData): {
|
|
37
|
+
valid: boolean;
|
|
38
|
+
missing: string[];
|
|
39
|
+
};
|
|
40
|
+
export(): string;
|
|
41
|
+
import(json: string, overwrite?: boolean): number;
|
|
42
|
+
}
|
|
43
|
+
export declare const PRESET_TEMPLATES: {
|
|
44
|
+
ORDER_CONFIRMATION: {
|
|
45
|
+
name: string;
|
|
46
|
+
category: string;
|
|
47
|
+
content: string;
|
|
48
|
+
};
|
|
49
|
+
WELCOME: {
|
|
50
|
+
name: string;
|
|
51
|
+
category: string;
|
|
52
|
+
content: string;
|
|
53
|
+
};
|
|
54
|
+
REMINDER: {
|
|
55
|
+
name: string;
|
|
56
|
+
category: string;
|
|
57
|
+
content: string;
|
|
58
|
+
};
|
|
59
|
+
SUPPORT_TICKET: {
|
|
60
|
+
name: string;
|
|
61
|
+
category: string;
|
|
62
|
+
content: string;
|
|
63
|
+
};
|
|
64
|
+
BIRTHDAY: {
|
|
65
|
+
name: string;
|
|
66
|
+
category: string;
|
|
67
|
+
content: string;
|
|
68
|
+
};
|
|
69
|
+
INVOICE: {
|
|
70
|
+
name: string;
|
|
71
|
+
category: string;
|
|
72
|
+
content: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
export declare const createTemplateManager: (includePresets?: boolean) => TemplateManager;
|
|
76
|
+
export declare const renderTemplate: (content: string, data?: TemplateData) => string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// JAP@Add --- part of the @japofc/baileys utils (templates.ts) (type-only
|
|
2
|
+
// annotations dropped; behavior unchanged).
|
|
3
|
+
export class TemplateManager {
|
|
4
|
+
templates = new Map();
|
|
5
|
+
generateId() {
|
|
6
|
+
return `tpl_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
7
|
+
}
|
|
8
|
+
extractVariables(content) {
|
|
9
|
+
const regex = /\{\{(\w+)(?::([^}]*))?\}\}/g;
|
|
10
|
+
const variables = [];
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
let match;
|
|
13
|
+
while ((match = regex.exec(content)) !== null) {
|
|
14
|
+
const name = match[1];
|
|
15
|
+
if (!name || seen.has(name))
|
|
16
|
+
continue;
|
|
17
|
+
seen.add(name);
|
|
18
|
+
variables.push({ name, defaultValue: match[2], required: !match[2] });
|
|
19
|
+
}
|
|
20
|
+
return variables;
|
|
21
|
+
}
|
|
22
|
+
create(options) {
|
|
23
|
+
const template = {
|
|
24
|
+
id: options.id ?? this.generateId(),
|
|
25
|
+
name: options.name,
|
|
26
|
+
content: options.content,
|
|
27
|
+
description: options.description,
|
|
28
|
+
category: options.category,
|
|
29
|
+
variables: this.extractVariables(options.content),
|
|
30
|
+
createdAt: new Date(),
|
|
31
|
+
updatedAt: new Date()
|
|
32
|
+
};
|
|
33
|
+
this.templates.set(template.id, template);
|
|
34
|
+
return template;
|
|
35
|
+
}
|
|
36
|
+
get(id) {
|
|
37
|
+
return this.templates.get(id);
|
|
38
|
+
}
|
|
39
|
+
getByName(name) {
|
|
40
|
+
return Array.from(this.templates.values()).find((t) => t.name === name);
|
|
41
|
+
}
|
|
42
|
+
getAll() {
|
|
43
|
+
return Array.from(this.templates.values());
|
|
44
|
+
}
|
|
45
|
+
getByCategory(category) {
|
|
46
|
+
return Array.from(this.templates.values()).filter((t) => t.category === category);
|
|
47
|
+
}
|
|
48
|
+
update(id, updates) {
|
|
49
|
+
const template = this.templates.get(id);
|
|
50
|
+
if (!template)
|
|
51
|
+
return undefined;
|
|
52
|
+
if (updates.content)
|
|
53
|
+
updates.variables = this.extractVariables(updates.content);
|
|
54
|
+
const updated = { ...template, ...updates, updatedAt: new Date() };
|
|
55
|
+
this.templates.set(id, updated);
|
|
56
|
+
return updated;
|
|
57
|
+
}
|
|
58
|
+
delete(id) {
|
|
59
|
+
return this.templates.delete(id);
|
|
60
|
+
}
|
|
61
|
+
renderContent(content, data = {}) {
|
|
62
|
+
return content.replace(/\{\{(\w+)(?::([^}]*))?\}\}/g, (match, name, defaultValue) => {
|
|
63
|
+
const value = data[name];
|
|
64
|
+
if (value !== undefined && value !== null)
|
|
65
|
+
return String(value);
|
|
66
|
+
if (defaultValue !== undefined)
|
|
67
|
+
return defaultValue;
|
|
68
|
+
return match;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
render(id, data = {}) {
|
|
72
|
+
const template = this.templates.get(id);
|
|
73
|
+
if (!template)
|
|
74
|
+
throw new Error(`Template not found: ${id}`);
|
|
75
|
+
return this.renderContent(template.content, data);
|
|
76
|
+
}
|
|
77
|
+
validate(id, data) {
|
|
78
|
+
const template = this.templates.get(id);
|
|
79
|
+
if (!template)
|
|
80
|
+
throw new Error(`Template not found: ${id}`);
|
|
81
|
+
const missing = template.variables.filter((v) => v.required && !(v.name in data)).map((v) => v.name);
|
|
82
|
+
return { valid: missing.length === 0, missing };
|
|
83
|
+
}
|
|
84
|
+
export() {
|
|
85
|
+
return JSON.stringify(Array.from(this.templates.values()), null, 2);
|
|
86
|
+
}
|
|
87
|
+
import(json, overwrite = false) {
|
|
88
|
+
const templates = JSON.parse(json);
|
|
89
|
+
let imported = 0;
|
|
90
|
+
for (const t of templates) {
|
|
91
|
+
if (!overwrite && this.templates.has(t.id))
|
|
92
|
+
continue;
|
|
93
|
+
this.templates.set(t.id, { ...t, createdAt: new Date(t.createdAt), updatedAt: new Date(t.updatedAt) });
|
|
94
|
+
imported++;
|
|
95
|
+
}
|
|
96
|
+
return imported;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Ready-made templates covering common bot scenarios (order, welcome, reminder, etc). */
|
|
100
|
+
export const PRESET_TEMPLATES = {
|
|
101
|
+
ORDER_CONFIRMATION: {
|
|
102
|
+
name: 'Order Confirmation',
|
|
103
|
+
category: 'order',
|
|
104
|
+
content: `✅ *Order Confirmed!*\n\nOrder ID: #{{orderId}}\nCustomer: {{customerName}}\nDate: {{orderDate}}\n\n📦 *Items:*\n{{items}}\n\n💰 *Total: {{total}}*\n\nThank you! 🙏`
|
|
105
|
+
},
|
|
106
|
+
WELCOME: {
|
|
107
|
+
name: 'Welcome Message',
|
|
108
|
+
category: 'greeting',
|
|
109
|
+
content: `👋 *Welcome, {{name}}!*\n\nThank you for joining {{companyName:us}}!\nNeed help? Reply to this message!`
|
|
110
|
+
},
|
|
111
|
+
REMINDER: {
|
|
112
|
+
name: 'Reminder',
|
|
113
|
+
category: 'notification',
|
|
114
|
+
content: `⏰ *Reminder*\n\nHi {{name}},\n\n📋 {{subject}}\n📅 Date: {{date}}\n🕐 Time: {{time}}\n📍 Location: {{location:TBD}}`
|
|
115
|
+
},
|
|
116
|
+
SUPPORT_TICKET: {
|
|
117
|
+
name: 'Support Ticket',
|
|
118
|
+
category: 'support',
|
|
119
|
+
content: `🎫 *Support Ticket Created*\n\nTicket #: {{ticketId}}\nSubject: {{subject}}\n\nHi {{name}},\n\nWe received your request! Response time: {{responseTime:24 hours}} 🙏`
|
|
120
|
+
},
|
|
121
|
+
BIRTHDAY: {
|
|
122
|
+
name: 'Birthday Wishes',
|
|
123
|
+
category: 'greeting',
|
|
124
|
+
content: `🎂 *Happy Birthday, {{name}}!* 🎉\n\nWishing you a wonderful day!\n\n🎁 Use code: {{code}} for {{discount:10}}% off! 🥳`
|
|
125
|
+
},
|
|
126
|
+
INVOICE: {
|
|
127
|
+
name: 'Invoice',
|
|
128
|
+
category: 'invoice',
|
|
129
|
+
content: `🧾 *Invoice {{invoiceNumber}}*\n\nBilled to: {{customerName}}\nInvoice date: {{invoiceDate}}\nDue date: {{dueDate:on receipt}}\n\n📋 *Items:*\n{{items}}\n\nSubtotal: {{subtotal}}\n💰 *Total: {{total}}*\n\nThank you for your business! 🙏`
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
export const createTemplateManager = (includePresets = true) => {
|
|
133
|
+
const manager = new TemplateManager();
|
|
134
|
+
if (includePresets) {
|
|
135
|
+
for (const [key, template] of Object.entries(PRESET_TEMPLATES)) {
|
|
136
|
+
manager.create({ ...template, id: key.toLowerCase() });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return manager;
|
|
140
|
+
};
|
|
141
|
+
export const renderTemplate = (content, data = {}) => {
|
|
142
|
+
return content.replace(/\{\{(\w+)(?::([^}]*))?\}\}/g, (match, name, defaultValue) => {
|
|
143
|
+
const value = data[name];
|
|
144
|
+
if (value !== undefined && value !== null)
|
|
145
|
+
return String(value);
|
|
146
|
+
if (defaultValue !== undefined)
|
|
147
|
+
return defaultValue;
|
|
148
|
+
return match;
|
|
149
|
+
});
|
|
150
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type TranscriptionProvider = (audio: Buffer, meta?: { mimetype?: string }) => Promise<{ text: string }>;
|
|
2
|
+
export declare const customProvider: (fn: (audio: Buffer, meta?: any) => Promise<{ text: string } | string> | { text: string } | string) => TranscriptionProvider;
|
|
3
|
+
export interface WhisperProviderOptions {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
language?: string;
|
|
8
|
+
fileName?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const openAIWhisperProvider: (opts: WhisperProviderOptions) => TranscriptionProvider;
|
|
11
|
+
export declare const transcribeAudio: (audio: Buffer, opts?: { provider?: TranscriptionProvider; mimetype?: string }) => Promise<{ text: string }>;
|
|
12
|
+
export declare const transcribeMessage: (sock: any, webMessage: any, opts?: { provider?: TranscriptionProvider; download?: (keys: any) => Promise<any> }) => Promise<{ text: string; seconds: number | null; ptt: boolean }>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JAP@Add --- voice-note transcription with pluggable providers.
|
|
3
|
+
*
|
|
4
|
+
* WhatsApp generates transcripts on-device only — there is no transcript API
|
|
5
|
+
* on the wire. So this module downloads the voice note and hands it to a
|
|
6
|
+
* *provider function* you choose: any `(audioBuffer, { mimetype }) => { text }`.
|
|
7
|
+
* Ships with an OpenAI-compatible Whisper provider; bring your own for local
|
|
8
|
+
* models (faster-whisper sidecar, etc).
|
|
9
|
+
*
|
|
10
|
+
* ```js
|
|
11
|
+
* import { transcribeMessage, openAIWhisperProvider } from '@japofc/baileys'
|
|
12
|
+
* const provider = openAIWhisperProvider({ apiKey: process.env.OPENAI_API_KEY })
|
|
13
|
+
* sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
14
|
+
* for (const m of messages) {
|
|
15
|
+
* if (m.message?.audioMessage?.ptt) console.log(await transcribeMessage(sock, m, { provider }))
|
|
16
|
+
* }
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { Boom } from '@hapi/boom';
|
|
21
|
+
import { downloadContentFromMessage } from './messages-media.js';
|
|
22
|
+
|
|
23
|
+
const streamToBuffer = async (stream) => {
|
|
24
|
+
const chunks = [];
|
|
25
|
+
for await (const chunk of stream) {
|
|
26
|
+
chunks.push(chunk);
|
|
27
|
+
}
|
|
28
|
+
return Buffer.concat(chunks);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const needProvider = (provider) => {
|
|
32
|
+
if (typeof provider !== 'function') {
|
|
33
|
+
throw new Boom('transcription needs { provider } — see customProvider() / openAIWhisperProvider()', { statusCode: 400 });
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Wrap any async `(audioBuffer, meta) => { text } | string` fn into a provider. */
|
|
38
|
+
export const customProvider = (fn) => {
|
|
39
|
+
if (typeof fn !== 'function') {
|
|
40
|
+
throw new Boom('customProvider(fn) needs a function', { statusCode: 400 });
|
|
41
|
+
}
|
|
42
|
+
return async (audio, meta = {}) => {
|
|
43
|
+
const res = await fn(audio, meta);
|
|
44
|
+
const text = typeof res === 'string' ? res : res?.text;
|
|
45
|
+
if (!text || typeof text !== 'string') {
|
|
46
|
+
throw new Boom('transcription provider returned no text', { statusCode: 502 });
|
|
47
|
+
}
|
|
48
|
+
return { text };
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** OpenAI-compatible `/v1/audio/transcriptions` endpoint (cloud or local clone). */
|
|
53
|
+
export const openAIWhisperProvider = ({ apiKey, model = 'whisper-1', baseUrl = 'https://api.openai.com/v1', language, fileName = 'voice.ogg' } = {}) => {
|
|
54
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
55
|
+
throw new Boom('openAIWhisperProvider needs { apiKey }', { statusCode: 400 });
|
|
56
|
+
}
|
|
57
|
+
return async (audio, { mimetype = 'audio/ogg' } = {}) => {
|
|
58
|
+
const form = new FormData();
|
|
59
|
+
form.append('model', model);
|
|
60
|
+
form.append('file', new Blob([audio], { type: mimetype }), fileName);
|
|
61
|
+
if (language) {
|
|
62
|
+
form.append('language', language);
|
|
63
|
+
}
|
|
64
|
+
const res = await fetch(`${baseUrl}/audio/transcriptions`, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
67
|
+
body: form
|
|
68
|
+
});
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
throw new Boom(`transcription failed: HTTP ${res.status}`, { statusCode: 502 });
|
|
71
|
+
}
|
|
72
|
+
const { text } = await res.json();
|
|
73
|
+
if (!text || typeof text !== 'string') {
|
|
74
|
+
throw new Boom('transcription endpoint returned no text', { statusCode: 502 });
|
|
75
|
+
}
|
|
76
|
+
return { text };
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** Transcribe a raw audio buffer with any provider. */
|
|
81
|
+
export const transcribeAudio = async (audio, { provider, mimetype } = {}) => {
|
|
82
|
+
if (!Buffer.isBuffer(audio) || !audio.length) {
|
|
83
|
+
throw new Boom('transcribeAudio(audio) needs a non-empty audio Buffer', { statusCode: 400 });
|
|
84
|
+
}
|
|
85
|
+
needProvider(provider);
|
|
86
|
+
return provider(audio, { mimetype });
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Download + transcribe a voice-note/audio WAMessage.
|
|
91
|
+
* `download` override exists for tests (default hits the WA media CDN).
|
|
92
|
+
*/
|
|
93
|
+
export const transcribeMessage = async (sock, webMessage, { provider, download } = {}) => {
|
|
94
|
+
const audio = webMessage?.message?.audioMessage;
|
|
95
|
+
if (!audio?.mediaKey) {
|
|
96
|
+
throw new Boom('transcribeMessage needs a voice-note/audio WAMessage', { statusCode: 400 });
|
|
97
|
+
}
|
|
98
|
+
needProvider(provider);
|
|
99
|
+
const dl = download || ((keys) => downloadContentFromMessage(keys, 'audio', {}));
|
|
100
|
+
const stream = await dl({ mediaKey: audio.mediaKey, directPath: audio.directPath, url: audio.url });
|
|
101
|
+
const buf = await streamToBuffer(stream);
|
|
102
|
+
const { text } = await provider(buf, { mimetype: audio.mimetype });
|
|
103
|
+
if (!text || typeof text !== 'string') {
|
|
104
|
+
throw new Boom('transcription provider returned no text', { statusCode: 502 });
|
|
105
|
+
}
|
|
106
|
+
return { text, seconds: audio.seconds ?? null, ptt: audio.ptt ?? false };
|
|
107
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthenticationState } from '../Types/index.js';
|
|
2
|
+
/** Minimal interface compatible with any cache-manager v5 store (Redis, Memcached, keyv, @cacheable/node-cache, etc). */
|
|
3
|
+
export type CacheManagerStore = {
|
|
4
|
+
set(key: string, value: string, ttl?: number): Promise<void>;
|
|
5
|
+
get(key: string): Promise<string | undefined | null>;
|
|
6
|
+
del(key: string): Promise<void>;
|
|
7
|
+
keys(pattern?: string): Promise<string[]>;
|
|
8
|
+
};
|
|
9
|
+
export declare const useCacheManagerAuthState: (store: CacheManagerStore, sessionKey: string) => Promise<{
|
|
10
|
+
state: AuthenticationState;
|
|
11
|
+
saveCreds: () => Promise<void>;
|
|
12
|
+
clearState: () => Promise<void>;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// JAP@Utils --- cache-manager auth-state backend (any cache-manager store).
|
|
2
|
+
// Adjustments for @japofc/baileys: import paths rewired to this fork's
|
|
3
|
+
// Utils layout (auth-utils.js / generics.js), otherwise logic-for-logic
|
|
4
|
+
// identical to the original — including the 2-year TTL on `creds` and the
|
|
5
|
+
// `sessionKey*` wildcard sweep in `clearState()`.
|
|
6
|
+
//
|
|
7
|
+
// Store interface required (matches any cache-manager v5-compatible store,
|
|
8
|
+
// e.g. Redis/Memcached/keyv, or this fork's own @cacheable/node-cache dep):
|
|
9
|
+
// store.get(key) -> string | undefined | null
|
|
10
|
+
// store.set(key, value, ttl?) -> void
|
|
11
|
+
// store.del(key) -> void
|
|
12
|
+
// store.keys(pattern?) -> string[] (used by clearState() for the wildcard sweep)
|
|
13
|
+
import { proto } from '../../WAProto/index.js';
|
|
14
|
+
import { initAuthCreds } from './auth-utils.js';
|
|
15
|
+
import { BufferJSON } from './generics.js';
|
|
16
|
+
|
|
17
|
+
export const useCacheManagerAuthState = async (store, sessionKey) => {
|
|
18
|
+
const defaultKey = (file) => `${sessionKey}:${file}`;
|
|
19
|
+
const writeData = async (file, data) => {
|
|
20
|
+
const ttl = file === 'creds' ? 63115200 : undefined; // 2 years for creds
|
|
21
|
+
await store.set(defaultKey(file), JSON.stringify(data, BufferJSON.replacer), ttl);
|
|
22
|
+
};
|
|
23
|
+
const readData = async (file) => {
|
|
24
|
+
try {
|
|
25
|
+
const data = await store.get(defaultKey(file));
|
|
26
|
+
return data !== null && data !== undefined ? JSON.parse(data, BufferJSON.reviver) : null;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const removeData = async (file) => {
|
|
33
|
+
try {
|
|
34
|
+
await store.del(defaultKey(file));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
console.error(`[useCacheManagerAuthState] Error removing ${file} from session ${sessionKey}`);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const clearState = async () => {
|
|
41
|
+
try {
|
|
42
|
+
const keys = await store.keys(`${sessionKey}*`);
|
|
43
|
+
await Promise.all(keys.map((key) => store.del(key)));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// best-effort — not every store backend supports pattern listing
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const creds = (await readData('creds')) || initAuthCreds();
|
|
50
|
+
return {
|
|
51
|
+
clearState,
|
|
52
|
+
state: {
|
|
53
|
+
creds,
|
|
54
|
+
keys: {
|
|
55
|
+
get: async (type, ids) => {
|
|
56
|
+
const data = {};
|
|
57
|
+
await Promise.all(ids.map(async (id) => {
|
|
58
|
+
let value = await readData(`${type}-${id}`);
|
|
59
|
+
if (type === 'app-state-sync-key' && value) {
|
|
60
|
+
value = proto.Message.AppStateSyncKeyData.fromObject(value);
|
|
61
|
+
}
|
|
62
|
+
data[id] = value;
|
|
63
|
+
}));
|
|
64
|
+
return data;
|
|
65
|
+
},
|
|
66
|
+
set: async (data) => {
|
|
67
|
+
const tasks = [];
|
|
68
|
+
for (const category in data) {
|
|
69
|
+
for (const id in data[category]) {
|
|
70
|
+
const value = data[category][id];
|
|
71
|
+
const key = `${category}-${id}`;
|
|
72
|
+
tasks.push(value ? writeData(key, value) : removeData(key));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
await Promise.all(tasks);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
saveCreds: () => writeData('creds', creds)
|
|
80
|
+
};
|
|
81
|
+
};
|