@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,652 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/Utils/MessageBuilder.js — AIRich / Button / ButtonV2 / Carousel / Toolkit
|
|
3
|
+
*
|
|
4
|
+
* Part of @japofc/baileys 1.4.4. Third-party attribution for the base
|
|
5
|
+
* implementation this file was adapted from is kept in /NOTICE.md
|
|
6
|
+
* (not inline here) per the original author's license terms.
|
|
7
|
+
*
|
|
8
|
+
* JAP@Merge 15-08-26 --- Ported into @japofc/baileys 1.3.9 from the
|
|
9
|
+
* @blurose/baileys 1.1.13 fork (base, feature-complete) with perf defaults
|
|
10
|
+
* and message-authenticity fields backported from arslan-baileys 1.1.0 and
|
|
11
|
+
* this project's own rich-message-utils.js. See changes tagged "JAP@" below.
|
|
12
|
+
*
|
|
13
|
+
* JAP@Fix 23-08-26 --- v4.7 -> v4.8. addGenerating() now defaults to appending a
|
|
14
|
+
* FOATextPrimitive text fallback ('[ Sedang diproses... ]'), same pattern as
|
|
15
|
+
* addTask/addThinkingStatus/addBloks. Previously the card had no client-visible
|
|
16
|
+
* content until WA's own timeout swapped it for its built-in failed-generation
|
|
17
|
+
* text; this makes the fallback instant. Opt out with { textFallback: false }.
|
|
18
|
+
*
|
|
19
|
+
* JAP@Merge 22-08-26 --- v4.6 -> v4.7. Button class hardened + extended:
|
|
20
|
+
* - Bug fix: addCall() wrote its second arg into buttonParamsJson.id, but
|
|
21
|
+
* the cta_call native-flow schema keys on `phone_number` (id is ignored
|
|
22
|
+
* by WhatsApp for this button type). Confirmed against 3 independent
|
|
23
|
+
* current Baileys-fork call sites before changing the wire shape.
|
|
24
|
+
* - Required-field validation added to the CTA helpers that silently
|
|
25
|
+
* produced a button WA would render but never route correctly
|
|
26
|
+
* (empty id/url/copy_code/phone_number).
|
|
27
|
+
* - New native-flow helpers for names WA recognises beyond the "mixed"
|
|
28
|
+
* set (cta_catalog, open_webview, call_permission_request,
|
|
29
|
+
* automated_greeting_message_view_catalog, payment_info,
|
|
30
|
+
* review_and_pay, wa_payment_transaction_details, mpm) — see the
|
|
31
|
+
* Button.#SPECIAL_FLOW map and each method's JSDoc for the
|
|
32
|
+
* business/official-client gating caveat.
|
|
33
|
+
* - send() now picks the correct <native_flow v=.. name=..> node per the
|
|
34
|
+
* first button's name instead of always emitting v=9 name=mixed, which
|
|
35
|
+
* is required for the special names above to have a chance of
|
|
36
|
+
* rendering at all (mirrors the same class of bug already fixed for
|
|
37
|
+
* lone single_select in 1.3.x).
|
|
38
|
+
* - JSDoc added across Toolkit/BaseBuilder/Button/ButtonV2/Carousel/AIRich
|
|
39
|
+
* for editor hover-docs; kept in sync with MessageBuilder.d.ts.
|
|
40
|
+
* All additions above are original implementations written against public
|
|
41
|
+
* Baileys-ecosystem documentation of the native-flow wire format, not
|
|
42
|
+
* copied from any third-party fork.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
'use strict';
|
|
46
|
+
|
|
47
|
+
// JAP@Fix 24-08-26: use the exported builder version everywhere; the old
|
|
48
|
+
// verification helper referenced an undeclared `VERSION`, making every AIRich.build() fail.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
import { generateWAMessageFromContent, prepareWAMessageMedia } from '../Utils/messages.js';
|
|
52
|
+
import { generateMessageIDV2 } from '../Utils/generics.js';
|
|
53
|
+
import { botMetadataSignature, botMetadataCertificate } from '../Utils/rich-message-utils.js';
|
|
54
|
+
// JAP@Fix 27-08-26: Button.send() was hand-rolling its own <biz> node with
|
|
55
|
+
// attrs: {} instead of reusing the canonical builder. Real client traffic
|
|
56
|
+
// (and the auto-attached biz node in Socket/messages-send.js) always carries
|
|
57
|
+
// actual_actors/host_storage/privacy_mode_ts on every <biz> node, including
|
|
58
|
+
// the one wrapping a lone single_select's <list> node. Missing them made the
|
|
59
|
+
// single_select wire payload diverge from what messages-send.js emits for
|
|
60
|
+
// every other message type -- import the shared helper instead of duplicating
|
|
61
|
+
// (and silently drifting from) its attrs.
|
|
62
|
+
import { getBizBinaryNode } from '../WABinary/index.js';
|
|
63
|
+
import crypto from 'crypto';
|
|
64
|
+
import { PassThrough, Readable } from 'stream';
|
|
65
|
+
// JAP@Fix 15-08-26 --- sharp/fluent-ffmpeg were statically imported in the blurose source.
|
|
66
|
+
// Both are optional peer deps here (see package.json peerDependenciesMeta); a static import
|
|
67
|
+
// throws at module-load time when they're not installed, which would crash the entire
|
|
68
|
+
// lib/Utils barrel export (and therefore bot startup) even for users who never call
|
|
69
|
+
// AIRich.addImage()/addVideo()/Toolkit.*. Lazy-load them instead, matching the pattern
|
|
70
|
+
// already used in messages-media.js's getImageProcessingLibrary().
|
|
71
|
+
let _sharp;
|
|
72
|
+
const getSharp = async () => {
|
|
73
|
+
if (_sharp === undefined) {
|
|
74
|
+
_sharp = await import('sharp').then((m) => m.default ?? m).catch(() => null);
|
|
75
|
+
}
|
|
76
|
+
if (!_sharp)
|
|
77
|
+
throw new Error('sharp is required for this operation. Install it with: npm i sharp');
|
|
78
|
+
return _sharp;
|
|
79
|
+
};
|
|
80
|
+
let _ffmpeg;
|
|
81
|
+
const getFfmpeg = async () => {
|
|
82
|
+
if (_ffmpeg === undefined) {
|
|
83
|
+
_ffmpeg = await import('fluent-ffmpeg').then((m) => m.default ?? m).catch(() => null);
|
|
84
|
+
}
|
|
85
|
+
if (!_ffmpeg)
|
|
86
|
+
throw new Error('fluent-ffmpeg is required for this operation. Install it with: npm i fluent-ffmpeg');
|
|
87
|
+
return _ffmpeg;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
function extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
|
|
91
|
+
if (!extract) {
|
|
92
|
+
return {
|
|
93
|
+
text,
|
|
94
|
+
ie: [],
|
|
95
|
+
inline_entities: [],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const createIE = (type, ie) => {
|
|
100
|
+
if (type == 'hyperlink') {
|
|
101
|
+
return {
|
|
102
|
+
key: ie.key,
|
|
103
|
+
metadata: {
|
|
104
|
+
display_name: ie.text,
|
|
105
|
+
is_trusted: ie.is_trusted,
|
|
106
|
+
url: ie.url,
|
|
107
|
+
__typename: 'GenAIInlineLinkItem',
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (type == 'citation') {
|
|
113
|
+
return {
|
|
114
|
+
key: ie.key,
|
|
115
|
+
metadata: {
|
|
116
|
+
reference_id: ie.reference_id,
|
|
117
|
+
reference_url: ie.url,
|
|
118
|
+
reference_title: ie.url,
|
|
119
|
+
reference_display_name: ie.url,
|
|
120
|
+
sources: [],
|
|
121
|
+
__typename: 'GenAISearchCitationItem',
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (type == 'latex') {
|
|
127
|
+
return {
|
|
128
|
+
key: ie.key,
|
|
129
|
+
metadata: {
|
|
130
|
+
latex_expression: ie.text,
|
|
131
|
+
latex_image: {
|
|
132
|
+
url: ie.url,
|
|
133
|
+
width: Number(ie.width) || 100,
|
|
134
|
+
height: Number(ie.height) || 100,
|
|
135
|
+
},
|
|
136
|
+
font_height: Number(ie.font_height) || 83.333333333333,
|
|
137
|
+
padding: Number(ie.padding) || 15,
|
|
138
|
+
__typename: 'GenAILatexItem',
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
let ie = [];
|
|
145
|
+
let inline_entities = [];
|
|
146
|
+
let result = '';
|
|
147
|
+
let last = 0;
|
|
148
|
+
let citation_index = 1;
|
|
149
|
+
let hyperlink_index = 0;
|
|
150
|
+
let latex_index = 0;
|
|
151
|
+
let stack = [];
|
|
152
|
+
|
|
153
|
+
for (let i = 0; i < text.length; i++) {
|
|
154
|
+
if (text[i] == '[' && text[i - 1] != '\\') {
|
|
155
|
+
stack.push(i);
|
|
156
|
+
} else if (text[i] == ']' && (text[i + 1] == '(' || text[i + 1] == '<')) {
|
|
157
|
+
let start = stack.pop();
|
|
158
|
+
|
|
159
|
+
if (start == null) continue;
|
|
160
|
+
|
|
161
|
+
let open = text[i + 1];
|
|
162
|
+
let close = open == '(' ? ')' : '>';
|
|
163
|
+
let type = open == '(' ? 'link' : 'latex';
|
|
164
|
+
let end = i + 2;
|
|
165
|
+
let depth = 1;
|
|
166
|
+
|
|
167
|
+
while (end < text.length && depth) {
|
|
168
|
+
if (text[end] == open && text[end - 1] != '\\') depth++;
|
|
169
|
+
else if (text[end] == close && text[end - 1] != '\\') depth--;
|
|
170
|
+
end++;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (depth) continue;
|
|
174
|
+
|
|
175
|
+
let raw = text.slice(start + 1, i).trim();
|
|
176
|
+
let url = text.slice(i + 2, end - 1).trim();
|
|
177
|
+
|
|
178
|
+
let key;
|
|
179
|
+
let tag;
|
|
180
|
+
let data;
|
|
181
|
+
|
|
182
|
+
if (type == 'latex') {
|
|
183
|
+
if (!latex) continue;
|
|
184
|
+
|
|
185
|
+
let [txt = '', width = null, height = null, font_height = null, padding = null] = raw.split('|');
|
|
186
|
+
|
|
187
|
+
key = `\u004E\u0049\u0058\u0045\u004C_LATEX_${latex_index++}`;
|
|
188
|
+
tag = `{{${key}}}${txt || 'image'}{{/${key}}}`;
|
|
189
|
+
|
|
190
|
+
data = {
|
|
191
|
+
type: 'latex',
|
|
192
|
+
ie: {
|
|
193
|
+
key,
|
|
194
|
+
text: txt,
|
|
195
|
+
url,
|
|
196
|
+
width,
|
|
197
|
+
height,
|
|
198
|
+
font_height,
|
|
199
|
+
padding,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
} else if (raw) {
|
|
203
|
+
if (!hyperlink) continue;
|
|
204
|
+
|
|
205
|
+
const trusted = !url.startsWith('!');
|
|
206
|
+
|
|
207
|
+
if (!trusted) {
|
|
208
|
+
url = url.slice(1);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
key = `\u004E\u0049\u0058\u0045\u004C_HYPERLINK_${hyperlink_index++}`;
|
|
212
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
213
|
+
|
|
214
|
+
data = {
|
|
215
|
+
type: 'hyperlink',
|
|
216
|
+
ie: {
|
|
217
|
+
key,
|
|
218
|
+
text: raw,
|
|
219
|
+
url,
|
|
220
|
+
is_trusted: trusted,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
} else {
|
|
224
|
+
if (!citation) continue;
|
|
225
|
+
|
|
226
|
+
key = `\u004E\u0049\u0058\u0045\u004C_CITATION_${citation_index - 1}`;
|
|
227
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
228
|
+
|
|
229
|
+
data = {
|
|
230
|
+
type: 'citation',
|
|
231
|
+
ie: {
|
|
232
|
+
reference_id: citation_index++,
|
|
233
|
+
key,
|
|
234
|
+
text: '',
|
|
235
|
+
url,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
result += text.slice(last, start) + tag;
|
|
241
|
+
last = end;
|
|
242
|
+
|
|
243
|
+
ie.push(data);
|
|
244
|
+
|
|
245
|
+
const entity = createIE(data.type, data.ie);
|
|
246
|
+
|
|
247
|
+
if (entity) {
|
|
248
|
+
inline_entities.push(entity);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
i = end - 1;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
result += text.slice(last);
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
text: result,
|
|
259
|
+
ie,
|
|
260
|
+
inline_entities,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function waitAllPromises(input) {
|
|
265
|
+
const isPromise = (v) => v && typeof v.then === 'function';
|
|
266
|
+
const isObject = (v) => v && typeof v === 'object';
|
|
267
|
+
|
|
268
|
+
const deep = async (v) => {
|
|
269
|
+
if (isPromise(v)) return deep(await v);
|
|
270
|
+
if (Array.isArray(v)) return Promise.all(v.map(deep));
|
|
271
|
+
if (isObject(v)) {
|
|
272
|
+
const entries = await Promise.all(Object.entries(v).map(async ([k, val]) => [k, await deep(val)]));
|
|
273
|
+
return Object.fromEntries(entries);
|
|
274
|
+
}
|
|
275
|
+
return v;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
return deep(await input);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Static grab-bag of media/text helpers shared by the builder classes above. */
|
|
282
|
+
class Toolkit {
|
|
283
|
+
constructor() {}
|
|
284
|
+
|
|
285
|
+
/** Parse `[label](url)` hyperlinks, `[]()` citations, and `[expr]<img-url>` latex tags out of `text`. */
|
|
286
|
+
static extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
|
|
287
|
+
return extractIE(text, { extract, hyperlink, citation, latex });
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Resize an image buffer to `x`×`y` via sharp (lazy-loaded; throws with an install hint if sharp isn't present). */
|
|
291
|
+
static async resize(buffer, x, y, fit = 'cover') {
|
|
292
|
+
const sharp = await getSharp();
|
|
293
|
+
return await sharp(buffer)
|
|
294
|
+
.resize(x, y, {
|
|
295
|
+
fit,
|
|
296
|
+
position: 'center',
|
|
297
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
298
|
+
})
|
|
299
|
+
.png()
|
|
300
|
+
.toBuffer();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Deeply await every Promise nested in `input` (objects/arrays), resolving it into plain values. */
|
|
304
|
+
static async waitAllPromises(input) {
|
|
305
|
+
return await waitAllPromises(input);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** Fetch `url` into a Buffer. @param {boolean} [silent] Return an empty Buffer instead of throwing on failure. @param {number} [timeout] Abort after this many ms (default 15s) instead of hanging indefinitely on a dead/slow host. */
|
|
309
|
+
static async fetchBuffer(url, options = {}, { silent = true, timeout = 15000 } = {}) {
|
|
310
|
+
const controller = new AbortController();
|
|
311
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
312
|
+
try {
|
|
313
|
+
let response = await fetch(url, { ...options, signal: options.signal ?? controller.signal });
|
|
314
|
+
if (!response.ok) throw Error(`HTTP ${response.status}`);
|
|
315
|
+
return Buffer.from(await response.arrayBuffer());
|
|
316
|
+
} catch (error) {
|
|
317
|
+
if (silent) return Buffer.alloc(0);
|
|
318
|
+
throw error;
|
|
319
|
+
} finally {
|
|
320
|
+
clearTimeout(timer);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Upload media to WhatsApp's media server and return its `url`/`directPath` descriptor. */
|
|
325
|
+
static async toUrl(_client, path, mediaType = 'document') {
|
|
326
|
+
if (!path) throw new Error('Url or buffer needed');
|
|
327
|
+
|
|
328
|
+
const media = await prepareWAMessageMedia(
|
|
329
|
+
{
|
|
330
|
+
[mediaType]: Buffer.isBuffer(path) ? path : { url: path },
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
upload: _client.waUploadToServer,
|
|
334
|
+
jid: '\u0040\u006e\u0065\u0077\u0073\u006c\u0065\u0074\u0074\u0065\u0072',
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
return Object.values(media)[0]?.url;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Normalize a url/buffer/array of either into the requested `result` shape ('url' | 'buffer' | 'base64'), optionally resizing and/or uploading to WA's media server first. */
|
|
342
|
+
static async resolveMedia(_client, media, mediaType = 'image', { resolveUrl = false, resolveWAUrl = false, result = 'url', resize = false, width = 300, height = 300 } = {}) {
|
|
343
|
+
const isUrl = (str) => /^https?:\/\/.+/i.test(str);
|
|
344
|
+
|
|
345
|
+
const isWAUrl = (str) => /^https?:\/\/[^/]*\.whatsapp\.net\//i.test(str);
|
|
346
|
+
|
|
347
|
+
// JAP@Fix (crash guard) --- keep the original raw url around so that if the
|
|
348
|
+
// resolveUrl=true upload-to-'@newsletter' round trip (Toolkit.toUrl -> prepareWAMessageMedia)
|
|
349
|
+
// throws/rejects (blocked account, network hiccup, WA server refusal, etc.), we can
|
|
350
|
+
// gracefully fall back to the raw url instead of letting the rejection bubble up
|
|
351
|
+
// unhandled through waitAllPromises() and take the whole process down. Only applies
|
|
352
|
+
// when the input was actually a url string; buffers/base64 have no such fallback.
|
|
353
|
+
const rawUrlFallback = typeof media === 'string' && isUrl(media) ? media : undefined;
|
|
354
|
+
|
|
355
|
+
if (Array.isArray(media)) {
|
|
356
|
+
return Promise.all(
|
|
357
|
+
media.map((item) =>
|
|
358
|
+
Toolkit.resolveMedia(_client, item, mediaType, {
|
|
359
|
+
resolveUrl,
|
|
360
|
+
resolveWAUrl,
|
|
361
|
+
result,
|
|
362
|
+
resize,
|
|
363
|
+
width,
|
|
364
|
+
height,
|
|
365
|
+
})
|
|
366
|
+
)
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (typeof media === 'string' && isUrl(media)) {
|
|
371
|
+
if (isWAUrl(media)) {
|
|
372
|
+
if (resolveWAUrl) {
|
|
373
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
374
|
+
} else if (!resolveUrl) {
|
|
375
|
+
if (result === 'url') return media;
|
|
376
|
+
|
|
377
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
if (!resolveUrl) {
|
|
381
|
+
if (result === 'url') return media;
|
|
382
|
+
|
|
383
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
384
|
+
} else {
|
|
385
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (typeof media === 'string' && !isUrl(media)) {
|
|
391
|
+
media = Buffer.from(media, 'base64');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (!Buffer.isBuffer(media) || !media.length) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (resize && Buffer.isBuffer(media)) {
|
|
399
|
+
media = await Toolkit.resize(media, width, height);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (result === 'buffer') {
|
|
403
|
+
return media;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (result === 'base64') {
|
|
407
|
+
return media.toString('base64');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// JAP@Fix 22-08-26 (v4.7) --- both branches of the old if/else here returned the exact
|
|
411
|
+
// same `Toolkit.toUrl(_client, media, mediaType)` call (dead branching left over from an
|
|
412
|
+
// earlier version that must have treated buffer vs non-buffer input differently). Collapsed
|
|
413
|
+
// to a single return; `originalIsBuffer` is now unused and removed below.
|
|
414
|
+
//
|
|
415
|
+
// JAP@Fix (crash guard) --- toUrl() uploads to WA's media server under a spoofed
|
|
416
|
+
// '@newsletter' jid; if that upload fails for any reason, fall back to the raw url
|
|
417
|
+
// (when we have one) instead of letting the exception propagate and crash the caller.
|
|
418
|
+
try {
|
|
419
|
+
return await Toolkit.toUrl(_client, media, mediaType);
|
|
420
|
+
} catch (err) {
|
|
421
|
+
if (rawUrlFallback) return rawUrlFallback;
|
|
422
|
+
throw err;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** Read an mp4 buffer's duration (seconds) straight from its moov atom, no ffprobe needed. */
|
|
427
|
+
static getMp4Duration(buffer, { silent = true } = {}) {
|
|
428
|
+
try {
|
|
429
|
+
if (!Buffer.isBuffer(buffer) || buffer.length < 8) {
|
|
430
|
+
if (silent) return 0;
|
|
431
|
+
throw new Error('Invalid buffer');
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
let offset = 0;
|
|
435
|
+
|
|
436
|
+
while (offset < buffer.length - 8) {
|
|
437
|
+
const size = buffer.readUInt32BE(offset);
|
|
438
|
+
|
|
439
|
+
if (size < 8 || offset + size > buffer.length) {
|
|
440
|
+
if (silent) return 0;
|
|
441
|
+
throw new Error('Invalid atom size');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const type = buffer.toString('ascii', offset + 4, offset + 8);
|
|
445
|
+
|
|
446
|
+
if (type === 'moov') {
|
|
447
|
+
let moovOffset = offset + 8;
|
|
448
|
+
const moovEnd = offset + size;
|
|
449
|
+
|
|
450
|
+
while (moovOffset < moovEnd - 8) {
|
|
451
|
+
const childSize = buffer.readUInt32BE(moovOffset);
|
|
452
|
+
|
|
453
|
+
if (childSize < 8 || moovOffset + childSize > moovEnd) {
|
|
454
|
+
if (silent) return 0;
|
|
455
|
+
throw new Error('Invalid child atom size');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const childType = buffer.toString('ascii', moovOffset + 4, moovOffset + 8);
|
|
459
|
+
|
|
460
|
+
if (childType === 'mvhd') {
|
|
461
|
+
const version = buffer.readUInt8(moovOffset + 8);
|
|
462
|
+
|
|
463
|
+
if (version === 0) {
|
|
464
|
+
const timescale = buffer.readUInt32BE(moovOffset + 20);
|
|
465
|
+
const duration = buffer.readUInt32BE(moovOffset + 24);
|
|
466
|
+
|
|
467
|
+
if (!timescale) {
|
|
468
|
+
if (silent) return 0;
|
|
469
|
+
throw new Error('Invalid timescale');
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return duration / timescale;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (version === 1) {
|
|
476
|
+
const timescale = buffer.readUInt32BE(moovOffset + 32);
|
|
477
|
+
const duration = Number(buffer.readBigUInt64BE(moovOffset + 36));
|
|
478
|
+
|
|
479
|
+
if (!timescale) {
|
|
480
|
+
if (silent) return 0;
|
|
481
|
+
throw new Error('Invalid timescale');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return duration / timescale;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
moovOffset += childSize;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
offset += size;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (silent) return 0;
|
|
496
|
+
|
|
497
|
+
throw new Error('No mvhd found!');
|
|
498
|
+
} catch (err) {
|
|
499
|
+
if (silent) return 0;
|
|
500
|
+
throw err;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/** Extract a single frame from an mp4 buffer as a thumbnail (ffmpeg lazy-loaded; throws with an install hint if missing). */
|
|
505
|
+
static getMp4Preview(videoBuffer, { time, result = 'buffer', resize = true, width = 300, height = 300, silent = true } = {}) {
|
|
506
|
+
return new Promise((resolve, reject) => {
|
|
507
|
+
const fail = (err) => {
|
|
508
|
+
if (silent) {
|
|
509
|
+
return resolve(result === 'base64' ? '' : Buffer.alloc(0));
|
|
510
|
+
}
|
|
511
|
+
return reject(err);
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
try {
|
|
515
|
+
if (!Buffer.isBuffer(videoBuffer) || !videoBuffer.length) {
|
|
516
|
+
return fail(new Error('videoBuffer tidak valid atau kosong'));
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const inputStream = new Readable({ read() {} });
|
|
520
|
+
inputStream.push(videoBuffer);
|
|
521
|
+
inputStream.push(null);
|
|
522
|
+
|
|
523
|
+
const outputStream = new PassThrough();
|
|
524
|
+
const chunks = [];
|
|
525
|
+
|
|
526
|
+
outputStream.on('data', (chunk) => chunks.push(chunk));
|
|
527
|
+
|
|
528
|
+
outputStream.on('end', async () => {
|
|
529
|
+
try {
|
|
530
|
+
let output = Buffer.concat(chunks);
|
|
531
|
+
|
|
532
|
+
if (!output.length) {
|
|
533
|
+
return fail(new Error('Output kosong — cek format atau timestamp video'));
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (resize) {
|
|
537
|
+
output = await Toolkit.resize(output, width, height);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return resolve(result === 'base64' ? output.toString('base64') : output);
|
|
541
|
+
} catch (err) {
|
|
542
|
+
return fail(err);
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
outputStream.on('error', fail);
|
|
547
|
+
|
|
548
|
+
time ??= Math.min(Toolkit.getMp4Duration(videoBuffer) * 0.2, 10);
|
|
549
|
+
|
|
550
|
+
getFfmpeg()
|
|
551
|
+
.then((ffmpeg) => {
|
|
552
|
+
ffmpeg(inputStream)
|
|
553
|
+
.outputOptions([`-ss ${time}`, '-vframes 1', '-vcodec png', '-f image2pipe'])
|
|
554
|
+
.on('error', (err) => fail(new Error(`ffmpeg error: ${err.message}`)))
|
|
555
|
+
.pipe(outputStream, { end: true });
|
|
556
|
+
})
|
|
557
|
+
.catch(fail);
|
|
558
|
+
} catch (err) {
|
|
559
|
+
return fail(err);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Shared chaining base for Button/ButtonV2/Carousel/AIRich: title/subtitle/body/footer,
|
|
567
|
+
* contextInfo (quoted/mentions/etc.), and an escape-hatch payload merged verbatim
|
|
568
|
+
* into the generated message content.
|
|
569
|
+
* @abstract
|
|
570
|
+
*/
|
|
571
|
+
class BaseBuilder {
|
|
572
|
+
constructor() {
|
|
573
|
+
this._title = '';
|
|
574
|
+
this._subtitle = '';
|
|
575
|
+
this._body = '';
|
|
576
|
+
this._footer = '';
|
|
577
|
+
this._contextInfo = {};
|
|
578
|
+
this._extraPayload = {};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** @param {string} title */
|
|
582
|
+
setTitle(title) {
|
|
583
|
+
if (typeof title !== 'string') {
|
|
584
|
+
throw new TypeError('Title must be a string');
|
|
585
|
+
}
|
|
586
|
+
this._title = title;
|
|
587
|
+
return this;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/** @param {string} subtitle */
|
|
591
|
+
setSubtitle(subtitle) {
|
|
592
|
+
if (typeof subtitle !== 'string') {
|
|
593
|
+
throw new TypeError('Subtitle must be a string');
|
|
594
|
+
}
|
|
595
|
+
this._subtitle = subtitle;
|
|
596
|
+
return this;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** @param {string} body Main message text. */
|
|
600
|
+
setBody(body) {
|
|
601
|
+
if (typeof body !== 'string') {
|
|
602
|
+
throw new TypeError('Body must be a string');
|
|
603
|
+
}
|
|
604
|
+
this._body = body;
|
|
605
|
+
return this;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/** @param {string} footer */
|
|
609
|
+
setFooter(footer) {
|
|
610
|
+
if (typeof footer !== 'string') {
|
|
611
|
+
throw new TypeError('Footer must be a string');
|
|
612
|
+
}
|
|
613
|
+
this._footer = footer;
|
|
614
|
+
return this;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/** @param {Record<string, any>} obj Raw `contextInfo` (quotedMessage, mentionedJid, etc.), merged verbatim. */
|
|
618
|
+
setContextInfo(obj) {
|
|
619
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
620
|
+
throw new TypeError('ContextInfo must be a plain object');
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
this._contextInfo = obj;
|
|
624
|
+
return this;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/** Escape hatch: shallow-merge arbitrary keys into the generated message content, alongside whatever this builder produces. */
|
|
628
|
+
addPayload(obj) {
|
|
629
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
630
|
+
throw new TypeError('Payload must be a plain object');
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
Object.assign(this._extraPayload, obj);
|
|
634
|
+
|
|
635
|
+
return this;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/** Tiny fluent helper for building a single quickReply button row (type 1). Standalone — not tied to Button/ButtonV2. */
|
|
640
|
+
class RowBuilder {
|
|
641
|
+
constructor() {
|
|
642
|
+
this.buttons = [];
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
button(displayText, buttonId) {
|
|
646
|
+
this.buttons.push({ buttonId, buttonText: { displayText }, type: 1 });
|
|
647
|
+
return this;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
export { Toolkit, BaseBuilder, RowBuilder, extractIE, waitAllPromises, getSharp, getFfmpeg, generateWAMessageFromContent, prepareWAMessageMedia, generateMessageIDV2, botMetadataSignature, botMetadataCertificate, getBizBinaryNode, crypto, PassThrough, Readable };
|