{"slug": "messagebuilderv4-3-js", "title": "MessageBuilderV4.3.js", "summary": "Developer Nixel released MessageBuilderV4.3.js, an advanced WhatsApp interactive message builder that creates buttons, carousels, native flows, and AI-rich response payloads using the Baileys library. The library features fluent chaining, flexible payload customization, and scalable architecture for modern bot development, with permission granted for personal or commercial use but prohibiting reuploading or reselling as a standalone product.", "body_md": "|\n/** |\n|\n* NIXCODE - Advanced WhatsApp Interactive Message Builder |\n|\n* Built for creating buttons, carousels, native flows, |\n|\n* and AI rich response payloads using Baileys with |\n|\n* fluent chaining, flexible payload customization, |\n|\n* and scalable architecture for modern bot development. |\n|\n* |\n|\n* Created by Nixel |\n|\n* wa.me/6282139672290 |\n|\n* |\n|\n* Copyright (c) 2026 Nixel |\n|\n* |\n|\n* Permission is granted to use and modify this library |\n|\n* for personal or commercial projects. |\n|\n* |\n|\n* Reuploading, reselling, relicensing, or redistributing |\n|\n* this library as a standalone product is prohibited. |\n|\n* |\n|\n* Do not claim this project as your own original work. |\n|\n*/ |\n|\n|\n|\nconst VERSION = '4.3'; |\n|\n|\n|\nimport { generateWAMessageFromContent, prepareWAMessageMedia } from 'baileys'; |\n|\nimport crypto from 'crypto'; |\n|\nimport sharp from 'sharp'; |\n|\n|\n|\nfunction extractHyperlink(text) { |\n|\nlet hyperlink = [], |\n|\nstack = [], |\n|\nresult = '', |\n|\nlast = 0, |\n|\nindex = 1, |\n|\nentity = 0; |\n|\nfor (let i = 0; i < text.length; i++) { |\n|\nif (text[i] == '[' && text[i - 1] != '\\\\') { |\n|\nstack.push(i); |\n|\n} else if (text[i] == ']' && text[i + 1] == '(') { |\n|\nlet start = stack.pop(); |\n|\nif (start == null) continue; |\n|\nlet end = i + 2, |\n|\ndepth = 1; |\n|\nwhile (end < text.length && depth) { |\n|\nif (text[end] == '(' && text[end - 1] != '\\\\') depth++; |\n|\nelse if (text[end] == ')' && text[end - 1] != '\\\\') depth--; |\n|\nend++; |\n|\n} |\n|\nif (depth) continue; |\n|\nlet txt = text.slice(start + 1, i).trim(), |\n|\nurl = text.slice(i + 2, end - 1), |\n|\nreference_id = txt ? 0 : index++, |\n|\nkey = `IE_${entity++}`, |\n|\ntag = `{{${key}}}${txt || 'Nixel'}{{/${key}}}`; |\n|\nresult += text.slice(last, start) + tag; |\n|\nlast = end; |\n|\nhyperlink.push({ |\n|\nreference_id, |\n|\nkey, |\n|\ntext: txt, |\n|\nurl, |\n|\n}); |\n|\ni = end - 1; |\n|\n} |\n|\n} |\n|\nresult += text.slice(last); |\n|\nreturn { |\n|\ntext: result, |\n|\nhyperlink, |\n|\n}; |\n|\n} |\n|\n|\n|\nasync function fetchBuffer(url, options = {}, config = {}) { |\n|\ntry { |\n|\nlet response = await fetch(url, options); |\n|\nif (!response.ok) throw Error(`HTTP ${response.status}`); |\n|\nreturn Buffer.from(await response.arrayBuffer()); |\n|\n} catch (error) { |\n|\nif (config.silent) return Buffer.alloc(0); |\n|\nthrow error; |\n|\n} |\n|\n} |\n|\n|\n|\nclass BaseBuilder { |\n|\nconstructor() { |\n|\nthis._title = ''; |\n|\nthis._subtitle = ''; |\n|\nthis._body = ''; |\n|\nthis._footer = ''; |\n|\nthis._contextInfo = {}; |\n|\nthis._extraPayload = {}; |\n|\n} |\n|\n|\n|\nsetTitle(title) { |\n|\nthis._title = title; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetSubtitle(subtitle) { |\n|\nthis._subtitle = subtitle; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetBody(body) { |\n|\nthis._body = body; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetFooter(footer) { |\n|\nthis._footer = footer; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetContextInfo(obj) { |\n|\nif (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { |\n|\nthrow new TypeError('ContextInfo must be a plain object'); |\n|\n} |\n|\n|\n|\nthis._contextInfo = obj; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddPayload(obj) { |\n|\nif (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { |\n|\nthrow new TypeError('Payload must be a plain object'); |\n|\n} |\n|\n|\n|\nObject.assign(this._extraPayload, obj); |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n} |\n|\n|\n|\nclass Button extends BaseBuilder { |\n|\n#client; |\n|\n|\n|\nconstructor(client) { |\n|\nsuper(); |\n|\nif (!client) { |\n|\nthrow new Error('Socket is required'); |\n|\n} |\n|\nthis.#client = client; |\n|\n|\n|\nthis._buttons = []; |\n|\nthis._data; |\n|\nthis._currentSelectionIndex = -1; |\n|\nthis._currentSectionIndex = -1; |\n|\nthis._params = {}; |\n|\n} |\n|\n|\n|\nsetVideo(path, options = {}) { |\n|\nif (!path) throw new Error('Url or buffer needed'); |\n|\nBuffer.isBuffer(path) ? (this._data = { video: path, ...options }) : (this._data = { video: { url: path }, ...options }); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetImage(path, options = {}) { |\n|\nif (!path) throw new Error('Url or buffer needed'); |\n|\nBuffer.isBuffer(path) ? (this._data = { image: path, ...options }) : (this._data = { image: { url: path }, ...options }); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetDocument(path, options = {}) { |\n|\nif (!path) throw new Error('Url or buffer needed'); |\n|\nBuffer.isBuffer(path) ? (this._data = { document: path, ...options }) : (this._data = { document: { url: path }, ...options }); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetMedia(obj) { |\n|\nif (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { |\n|\nthrow new TypeError('Media must be a plain object'); |\n|\n} |\n|\n|\n|\nthis._data = obj; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nclearButtons() { |\n|\nthis._buttons = []; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetParams(obj) { |\n|\nthis._params = obj; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddButton(name, params) { |\n|\nthis._buttons.push({ |\n|\nname, |\n|\nbuttonParamsJson: typeof params === 'string' ? params : JSON.stringify(params), |\n|\n}); |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\nmakeRow(header = '', title = '', description = '', id = crypto.randomUUID()) { |\n|\nif (this._currentSelectionIndex === -1 || this._currentSectionIndex === -1) { |\n|\nthrow new Error('You need to create a selection and a section first'); |\n|\n} |\n|\nconst buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson); |\n|\nbuttonParams.sections[this._currentSectionIndex].rows.push({ header, title, description, id }); |\n|\nthis._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nmakeSections(title = '', highlight_label = '') { |\n|\nif (this._currentSelectionIndex === -1) { |\n|\nthrow new Error('You need to create a selection first'); |\n|\n} |\n|\nconst buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson); |\n|\nbuttonParams.sections.push({ title, highlight_label, rows: [] }); |\n|\nthis._currentSectionIndex = buttonParams.sections.length - 1; |\n|\nthis._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddSelection(title) { |\n|\nthis._buttons.push({ name: 'single_select', buttonParamsJson: JSON.stringify({ title, sections: [] }) }); |\n|\nthis._currentSelectionIndex = this._buttons.length - 1; |\n|\nthis._currentSectionIndex = -1; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddReply(display_text = '', id = crypto.randomUUID()) { |\n|\nthis._buttons.push({ name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text, id }) }); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddCall(display_text = '', id = crypto.randomUUID()) { |\n|\nthis._buttons.push({ |\n|\nname: 'cta_call', |\n|\nbuttonParamsJson: JSON.stringify({ |\n|\ndisplay_text, |\n|\nid, |\n|\n}), |\n|\n}); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddReminder(display_text = '', id = crypto.randomUUID()) { |\n|\nthis._buttons.push({ |\n|\nname: 'cta_reminder', |\n|\nbuttonParamsJson: JSON.stringify({ |\n|\ndisplay_text, |\n|\nid, |\n|\n}), |\n|\n}); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddCancelReminder(display_text = '', id = crypto.randomUUID()) { |\n|\nthis._buttons.push({ |\n|\nname: 'cta_cancel_reminder', |\n|\nbuttonParamsJson: JSON.stringify({ |\n|\ndisplay_text, |\n|\nid, |\n|\n}), |\n|\n}); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddAddress(display_text = '', id = crypto.randomUUID()) { |\n|\nthis._buttons.push({ |\n|\nname: 'address_message', |\n|\nbuttonParamsJson: JSON.stringify({ |\n|\ndisplay_text, |\n|\nid, |\n|\n}), |\n|\n}); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddLocation() { |\n|\nthis._buttons.push({ |\n|\nname: 'send_location', |\n|\nbuttonParamsJson: '', |\n|\n}); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddUrl(display_text = '', url = '', webview_interaction = false) { |\n|\nthis._buttons.push({ |\n|\nname: 'cta_url', |\n|\nbuttonParamsJson: JSON.stringify({ |\n|\ndisplay_text, |\n|\nurl, |\n|\nwebview_interaction, |\n|\n}), |\n|\n}); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddCopy(display_text = '', copy_code = '', id = crypto.randomUUID()) { |\n|\nthis._buttons.push({ |\n|\nname: 'cta_copy', |\n|\nbuttonParamsJson: JSON.stringify({ |\n|\ndisplay_text, |\n|\ncopy_code, |\n|\nid, |\n|\n}), |\n|\n}); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nstatic paramsList = { |\n|\nlimited_time_offer: { |\n|\ntext: 'string', |\n|\nurl: 'string', |\n|\ncopy_code: 'string', |\n|\nexpiration_time: 'number', |\n|\n}, |\n|\nbottom_sheet: { |\n|\nin_thread_buttons_limit: 'number', |\n|\ndivider_indices: ['number'], |\n|\nlist_title: 'string', |\n|\nbutton_title: 'string', |\n|\n}, |\n|\ntap_target_configuration: { |\n|\ntitle: 'string', |\n|\ndescription: 'string', |\n|\ncanonical_url: 'string', |\n|\ndomain: 'string', |\n|\nbuttonIndex: 'number', |\n|\n}, |\n|\n}; |\n|\n|\n|\nasync toCard() { |\n|\nreturn { |\n|\nbody: { |\n|\ntext: this._body, |\n|\n}, |\n|\nfooter: { |\n|\ntext: this._footer, |\n|\n}, |\n|\nheader: { |\n|\ntitle: this._title, |\n|\nsubtitle: this._subtitle, |\n|\nhasMediaAttachment: !!this._data, |\n|\n...(this._data ? await prepareWAMessageMedia(this._data, { upload: this.#client.waUploadToServer }) : {}), |\n|\n}, |\n|\nnativeFlowMessage: { |\n|\nmessageParamsJson: JSON.stringify(this._params), |\n|\nbuttons: this._buttons, |\n|\n}, |\n|\n}; |\n|\n} |\n|\n|\n|\nasync build(jid, { ...options } = {}) { |\n|\nconst message = await this.toCard(); |\n|\n|\n|\nreturn generateWAMessageFromContent( |\n|\njid, |\n|\n{ |\n|\n...this._extraPayload, |\n|\ninteractiveMessage: { |\n|\n...message, |\n|\ncontextInfo: this._contextInfo, |\n|\n}, |\n|\n}, |\n|\n{ ...options } |\n|\n); |\n|\n} |\n|\n|\n|\nasync send(jid, { ...options } = {}) { |\n|\nconst msg = await this.build(jid, options); |\n|\n|\n|\nawait this.#client.relayMessage(msg.key.remoteJid, msg.message, { |\n|\nmessageId: msg.key.id, |\n|\nadditionalNodes: [ |\n|\n{ |\n|\ntag: 'biz', |\n|\nattrs: {}, |\n|\ncontent: [ |\n|\n{ |\n|\ntag: 'interactive', |\n|\nattrs: { type: 'native_flow', v: '1' }, |\n|\ncontent: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }], |\n|\n}, |\n|\n], |\n|\n}, |\n|\n], |\n|\n...options, |\n|\n}); |\n|\nreturn msg; |\n|\n} |\n|\n} |\n|\n|\n|\nclass ButtonV2 extends BaseBuilder { |\n|\n#client; |\n|\n|\n|\nconstructor(client) { |\n|\nsuper(); |\n|\nif (!client) { |\n|\nthrow new Error('Socket is required'); |\n|\n} |\n|\n|\n|\nthis.#client = client; |\n|\nthis._image; |\n|\nthis._data; |\n|\nthis._buttons = []; |\n|\n} |\n|\n|\n|\naddButton(displayText = '', buttonId = crypto.randomUUID()) { |\n|\nthis._buttons.push({ buttonId, buttonText: { displayText }, type: 1 }); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddRawButton(obj) { |\n|\nif (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { |\n|\nthrow new TypeError('Buttons must be a plain object'); |\n|\n} |\n|\n|\n|\nthis._buttons.push(obj); |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetThumbnail(path) { |\n|\nif (!path) throw new Error('Url or buffer needed'); |\n|\nthis._image = path; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nsetMedia(obj) { |\n|\nif (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { |\n|\nthrow new TypeError('Media must be a plain object'); |\n|\n} |\n|\n|\n|\nthis._data = obj; |\n|\nreturn this; |\n|\n} |\n|\n|\n|\nasync build(jid, { ...options } = {}) { |\n|\nlet _thumbnail = this._image |\n|\n? await sharp(Buffer.isBuffer(this._image) ? this._image : await fetchBuffer(this._image, {}, { silent: true })) |\n|\n.resize(300, 300) |\n|\n.png() |\n|\n.toBuffer() |\n|\n: null; |\n|\nconst msg = generateWAMessageFromContent( |\n|\njid, |\n|\n{ |\n|\n...this._extraPayload, |\n|\nbuttonsMessage: { |\n|\ncontentText: this._body, |\n|\nfooterText: this._footer, |\n|\n...(this._data |\n|\n? this._data |\n|\n: { |\n|\nheaderType: 6, |\n|\nlocationMessage: { |\n|\njpegThumbnail: _thumbnail, |\n|\n}, |\n|\n}), |\n|\nviewOnce: true, |\n|\ncontextInfo: this._contextInfo, |\n|\nbuttons: [...this._buttons], |\n|\n}, |\n|\n}, |\n|\n{ ...options } |\n|\n); |\n|\nreturn msg; |\n|\n} |\n|\n|\n|\nasync send(jid, { ...options } = {}) { |\n|\nconst msg = await this.build(jid, options); |\n|\n|\n|\nawait this.#client.relayMessage(msg.key.remoteJid, msg.message, { |\n|\nmessageId: msg.key.id, |\n|\nadditionalNodes: [ |\n|\n{ |\n|\ntag: 'biz', |\n|\nattrs: {}, |\n|\ncontent: [ |\n|\n{ |\n|\ntag: 'interactive', |\n|\nattrs: { type: 'native_flow', v: '1' }, |\n|\ncontent: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }], |\n|\n}, |\n|\n], |\n|\n}, |\n|\n], |\n|\n...options, |\n|\n}); |\n|\nreturn msg; |\n|\n} |\n|\n} |\n|\n|\n|\nclass Carousel extends BaseBuilder { |\n|\n#client; |\n|\nconstructor(client) { |\n|\nsuper(); |\n|\nif (!client) { |\n|\nthrow new Error('Socket is required'); |\n|\n} |\n|\n|\n|\nthis.#client = client; |\n|\nthis._cards = []; |\n|\n} |\n|\n|\n|\naddCard(card) { |\n|\nif (Array.isArray(card)) { |\n|\nthis._cards.push(...card); |\n|\n} else { |\n|\nthis._cards.push(card); |\n|\n} |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\nbuild(jid, { ...options }) { |\n|\nreturn generateWAMessageFromContent( |\n|\njid, |\n|\n{ |\n|\n...this._extraPayload, |\n|\ninteractiveMessage: { |\n|\nheader: { |\n|\nhasMediaAttachment: false, |\n|\n}, |\n|\nbody: { text: this._body }, |\n|\nfooter: { text: this._footer }, |\n|\ncontextInfo: this._contextInfo, |\n|\ncarouselMessage: { |\n|\ncards: this._cards, |\n|\n}, |\n|\n}, |\n|\n}, |\n|\n{ ...options } |\n|\n); |\n|\n} |\n|\n|\n|\nasync send(jid, { ...options } = {}) { |\n|\nconst msg = this.build(jid, options); |\n|\n|\n|\nawait this.#client.relayMessage(msg.key.remoteJid, msg.message, { |\n|\nmessageId: msg.key.id, |\n|\nadditionalNodes: [ |\n|\n{ |\n|\ntag: 'biz', |\n|\nattrs: {}, |\n|\ncontent: [ |\n|\n{ |\n|\ntag: 'interactive', |\n|\nattrs: { type: 'native_flow', v: '1' }, |\n|\ncontent: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }], |\n|\n}, |\n|\n], |\n|\n}, |\n|\n], |\n|\n...options, |\n|\n}); |\n|\nreturn msg; |\n|\n} |\n|\n} |\n|\n|\n|\nclass AIRich { |\n|\n#client; |\n|\nconstructor(client) { |\n|\nif (!client) { |\n|\nthrow new Error('Socket is required'); |\n|\n} |\n|\n|\n|\nthis.#client = client; |\n|\nthis._submessages = []; |\n|\nthis._sections = []; |\n|\nthis._richResponseSources = []; |\n|\n} |\n|\n|\n|\naddText(text, { hyperlink = true } = {}) { |\n|\nconst extractedHyperlink = hyperlink |\n|\n? extractHyperlink(text) |\n|\n: { |\n|\ntext, |\n|\nhyperlink: [], |\n|\n}; |\n|\n|\n|\nthis._submessages.push({ |\n|\nmessageType: 2, |\n|\nmessageText: hyperlink ? extractedHyperlink.text : text, |\n|\n}); |\n|\n|\n|\nif (extractedHyperlink.hyperlink.length && hyperlink) { |\n|\nthis._sections.push({ |\n|\nview_model: { |\n|\nprimitive: { |\n|\ntext: extractedHyperlink.text, |\n|\ninline_entities: extractedHyperlink.hyperlink.map(({ reference_id, key, text, url }) => ({ |\n|\nkey, |\n|\nmetadata: text?.trim() |\n|\n? { |\n|\ndisplay_name: text, |\n|\nis_trusted: true, |\n|\nurl, |\n|\n__typename: 'GenAIInlineLinkItem', |\n|\n} |\n|\n: { |\n|\nreference_id, |\n|\nreference_url: url, |\n|\nreference_title: url, |\n|\nreference_display_name: url, |\n|\nsources: [], |\n|\n__typename: 'GenAISearchCitationItem', |\n|\n}, |\n|\n})), |\n|\n__typename: 'GenAIMarkdownTextUXPrimitive', |\n|\n}, |\n|\n__typename: 'GenAISingleLayoutViewModel', |\n|\n}, |\n|\n}); |\n|\n} else { |\n|\nthis._sections.push({ |\n|\nview_model: { |\n|\nprimitive: { |\n|\ntext, |\n|\n__typename: 'GenAIMarkdownTextUXPrimitive', |\n|\n}, |\n|\n|\n|\n__typename: 'GenAISingleLayoutViewModel', |\n|\n}, |\n|\n}); |\n|\n} |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddCode(language, code) { |\n|\nconst meta = AIRich.tokenizer(code, language); |\n|\n|\n|\nthis._submessages.push({ |\n|\nmessageType: 5, |\n|\ncodeMetadata: { |\n|\ncodeLanguage: language, |\n|\ncodeBlocks: meta.codeBlock, |\n|\n}, |\n|\n}); |\n|\n|\n|\nthis._sections.push({ |\n|\nview_model: { |\n|\nprimitive: { |\n|\nlanguage, |\n|\ncode_blocks: meta.unified_codeBlock, |\n|\n__typename: 'GenAICodeUXPrimitive', |\n|\n}, |\n|\n__typename: 'GenAISingleLayoutViewModel', |\n|\n}, |\n|\n}); |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddTable(table) { |\n|\nconst meta = AIRich.toTableMetadata(table); |\n|\n|\n|\nthis._submessages.push({ |\n|\nmessageType: 4, |\n|\ntableMetadata: { |\n|\ntitle: meta.title, |\n|\nrows: meta.rows, |\n|\n}, |\n|\n}); |\n|\n|\n|\nthis._sections.push({ |\n|\nview_model: { |\n|\nprimitive: { |\n|\nrows: meta.unified_rows, |\n|\n__typename: 'GenATableUXPrimitive', |\n|\n}, |\n|\n__typename: 'GenAISingleLayoutViewModel', |\n|\n}, |\n|\n}); |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddSource(sources = []) { |\n|\nconst source = sources.map(([profile_url, url, text]) => ({ |\n|\nsource_type: 'THIRD_PARTY', |\n|\nsource_display_name: text, |\n|\nsource_subtitle: 'AI', |\n|\nsource_url: url, |\n|\nfavicon: { |\n|\nurl: profile_url, |\n|\nmime_type: 'image/jpeg', |\n|\nwidth: 16, |\n|\nheight: 16, |\n|\n}, |\n|\n})); |\n|\n|\n|\nthis._sections.push({ |\n|\nview_model: { |\n|\nprimitive: { |\n|\nsources: source, |\n|\n__typename: 'GenAISearchResultPrimitive', |\n|\n}, |\n|\n__typename: 'GenAISingleLayoutViewModel', |\n|\n}, |\n|\n}); |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddReels(reelsItems = []) { |\n|\nthis._submessages.push({ |\n|\nmessageType: 9, |\n|\ncontentItemsMetadata: { |\n|\ncontentType: 1, |\n|\nitemsMetadata: reelsItems.map((item) => ({ |\n|\nreelItem: { |\n|\ntitle: item.title, |\n|\nprofileIconUrl: item.profileIconUrl, |\n|\nthumbnailUrl: item.thumbnailUrl, |\n|\nvideoUrl: item.videoUrl, |\n|\n}, |\n|\n})), |\n|\n}, |\n|\n}); |\n|\n|\n|\nreelsItems.forEach((item, idx) => { |\n|\nthis._richResponseSources.push({ |\n|\nprovider: 'UNKNOWN', |\n|\nthumbnailCDNURL: item.thumbnailUrl, |\n|\nsourceProviderURL: item.videoUrl, |\n|\nsourceQuery: '', |\n|\nfaviconCDNURL: item.profileIconUrl, |\n|\ncitationNumber: idx + 1, |\n|\nsourceTitle: item.title, |\n|\n}); |\n|\n}); |\n|\n|\n|\nthis._sections.push({ |\n|\nview_model: { |\n|\nprimitives: reelsItems.map((item) => ({ |\n|\nreels_url: item.videoUrl, |\n|\nthumbnail_url: item.thumbnailUrl, |\n|\ncreator: item.title, |\n|\navatar_url: item.profileIconUrl, |\n|\nreels_title: item.reels_title, |\n|\nlikes_count: 0, |\n|\nshares_count: 0, |\n|\nview_count: 0, |\n|\nreel_source: 'IG', |\n|\nis_verified: item.is_verified, |\n|\n__typename: 'GenAIReelPrimitive', |\n|\n})), |\n|\n__typename: 'GenAIHScrollLayoutViewModel', |\n|\n}, |\n|\n}); |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\naddImage(imageUrl) { |\n|\nconst imageUrls = Array.isArray(imageUrl) |\n|\n? imageUrl.map((url) => ({ |\n|\nimagePreviewUrl: url, |\n|\nimageHighResUrl: url, |\n|\nsourceUrl: 'https://google.com', |\n|\n})) |\n|\n: [ |\n|\n{ |\n|\nimagePreviewUrl: imageUrl, |\n|\nimageHighResUrl: imageUrl, |\n|\nsourceUrl: 'https://google.com', |\n|\n}, |\n|\n]; |\n|\n|\n|\nthis._submessages.push({ |\n|\nmessageType: 1, |\n|\ngridImageMetadata: { |\n|\ngridImageUrl: { |\n|\nimagePreviewUrl: Array.isArray(imageUrl) ? imageUrl[0] : imageUrl, |\n|\n}, |\n|\nimageUrls, |\n|\n}, |\n|\n}); |\n|\n|\n|\nimageUrls.forEach(({ imagePreviewUrl }) => { |\n|\nthis._sections.push({ |\n|\nview_model: { |\n|\nprimitive: { |\n|\nmedia: { |\n|\nurl: imagePreviewUrl, |\n|\nmime_type: 'image/jpeg', |\n|\n}, |\n|\nimagine_type: 3, |\n|\nstatus: { |\n|\nstatus: 'READY', |\n|\n}, |\n|\n__typename: 'GenAIImaginePrimitive', |\n|\n}, |\n|\n__typename: 'GenAISingleLayoutViewModel', |\n|\n}, |\n|\n}); |\n|\n}); |\n|\n|\n|\nreturn this; |\n|\n} |\n|\n|\n|\nbuild({ forwarded = true, includesUnifiedResponse = true, ...options } = {}) { |\n|\nconst contextInfo = forwarded |\n|\n? { |\n|\nforwardingScore: 1, |\n|\nisForwarded: true, |\n|\nforwardedAiBotMessageInfo: { botJid: '0@bot' }, |\n|\nforwardOrigin: 4, |\n|\n} |\n|\n: {}; |\n|\n|\n|\nreturn { |\n|\nmessageContextInfo: { |\n|\ndeviceListMetadata: {}, |\n|\ndeviceListMetadataVersion: 2, |\n|\nbotMetadata: { |\n|\npluginMetadata: {}, |\n|\nrichResponseSourcesMetadata: { sources: this._richResponseSources }, |\n|\n}, |\n|\n}, |\n|\nbotForwardedMessage: { |\n|\nmessage: { |\n|\nrichResponseMessage: { |\n|\nmessageType: 1, |\n|\nsubmessages: this._submessages, |\n|\nunifiedResponse: { |\n|\ndata: includesUnifiedResponse ? Buffer.from(JSON.stringify({ response_id: crypto.randomUUID(), sections: this._sections })).toString('base64') : '', |\n|\n}, |\n|\ncontextInfo, |\n|\n}, |\n|\n}, |\n|\n}, |\n|\n}; |\n|\n} |\n|\n|\n|\nasync send(jid, { forwarded, includesUnifiedResponse, ...options } = {}) { |\n|\nconst msg = this.build({ forwarded, includesUnifiedResponse, ...options }); |\n|\n|\n|\nreturn await this.#client.relayMessage(jid, msg, { ...options }); |\n|\n} |\n|\n|\n|\nstatic tokenizer(code, lang = 'javascript') { |\n|\nconst keywordsMap = { |\n|\njavascript: new Set([ |\n|\n'break', |\n|\n'case', |\n|\n'catch', |\n|\n'continue', |\n|\n'debugger', |\n|\n'delete', |\n|\n'do', |\n|\n'else', |\n|\n'finally', |\n|\n'for', |\n|\n'function', |\n|\n'if', |\n|\n'in', |\n|\n'instanceof', |\n|\n'new', |\n|\n'return', |\n|\n'switch', |\n|\n'this', |\n|\n'throw', |\n|\n'try', |\n|\n'typeof', |\n|\n'var', |\n|\n'void', |\n|\n'while', |\n|\n'with', |\n|\n'true', |\n|\n'false', |\n|\n'null', |\n|\n'undefined', |\n|\n'class', |\n|\n'const', |\n|\n'let', |\n|\n'super', |\n|\n'extends', |\n|\n'export', |\n|\n'import', |\n|\n'yield', |\n|\n'static', |\n|\n'constructor', |\n|\n'async', |\n|\n'await', |\n|\n'get', |\n|\n'set', |\n|\n]), |\n|\n}; |\n|\n|\n|\nconst TYPE_MAP = { |\n|\n0: 'DEFAULT', |\n|\n1: 'KEYWORD', |\n|\n2: 'METHOD', |\n|\n3: 'STR', |\n|\n4: 'NUMBER', |\n|\n5: 'COMMENT', |\n|\n}; |\n|\n|\n|\nconst keywords = keywordsMap[lang] || new Set(); |\n|\nconst tokens = []; |\n|\n|\n|\nlet i = 0; |\n|\n|\n|\nconst push = (content, type) => { |\n|\nif (!content) return; |\n|\nconst last = tokens[tokens.length - 1]; |\n|\nif (last && last.highlightType === type) last.codeContent += content; |\n|\nelse tokens.push({ codeContent: content, highlightType: type }); |\n|\n}; |\n|\n|\n|\nwhile (i < code.length) { |\n|\nconst c = code[i]; |\n|\n|\n|\nif (/\\s/.test(c)) { |\n|\nlet s = i; |\n|\nwhile (i < code.length && /\\s/.test(code[i])) i++; |\n|\npush(code.slice(s, i), 0); |\n|\ncontinue; |\n|\n} |\n|\n|\n|\nif (c === '/' && code[i + 1] === '/') { |\n|\nlet s = i; |\n|\ni += 2; |\n|\nwhile (i < code.length && code[i] !== '\\n') i++; |\n|\npush(code.slice(s, i), 5); |\n|\ncontinue; |\n|\n} |\n|\n|\n|\nif (c === '\"' || c === \"'\" || c === '`') { |\n|\nlet s = i; |\n|\nconst q = c; |\n|\ni++; |\n|\nwhile (i < code.length) { |\n|\nif (code[i] === '\\\\' && i + 1 < code.length) i += 2; |\n|\nelse if (code[i] === q) { |\n|\ni++; |\n|\nbreak; |\n|\n} else i++; |\n|\n} |\n|\npush(code.slice(s, i), 3); |\n|\ncontinue; |\n|\n} |\n|\n|\n|\nif (/[0-9]/.test(c)) { |\n|\nlet s = i; |\n|\nwhile (i < code.length && /[0-9.]/.test(code[i])) i++; |\n|\npush(code.slice(s, i), 4); |\n|\ncontinue; |\n|\n} |\n|\n|\n|\nif (/[a-zA-Z_$]/.test(c)) { |\n|\nlet s = i; |\n|\nwhile (i < code.length && /[a-zA-Z0-9_$]/.test(code[i])) i++; |\n|\nconst word = code.slice(s, i); |\n|\n|\n|\nlet type = 0; |\n|\nif (keywords.has(word)) type = 1; |\n|\nelse { |\n|\nlet j = i; |\n|\nwhile (j < code.length && /\\s/.test(code[j])) j++; |\n|\nif (code[j] === '(') type = 2; |\n|\n} |\n|\n|\n|\npush(word, type); |\n|\ncontinue; |\n|\n} |\n|\n|\n|\npush(c, 0); |\n|\ni++; |\n|\n} |\n|\n|\n|\nreturn { |\n|\ncodeBlock: tokens, |\n|\nunified_codeBlock: tokens.map((t) => ({ |\n|\ncontent: t.codeContent, |\n|\ntype: TYPE_MAP[t.highlightType], |\n|\n})), |\n|\n}; |\n|\n} |\n|\n|\n|\nstatic toTableMetadata(arr) { |\n|\nif (!Array.isArray(arr) || arr.length < 2) throw new Error('Format tabel ngawur'); |\n|\n|\n|\nconst [header, ...rows] = arr; |\n|\n|\n|\nconst maxLen = Math.max(header.length, ...rows.map((r) => r.length)); |\n|\n|\n|\nconst normalize = (r) => [...r, ...Array(maxLen - r.length).fill('')]; |\n|\n|\n|\nconst unified_rows = [ |\n|\n{ |\n|\nis_header: true, |\n|\ncells: normalize(header), |\n|\n}, |\n|\n...rows.map((r) => ({ |\n|\nis_header: false, |\n|\ncells: normalize(r), |\n|\n})), |\n|\n]; |\n|\n|\n|\nconst rowsMeta = unified_rows.map((r) => ({ |\n|\nitems: r.cells, |\n|\n...(r.is_header ? { isHeading: true } : {}), |\n|\n})); |\n|\n|\n|\nreturn { |\n|\ntitle: '', |\n|\nrows: rowsMeta, |\n|\nunified_rows, |\n|\n}; |\n|\n} |\n|\n} |\n|\n|\n|\nexport { VERSION, Button, ButtonV2, Carousel, AIRich }; |", "url": "https://wpnews.pro/news/messagebuilderv4-3-js", "canonical_source": "https://gist.github.com/ValdazGT/fb6c9126473fb9d726889683caaaf2f0", "published_at": "2026-05-25 08:42:43+00:00", "updated_at": "2026-05-28 04:53:58.042905+00:00", "lang": "en", "topics": ["ai-tools"], "entities": ["Nixel", "Baileys"], "alternates": {"html": "https://wpnews.pro/news/messagebuilderv4-3-js", "markdown": "https://wpnews.pro/news/messagebuilderv4-3-js.md", "text": "https://wpnews.pro/news/messagebuilderv4-3-js.txt", "jsonld": "https://wpnews.pro/news/messagebuilderv4-3-js.jsonld"}}