@codexverified/baileys 2.7.9 → 2.8.11

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/README.md CHANGED
@@ -4,14 +4,14 @@
4
4
 
5
5
  `@codexverified/baileys` is a Node.js and TypeScript library for building WhatsApp integrations over the Baileys protocol. It provides a familiar socket-based API together with media handling, authentication helpers, newsletter operations, interactive messages, rich content utilities, and account-management features.
6
6
 
7
- The project is developed and maintained by **Codex** with an emphasis on readable source code, explicit behavior, maintainable interfaces, and practical production use.
7
+ The project is developed and maintained by **Codex** with an emphasis on readable source code, explicit behavior, maintainable interfaces,and practical production use.
8
8
 
9
9
  ## Project Status
10
10
 
11
11
  | Property | Value |
12
12
  | --- | --- |
13
13
  | Package | `@codexverified/baileys` |
14
- | Version | `2.7.5` |
14
+ | Version | `2.8.11` |
15
15
  | Runtime | Node.js 20 or newer |
16
16
  | Module format | ESM with CommonJS compatibility where supported |
17
17
  | Type declarations | Included |
@@ -26,10 +26,10 @@ Install the published package when it is available in the npm registry:
26
26
  npm install @codexverified/baileys
27
27
  ```
28
28
 
29
- To install the current local build from the provided archive, place `codex-baileys-2.7.5.tgz` in your project directory and run:
29
+ To install the current local build from the provided archive, place `codex-baileys-2.8.11.tgz` in your project directory and run:
30
30
 
31
31
  ```bash
32
- npm install ./codex-baileys-2.7.5.tgz
32
+ npm install ./codex-baileys-2.8.11.tgz
33
33
  ```
34
34
 
35
35
  The local archive installs under the package name `@codexverified/baileys`, so application imports remain the same in both cases.
@@ -178,11 +178,104 @@ The package displays the following startup identity when a socket is created:
178
178
 
179
179
  ```text
180
180
  CODEX TECHNOLOGY
181
- A premium Baileys developed and built by Dev Codex
181
+ A premium Baileys developed and built by codex
182
182
  ```
183
183
 
184
184
  Generated message identifiers use the `CODEX` marker. This branding is informational and does not change the WhatsApp protocol or the message transport format.
185
185
 
186
+ ## CODEX Rich Menu and Interactive Helpers
187
+
188
+ The following helpers are available on a socket created with `makeWASocket`. They use the existing message relay and do not change the normal `sendMessage` behavior.
189
+
190
+ ### Spoiler media
191
+
192
+ Use `spoiler: true` when sending supported media. The WhatsApp client controls the visual spoiler and download presentation.
193
+
194
+ ```javascript
195
+ await sock.sendMessage(jid, {
196
+ video: { url: './media/clip.mp4' },
197
+ caption: 'Spoiler media',
198
+ spoiler: true
199
+ })
200
+ ```
201
+
202
+ ### Experimental Gen4 rich menu
203
+
204
+ `richMenu` creates a Meta AI-style rich-response card with a header, optional image, card sections, stable button IDs, optional toast metadata, disclaimers, carousel or row layout, and a footer URL or image. Buttons may be strings or objects. String buttons receive generated tool IDs; object buttons preserve their supplied `id`. Set `body.carousel: true` for horizontal carousel layout, or leave it false for row layout. On some WhatsApp versions, a button tap may arrive as ordinary message text or through another interactive response envelope, so receiving code should handle both the ID and visible label.
205
+
206
+ ```javascript
207
+ await sock.richMenu(jid, {
208
+ header: {
209
+ title: 'Rich Menu',
210
+ image: { url: 'https://example.com/menu.jpg', mime_type: 'image/jpeg' }
211
+ },
212
+ body: {
213
+ row: true,
214
+ carousel: false,
215
+ cards: [{
216
+ title: 'Menu 1',
217
+ toast: 'Menu 1 selected',
218
+ buttons: ['menu2', 'menu3', 'rich3']
219
+ }, {
220
+ title: 'Menu 2',
221
+ buttons: [
222
+ { id: 'test', text: 'test', toast: 'Test selected' },
223
+ { id: 'me', label: 'me' },
224
+ { id: 'rich2', text: 'rich2' }
225
+ ]
226
+ }]
227
+ },
228
+ footer: {
229
+ text: 'Telegram channel',
230
+ url: 'https://t.me/example',
231
+ image: { url: 'https://example.com/footer.jpg', mime_type: 'image/jpeg' }
232
+ }
233
+ })
234
+ ```
235
+
236
+ ### Status, button grids, tables, and Flows
237
+
238
+ ```javascript
239
+ await sock.sendStatus({ text: 'New status' }, {
240
+ statusJidList: ['1234567890@s.whatsapp.net']
241
+ })
242
+
243
+ await sock.sendStatusMentions({ text: 'Mentioned status' }, [
244
+ '1234567890@s.whatsapp.net',
245
+ '9876543210@s.whatsapp.net'
246
+ ])
247
+
248
+ await sock.sendRichButtonGrid(jid, {
249
+ text: 'Choose an option',
250
+ cards: [{
251
+ title: 'Actions',
252
+ buttons: [
253
+ { id: 'action_one', text: 'Action one' },
254
+ { id: 'action_two', text: 'Action two' }
255
+ ]
256
+ }]
257
+ })
258
+
259
+ await sock.sendInteractiveTable(jid, {
260
+ title: 'Plans',
261
+ headers: ['Name', 'Price'],
262
+ rows: [['Basic', '$5'], ['Pro', '$10']],
263
+ buttons: [{ id: 'choose_pro', text: 'Choose Pro' }],
264
+ footer: 'Select a plan'
265
+ })
266
+
267
+ await sock.sendWhatsAppFlow(jid, {
268
+ text: 'Open the form',
269
+ flowId: 'your-flow-id',
270
+ flowToken: 'your-flow-token',
271
+ flowName: 'your-flow-name',
272
+ flowAction: 'navigate',
273
+ flowActionPayload: { screen: 'WELCOME' }
274
+ })
275
+ ```
276
+
277
+ These helpers and the rich-menu format are client-dependent experimental features. Use stable IDs and test the receiving message normalization on the WhatsApp versions used by your application.
278
+
186
279
  ## Development
187
280
 
188
281
  Clone or extract the source archive, then install the package dependencies in the project directory:
@@ -23,24 +23,21 @@ import { makeGraphQLSocket } from './graphql.js';
23
23
 
24
24
  // export the last socket layer
25
25
  const makeWASocket = (config) => {
26
- // CODEX branding banner
27
- // Printed once per process when a socket is created.
26
+ // CODEX branding banner. Printed once per process.
28
27
  if (!globalThis.__codexBannerShown) {
29
28
  globalThis.__codexBannerShown = true;
30
- const yellow = '\x1b[93m'; // bright / light yellow
31
- const dim = '\x1b[2m';
29
+ const yellow = '\x1b[93m';
30
+ const blue = '\x1b[94m';
32
31
  const reset = '\x1b[0m';
33
- const logo = [
34
- ' ',
35
- ' ',
36
- ' ',
37
- ' ',
38
- ' ',
39
- ' '
40
- ].join('\\n');
32
+ const width = 41;
33
+ const center = (text) => {
34
+ const pad = Math.max(0, Math.floor((width - text.length) / 2));
35
+ return ' '.repeat(pad) + text;
36
+ };
41
37
  console.log(
42
- '\\n' + yellow + logo + reset + '\\n' +
43
- dim + ' CODEX TECHNOLOGY a premium Baileys developed and built by Dev Codex' + reset + '\\n'
38
+ `\n${yellow}${center('CODEX TECHNOLOGY')}${reset}\n` +
39
+ `${blue}${center('@codexverified/Baileys')}${reset}\n` +
40
+ `${yellow}${center('premium baileys built by codex')}${reset}\n`
44
41
  );
45
42
  }
46
43
  const userExplicitSyncFlag = typeof config?.syncFullHistory === 'boolean';
@@ -11,7 +11,7 @@ import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/
11
11
  import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, resolveTcTokenJid, shouldSendNewTcToken, storeTcTokensFromIqResult } from '../Utils/tc-token-utils.js';
12
12
  import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, getBizBinaryNode, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isJidNewsletter, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET } from '../WABinary/index.js';
13
13
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
14
- import { captureUnifiedResponse, generateCodeBlockContent, generateLatexContent, generateListContent, generateTableContent, generateUnifiedResponseContent } from '../Utils/message-composer.js';
14
+ import { captureUnifiedResponse, generateButtonGridContent, generateCodeBlockContent, generateLatexContent, generateListContent, generateRichMenuContent, generateTableContent, generateUnifiedResponseContent } from '../Utils/message-composer.js';
15
15
  import { Baron } from './interactive-handler.js';
16
16
  import { collectMetaAIBotParticipantJids, isMetaAIBotResponse, META_AI_BOT_JID } from './aigroups.js';
17
17
  import { makeUsernameSocket } from './username.js';
@@ -1203,6 +1203,42 @@ export const makeMessagesSocket = (config) => {
1203
1203
  sendBulkReactions, // NEW: Bulk reaction helper
1204
1204
  sendAsMimic,
1205
1205
  sendStatusMention: async (content, jids = []) => baron2.sendStatusWhatsApp(content, jids),
1206
+ sendStatusMentions: async (content, jids = [], options = {}) => {
1207
+ if (!Array.isArray(jids) || jids.length === 0) throw new Boom('sendStatusMentions requires at least one recipient JID', { statusCode: 400 });
1208
+ return sock.sendMessage(STATUS_JID, { ...content, status: true }, { ...options, broadcast: true, statusJidList: normalizeStatusJidList(jids) });
1209
+ },
1210
+ sendStatus: async (content, options = {}) => {
1211
+ const recipients = normalizeStatusJidList(options.statusJidList || content?.statusJidList);
1212
+ return sock.sendMessage(STATUS_JID, { ...content, status: true }, { ...options, broadcast: true, statusJidList: recipients });
1213
+ },
1214
+ richMenu: async (jid, content = {}, options = {}) => {
1215
+ if (!jid) throw new Boom('richMenu requires a target JID', { statusCode: 400 });
1216
+ const message = generateRichMenuContent(content, options.quoted, options);
1217
+ const fullMsg = await generateWAMessageFromContent(jid, message, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
1218
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, statusJidList: options.statusJidList });
1219
+ return fullMsg;
1220
+ },
1221
+ sendRichButtonGrid: async (jid, grid, options = {}) => {
1222
+ const message = generateButtonGridContent(grid, options.quoted, options);
1223
+ const fullMsg = await generateWAMessageFromContent(jid, message, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
1224
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata });
1225
+ return fullMsg;
1226
+ },
1227
+ sendInteractiveTable: async (jid, table, options = {}) => {
1228
+ const { title = '', headers = [], rows = [], image, buttons = [], footer } = table || {};
1229
+ if (!Array.isArray(headers) || !Array.isArray(rows) || !Array.isArray(buttons)) throw new Boom('sendInteractiveTable expects headers, rows, and buttons arrays', { statusCode: 400 });
1230
+ const lines = [title, headers.length ? `| ${headers.map(String).join(' | ')} |` : '', headers.length ? `| ${headers.map(() => '---').join(' | ')} |` : '', ...rows.map(row => `| ${(Array.isArray(row) ? row : [row]).map(value => String(value ?? '')).join(' | ')} |`)].filter(Boolean);
1231
+ return sock.sendMessage(jid, { ...(image ? { image, caption: lines.join('\\n') } : { text: lines.join('\\n') }), buttons, ...(footer ? { footer } : {}) }, options);
1232
+ },
1233
+ sendWhatsAppFlow: async (jid, flow = {}, options = {}) => {
1234
+ const { text, footer, image, caption, flowId, flowToken, flowName = 'flow', flowAction = 'navigate', flowActionPayload = {} } = flow;
1235
+ if (!flowId || !flowToken) throw new Boom('sendWhatsAppFlow requires flowId and flowToken', { statusCode: 400 });
1236
+ const button = {
1237
+ name: 'flow',
1238
+ buttonParamsJson: JSON.stringify({ flow_id: String(flowId), flow_token: String(flowToken), flow_name: String(flowName), flow_action: String(flowAction), flow_action_payload: flowActionPayload }),
1239
+ };
1240
+ return sock.sendMessage(jid, { ...(image ? { image, caption: caption || text || flowId } : { text: text || flowId }), ...(footer ? { footer } : {}), nativeFlow: [button] }, options);
1241
+ },
1206
1242
  sendTable: async (jid, title, headers, rows, quoted, options = {}) => {
1207
1243
  const { message, messageId } = generateTableContent(title, headers, rows, quoted, options);
1208
1244
  await relayMessage(jid, message, { messageId });
@@ -465,3 +465,114 @@ export const generateRichMessageContent = (submessages, quoted, options) => {
465
465
  messageId: generateMessageIDV2()
466
466
  };
467
467
  };
468
+
469
+
470
+ const richMenuToolId = () => generateMessageIDV2();
471
+
472
+ const richMenuMedia = (image, inline = false, padding = 4) => {
473
+ if (!image?.url) return null;
474
+ const media = {
475
+ __typename: 'GenAIMediaItem',
476
+ mime_type: image.mime_type || image.mimeType || 'image/png',
477
+ url: image.url,
478
+ url_fallback: image.url,
479
+ width: image.width || (inline ? 500 : undefined),
480
+ height: image.height || (inline ? 500 : undefined),
481
+ expiration_timestamp_ms: Date.now() + 86400000,
482
+ };
483
+ if (inline) return {
484
+ __typename: 'GenAIMarkdownTextUXPrimitive',
485
+ text: '{{header}}.{{/header}}',
486
+ inline_entities: [{
487
+ __typename: 'GenAITextInlineEntity',
488
+ key: 'header',
489
+ metadata: {
490
+ __typename: 'GenAILatexItem', latex_expression: '.', font_height: 24,
491
+ padding, latex_image: media,
492
+ },
493
+ }],
494
+ };
495
+ return { __typename: 'GenAIImagePrimitive', preview_image: media, full_image: media };
496
+ };
497
+
498
+ const richMenuButton = (button, toast = '') => {
499
+ const isString = typeof button === 'string';
500
+ const label = isString ? button : (button?.text || button?.label || button?.id || 'Option');
501
+ return {
502
+ label: String(label), state: 'PENDING', kind: 'OTHER',
503
+ tool_call_id: !isString && button?.id != null ? String(button.id) : richMenuToolId(),
504
+ toast: {
505
+ label: !isString && button?.toast != null ? String(button.toast) : String(toast || ''),
506
+ __typename: 'GenAIExtWidgetToast',
507
+ },
508
+ __typename: 'GenAI3PExtWidgetCTA',
509
+ };
510
+ };
511
+
512
+ export const generateRichMenuContent = (content = {}, quoted, options = {}) => {
513
+ const header = content.header || {};
514
+ const body = content.body || {};
515
+ const footer = content.footer || {};
516
+ const sections = [];
517
+ if (header.title) sections.push({ __typename: 'GenAIUnifiedResponseSection', view_model: {
518
+ __typename: 'GenAISingleLayoutViewModel', primitive: { __typename: 'FOATextPrimitive', text: `# ${String(header.title)}` },
519
+ } });
520
+ const headerImage = richMenuMedia(header.image, Boolean(header.image?.inline));
521
+ if (headerImage) sections.push({ __typename: 'GenAIUnifiedResponseSection', view_model: {
522
+ __typename: 'GenAISingleLayoutViewModel', primitive: headerImage,
523
+ } });
524
+ if (header.disclaimer) sections.push({ __typename: 'GenAIUnifiedResponseSection', view_model: {
525
+ __typename: 'GenAISingleLayoutViewModel', primitive: {
526
+ __typename: 'GenAIMarkdownTextUXPrimitive', text: String(header.disclaimerText || ' '),
527
+ },
528
+ } });
529
+ const cards = Array.isArray(body.cards) ? body.cards : [];
530
+ const buttons = Array.isArray(body.buttons) ? body.buttons : [];
531
+ if (cards.length) sections.push({ __typename: 'GenAIUnifiedResponseSection', view_model: {
532
+ __typename: body.carousel || body.row === false ? 'GenAIHScrollLayoutViewModel' : 'GenAIActionRowLayoutViewModel',
533
+ primitives: cards.map(card => ({
534
+ __typename: 'GenAI3PExtWidgetPrimitive',
535
+ header: { __typename: 'GenAI3PExtWidgetStandardHeader', title: String(card?.title || '') },
536
+ body: {
537
+ __typename: 'GenAI3PExtCalendarEventList',
538
+ ctas: (Array.isArray(card?.buttons) ? card.buttons : []).map(button => richMenuButton(button, card?.toast || body.toast)),
539
+ sections: [],
540
+ },
541
+ })),
542
+ } });
543
+ else if (buttons.length) sections.push({ __typename: 'GenAIUnifiedResponseSection', view_model: {
544
+ __typename: 'GenAISingleLayoutViewModel', primitive: {
545
+ __typename: 'GenAI3PExtWidgetPrimitive',
546
+ header: { __typename: 'GenAI3PExtWidgetStandardHeader', title: String(body.title || '') },
547
+ body: { __typename: 'GenAI3PExtCalendarEventList', ctas: buttons.map(button => richMenuButton(button, body.toast)), sections: [] },
548
+ },
549
+ } });
550
+ if (footer.text || footer.url || footer.image?.url) {
551
+ const footerImage = richMenuMedia(footer.image, true, -5);
552
+ sections.push({ view_model: {
553
+ __typename: 'GenAIActionRowLayoutViewModel', primitives: [
554
+ { __typename: 'GenAIFooterActionPrimitive', cta_text: String(footer.text || 'Open'), cta_type: 'OPEN_URL', cta_url: String(footer.url || '') },
555
+ ...(footerImage ? [footerImage] : []),
556
+ ],
557
+ } });
558
+ }
559
+ const unified = { response_id: options.responseId || richMenuToolId(), sections };
560
+ const richResponseMessage = proto.AIRichResponseMessage.create({
561
+ submessages: [],
562
+ messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
563
+ unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
564
+ contextInfo: { ...buildRichContextInfo(quoted, options), isForwarded: true, forwardingScore: 1, forwardOrigin: 4 },
565
+ });
566
+ return buildBotForwardedMessage([], richResponseMessage.contextInfo, richResponseMessage.unifiedResponse);
567
+ };
568
+
569
+ export const generateButtonGridContent = (grid = {}, quoted, options = {}) => {
570
+ const { text, footer, cards = [] } = grid;
571
+ if (!Array.isArray(cards) || cards.length === 0) throw new Error('sendRichButtonGrid expects at least one card');
572
+ return generateRichMenuContent({
573
+ header: text ? { title: text } : {},
574
+ body: { cards: cards.map(card => ({ ...card, buttons: card.buttons || card.nativeFlow || [] })) },
575
+ footer: footer ? { text: footer } : {},
576
+ }, quoted, options);
577
+ };
578
+
package/lib/index.d.ts CHANGED
@@ -249,6 +249,21 @@ export interface WASocket {
249
249
  managedAccountSyncActivities(): Promise<unknown>;
250
250
  managedAccountUpdatePin(pin: string): Promise<unknown>;
251
251
 
252
+ /** Send a status update to an explicit recipient list. */
253
+ sendStatus(content: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
254
+ /** Send a status update mentioning one or more recipients. */
255
+ sendStatusMention(content: Record<string, unknown>, jids?: string[], options?: Record<string, unknown>): Promise<unknown>;
256
+ /** Alias supporting multiple status recipients. */
257
+ sendStatusMentions(content: Record<string, unknown>, jids?: string[], options?: Record<string, unknown>): Promise<unknown>;
258
+ /** Send an experimental Gen4 / Meta-AI-style rich menu card. */
259
+ richMenu(jid: string, content?: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
260
+ /** Send a rich button-card grid. */
261
+ sendRichButtonGrid(jid: string, grid: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
262
+ /** Send a markdown-style interactive table with buttons. */
263
+ sendInteractiveTable(jid: string, table: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
264
+ /** Send a WhatsApp native flow button. */
265
+ sendWhatsAppFlow(jid: string, flow: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
266
+
252
267
  // ---- GraphQL layer ----
253
268
  setAccessToken(token: string): Promise<void>;
254
269
  setWamoAuth(token: string): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexverified/baileys",
3
- "version": "2.7.9",
3
+ "version": "2.8.11",
4
4
  "description": "CODEX TECHNOLOGY a premium Baileys developed and built by Dev Codex, with Meta compositing, bot planning replay, welcome flow, rich messages, interactive messages, albums, and more.",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  "baileys-fork",
27
27
  "baileys-mod",
28
28
  "codex technology",
29
- "cody ai",
29
+ "codex ai",
30
30
  "bot-planning-replay",
31
31
  "codex",
32
32
  "interactive-messages",
@@ -43,7 +43,7 @@
43
43
  "whatsapp-web"
44
44
  ],
45
45
  "homepage": "https://github.com/codexverified/baileys-",
46
- "author": "Dev Codex",
46
+ "author": "codexverified",
47
47
  "license": "MIT",
48
48
  "dependencies": {
49
49
  "@adiwajshing/keyed-db": "^0.2.4",