@codexverified/baileys 2.10.11 → 2.11.12

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
@@ -1,52 +1,79 @@
1
1
  # @codexverified/baileys
2
2
 
3
- > A premium Baileys package built and maintained by Codex.
4
-
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
-
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
-
9
- ## Project Status
3
+ [![npm version](https://img.shields.io/npm/v/@codexverified/baileys.svg)](https://www.npmjs.com/package/@codexverified/baileys)
4
+ [![node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](#at-a-glance)
5
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](#license-and-maintenance)
6
+ [![types](https://img.shields.io/badge/types-included-blue)](#at-a-glance)
7
+
8
+ > A readable, carefully maintained Baileys distribution for building reliable WhatsApp integrations with codexverified/baileys.
9
+
10
+ `@codexverified/baileys` is a Node.js and TypeScript library for creating WhatsApp automations over the Baileys protocol. It provides a socket-oriented API for authentication, messaging, media, interactive content, rich responses, newsletters, groups, communities, business features, account utilities, and carefully documented extensions.
11
+
12
+ The package is maintained by **Codex** under the **CodexVerified** organization. It is intended for developers who want a practical Baileys foundation with familiar interfaces, public TypeScript declarations, readable source code, explicit behavior, and room for carefully tested improvements.
13
+
14
+ ## Table of contents
15
+
16
+ - [At a glance](#at-a-glance)
17
+ - [Installation](#installation)
18
+ - [Quick start](#quick-start)
19
+ - [CommonJS usage](#commonjs-usage)
20
+ - [Core capabilities](#core-capabilities)
21
+ - [Everyday message usage](#everyday-message-usage)
22
+ - [Rich menu example](#rich-menu-example)
23
+ - [Status, grids, tables, and flows](#status-grids-tables-and-flows)
24
+ - [Authentication and deployment guidance](#authentication-and-deployment-guidance)
25
+ - [Development workflow](#development-workflow)
26
+ - [Recent compatibility updates](#recent-compatibility-updates)
27
+ - [About Codex](#about-codex)
28
+ - [Package layout](#package-layout)
29
+ - [Security and responsible use](#security-and-responsible-use)
30
+ - [License and maintenance](#license-and-maintenance)
31
+ - [Compatibility additions](#compatibility-additions)
32
+ - [Comparison references](#comparison-references)
33
+ - [Additional functional compatibility helpers](#additional-functional-compatibility-helpers)
34
+ - [AI generation primitive](#ai-generation-primitive)
35
+
36
+ ## At a glance
10
37
 
11
38
  | Property | Value |
12
39
  | --- | --- |
13
40
  | Package | `@codexverified/baileys` |
14
- | Version | `2.10.11` |
41
+ | Version | `2.11.12` |
15
42
  | Runtime | Node.js 20 or newer |
16
- | Module format | ESM with CommonJS compatibility where supported |
17
- | Type declarations | Included |
18
- | License | MIT |
43
+ | Module format | ESM, with CommonJS compatibility where supported |
44
+ | Type declarations | Included at `lib/index.d.ts` |
45
+ | License | MIT, as declared by the package metadata |
19
46
  | Maintainer | Codex |
47
+ | Entry point | `lib/index.js` |
48
+ | Repository | `https://github.com/codexverified/baileys` |
20
49
 
21
50
  ## Installation
22
51
 
23
- Install the published package when it is available in the npm registry:
52
+ | Method | Command | Notes |
53
+ | --- | --- | --- |
54
+ | From npm | `npm install @codexverified/baileys` | Standard install when published under your organization |
55
+ | From local archive | `npm install ./codex-baileys-2.11.12.tgz` | Place the `.tgz` beside your application |
56
+ | Source audit (no scripts) | `npm install --ignore-scripts` | Skips install hooks for local review |
24
57
 
25
- ```bash
26
- npm install @codexverified/baileys
27
- ```
28
-
29
- To install the current local build from the provided archive, place `codex-baileys-2.10.11.tgz` in your project directory and run:
58
+ Both npm and archive installs use the same import name:
30
59
 
31
- ```bash
32
- npm install ./codex-baileys-2.10.11.tgz
60
+ ```javascript
61
+ import { makeWASocket } from '@codexverified/baileys'
33
62
  ```
34
63
 
35
- The local archive installs under the package name `@codexverified/baileys`, so application imports remain the same in both cases.
36
-
37
- ## Quick Start
64
+ ## Quick start
38
65
 
39
- The following example creates a socket, persists authentication credentials, and reconnects after an unexpected connection close.
66
+ The following example creates a socket, stores multi-file authentication credentials, reconnects after an unexpected disconnect, and replies to incoming messages. Keep the session directory private and never commit it to a public repository.
40
67
 
41
68
  ```javascript
42
69
  import {
70
+ DisconnectReason,
43
71
  makeWASocket,
44
- useMultiFileAuthState,
45
- DisconnectReason
72
+ useMultiFileAuthState
46
73
  } from '@codexverified/baileys'
47
74
  import P from 'pino'
48
75
 
49
- const start = async () => {
76
+ async function start() {
50
77
  const { state, saveCreds } = await useMultiFileAuthState('./session')
51
78
 
52
79
  const sock = makeWASocket({
@@ -58,14 +85,12 @@ const start = async () => {
58
85
 
59
86
  sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
60
87
  if (connection === 'open') {
61
- console.log('Connected using @codexverified/baileys')
88
+ console.log('Connected with @codexverified/baileys')
62
89
  }
63
90
 
64
91
  if (connection === 'close') {
65
92
  const statusCode = lastDisconnect?.error?.output?.statusCode
66
- const shouldReconnect = statusCode !== DisconnectReason.loggedOut
67
-
68
- if (shouldReconnect) {
93
+ if (statusCode !== DisconnectReason.loggedOut) {
69
94
  start().catch(console.error)
70
95
  }
71
96
  }
@@ -85,9 +110,7 @@ const start = async () => {
85
110
  start().catch(console.error)
86
111
  ```
87
112
 
88
- ## CommonJS Usage
89
-
90
- For supported Node.js versions, the package can also be loaded through CommonJS:
113
+ ## CommonJS usage
91
114
 
92
115
  ```javascript
93
116
  const {
@@ -96,162 +119,140 @@ const {
96
119
  } = require('@codexverified/baileys')
97
120
  ```
98
121
 
99
- ## Core Capabilities
122
+ If your runtime or bundler does not support this interop path, use the ESM import form instead.
100
123
 
101
- The package includes the following major capabilities:
124
+ ## Core capabilities
102
125
 
103
- | Area | Included functionality |
126
+ | Area | What it covers |
104
127
  | --- | --- |
105
- | Connections | WebSocket connection handling, reconnect support, connection events, pairing codes, and browser identity configuration |
106
- | Authentication | Multi-file, single-file, SQLite, and cache-manager authentication helpers |
107
- | Messages | Text, mentions, reactions, edits, deletes, forwards, replies, polls, contacts, locations, events, and group invites |
108
- | Media | Images, videos, audio, documents, stickers, albums, thumbnails, HD media processing, and GIF playback |
109
- | Interactive content | Buttons, lists, native flows, carousels, templates, and other interactive message structures |
110
- | Rich content | Code blocks, tables, inline entities, LaTeX content, link previews, and rich response utilities |
111
- | Groups | Group creation, participant management, settings, metadata, invites, communities, and labels |
112
- | Newsletters | Channel information, subscribers, following, unfollowing, posts, reactions, media, and polls |
113
- | Account features | Profiles, business information, privacy controls, usernames, interoperation, and account layers |
114
- | Storage | In-memory stores, ordered dictionaries, cache-manager stores, and persistent authentication storage |
115
-
116
- ## Sending Messages
117
-
118
- A basic text message can be sent with `sendMessage`:
128
+ | Connections & authentication | WebSocket connection events, reconnect handling, browser identity configuration, pairing-code flows, connection state transitions |
129
+ | Auth persistence | Multi-file credentials, single-file state, SQLite-backed persistence (optional driver), cache-manager integrations |
130
+ | Messages & conversations | Text, mentions, replies, reactions, edits, deletions, forwards, polls, contacts, locations, events, group invitations, quoted messages, disappearing messages, view-once envelopes |
131
+ | Media & albums | Images, video, audio, documents, stickers, thumbnails, albums; sourced from URLs, local files, or buffers; optional `sharp` / `@napi-rs/image` / `jimp` image processing; GIF-style video playback |
132
+ | Interactive content | Buttons, lists, native flows, hydrated templates, carousel layouts, button grids |
133
+ | Rich content & previews | Code blocks, tables, inline entities, LaTeX-oriented content, link previews, structured response arrays |
134
+ | Rich menus (experimental) | Header image, row/carousel cards, stable button IDs, toast metadata, disclaimers, footer action |
135
+ | Groups & communities | Group creation, participant management, settings, metadata, invites, labels, community/subgroup relationships |
136
+ | Newsletters & channels | Channel metadata, follow/unfollow, posts, reactions, media, polls |
137
+ | Account, business & privacy | Profile/business helpers, product & catalog operations, privacy controls, username utilities, status publishing, favorites management |
138
+ | Storage & protocol utilities | In-memory and ordered-dictionary stores, cache-manager support, LID/phone-number resolution, event utilities, message normalization, media retry handling, TypeScript declarations |
139
+
140
+ ## Everyday message usage
141
+
142
+ | Message type | Key options | Example |
143
+ | --- | --- | --- |
144
+ | Text | `text` | `sock.sendMessage(jid, { text: '...' })` |
145
+ | Media with caption | `image` / `video` / `audio` / `document`, `caption` | `sock.sendMessage(jid, { image: { url } , caption: '...' })` |
146
+ | GIF-style video | `video`, `gifPlayback: true` | `sock.sendMessage(jid, { video: { url }, gifPlayback: true })` |
147
+ | View-once media | `viewOnce: true` (also `viewOnceV2`, `viewOnceV2Extension`, `spoiler`) | `sock.sendMessage(jid, { image: { url }, viewOnce: true })` |
148
+ | Spoiler / view-once (new) | `mediaSpoilerMode: 'viewOnce' \| 'native'` | see below |
119
149
 
120
150
  ```javascript
121
151
  await sock.sendMessage(jid, {
122
- text: 'Your message text'
152
+ text: 'A message from Codex'
123
153
  })
124
- ```
125
-
126
- A media message can be sent from a local file, URL, or buffer depending on the upload configuration:
127
154
 
128
- ```javascript
129
155
  await sock.sendMessage(jid, {
130
- image: { url: './image.jpg' },
131
- caption: 'A caption from Codex'
156
+ image: { url: './media/photo.jpg' },
157
+ caption: 'A photo message'
132
158
  })
133
- ```
134
159
 
135
- A video can be delivered with GIF playback enabled:
136
-
137
- ```javascript
138
160
  await sock.sendMessage(jid, {
139
- video: { url: './animation.mp4' },
161
+ video: { url: './media/animation.mp4' },
140
162
  gifPlayback: true,
141
163
  caption: 'Animated media'
142
164
  })
143
- ```
144
-
145
- ## Authentication
146
-
147
- The recommended authentication helper is `useMultiFileAuthState`:
148
-
149
- ```javascript
150
- import { useMultiFileAuthState } from '@codexverified/baileys'
151
-
152
- const { state, saveCreds } = await useMultiFileAuthState('./session')
153
- ```
154
165
 
155
- Authentication data contains sensitive account credentials. Keep the session directory private, exclude it from version control, and do not upload it to public repositories.
156
-
157
- ## Explicit Newsletter Following
158
-
159
- The package does not automatically follow trusted channels, subscribe to fallback channels, or inject a fallback channel identifier into media messages. Newsletter following is consumer-controlled and must be requested explicitly:
160
-
161
- ```javascript
162
166
  await sock.sendMessage(jid, {
163
- followMe: true,
164
- channelId: '123456789@newsletter',
165
- count: 'once'
167
+ image: { url: './media/private-image.jpg' },
168
+ caption: 'Open once',
169
+ viewOnce: true
166
170
  })
167
- ```
168
-
169
- Applications should validate channel identifiers before sending requests and should only follow channels when the behavior is clearly intended by the application owner and its users.
170
-
171
- ## Media Attribution
172
-
173
- Generated image and video messages do not receive an automatic newsletter annotation or channel pill. If an application intentionally needs message context, it should provide that context explicitly through the supported message options rather than relying on hidden defaults.
174
-
175
- ## CODEX Branding
176
-
177
- The package displays the following startup identity when a socket is created:
178
-
179
- ```text
180
- CODEX TECHNOLOGY
181
- A premium Baileys developed and built by codex
182
- ```
183
-
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
-
186
- ## CODEX Rich Menu and Interactive Helpers
187
171
 
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
172
  await sock.sendMessage(jid, {
196
173
  video: { url: './media/clip.mp4' },
197
- caption: 'Spoiler media',
198
- spoiler: true
174
+ caption: 'View-once video',
175
+ mediaSpoilerMode: 'viewOnce'
176
+ })
177
+
178
+ await sock.sendMessage(jid, {
179
+ image: { url: './media/hidden-preview.jpg' },
180
+ mediaSpoilerMode: 'native'
199
181
  })
200
182
  ```
201
183
 
202
- ### Experimental Gen4 rich menu
184
+ `mediaSpoilerMode` is an additional, opt-in path for supported image, video, document, or sticker media:
203
185
 
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.
186
+ | Value | Effect |
187
+ | --- | --- |
188
+ | `viewOnce` | Wraps supported media in a view-once envelope |
189
+ | `native` | Applies the native spoiler context flag |
190
+
191
+ The existing `viewOnce`, `viewOnceV2`, `viewOnceV2Extension`, and `spoiler` options remain supported and take precedence over `mediaSpoilerMode` when explicitly set.
192
+
193
+ ## Rich menu example
205
194
 
206
195
  ```javascript
207
196
  await sock.richMenu(jid, {
208
197
  header: {
209
- title: 'Rich Menu',
210
- image: { url: 'https://example.com/menu.jpg', mime_type: 'image/jpeg' }
198
+ title: 'Codex Menu',
199
+ image: {
200
+ url: 'https://example.com/menu.jpg',
201
+ mime_type: 'image/jpeg'
202
+ }
211
203
  },
212
204
  body: {
213
205
  row: true,
214
206
  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
- }]
207
+ cards: [
208
+ {
209
+ title: 'Account',
210
+ buttons: [
211
+ { id: 'profile', text: 'Profile' },
212
+ { id: 'settings', text: 'Settings' }
213
+ ]
214
+ },
215
+ {
216
+ title: 'Support',
217
+ buttons: ['help', 'contact']
218
+ }
219
+ ]
227
220
  },
228
221
  footer: {
229
- text: 'Telegram channel',
230
- url: 'https://t.me/example',
231
- image: { url: 'https://example.com/footer.jpg', mime_type: 'image/jpeg' }
222
+ text: 'Codex Technology',
223
+ url: 'https://example.com'
232
224
  }
233
225
  })
234
226
  ```
235
227
 
236
- ### Status, button grids, tables, and Flows
228
+ | Rich menu field | Purpose |
229
+ | --- | --- |
230
+ | `header` | Optional title and image shown above the menu |
231
+ | `body.row` / `body.carousel` | Layout mode for the cards |
232
+ | `body.cards` | Rows of stable button IDs and labels |
233
+ | `footer` | Text plus an optional action URL |
234
+
235
+ ## Status, grids, tables, and flows
236
+
237
+ | Helper | Purpose |
238
+ | --- | --- |
239
+ | `sendStatus` | Post a status update, optionally with mentions via `statusJidList` |
240
+ | `sendRichButtonGrid` | Send a card grid of stable-ID buttons |
241
+ | `sendInteractiveTable` | Send tabular content with headers, rows, and action buttons |
242
+ | `sendWhatsAppFlow` | Launch a published WhatsApp Flow |
237
243
 
238
244
  ```javascript
239
- await sock.sendStatus({ text: 'New status' }, {
245
+ await sock.sendStatus({ text: 'New Codex status' }, {
240
246
  statusJidList: ['1234567890@s.whatsapp.net']
241
247
  })
242
248
 
243
- await sock.sendStatusMentions({ text: 'Mentioned status' }, [
244
- '1234567890@s.whatsapp.net',
245
- '9876543210@s.whatsapp.net'
246
- ])
247
-
248
249
  await sock.sendRichButtonGrid(jid, {
249
250
  text: 'Choose an option',
250
251
  cards: [{
251
252
  title: 'Actions',
252
253
  buttons: [
253
- { id: 'action_one', text: 'Action one' },
254
- { id: 'action_two', text: 'Action two' }
254
+ { id: 'first_action', text: 'First action' },
255
+ { id: 'second_action', text: 'Second action' }
255
256
  ]
256
257
  }]
257
258
  })
@@ -274,53 +275,178 @@ await sock.sendWhatsAppFlow(jid, {
274
275
  })
275
276
  ```
276
277
 
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
+ These helpers are protocol- and client-dependent. Use graceful fallbacks when an application serves a wide range of WhatsApp client versions.
279
+
280
+ ## Authentication and deployment guidance
278
281
 
279
- ## Development
282
+ | Practice | Detail |
283
+ | --- | --- |
284
+ | Session privacy | Keep the session directory private and excluded from version control |
285
+ | Access control | Use a dedicated service account or restricted filesystem permissions where possible |
286
+ | Secrets handling | Do not place access tokens, private keys, phone numbers, or personal account data in the README, package archive, or a public repository |
287
+ | Dependency pinning | Pin dependencies with a lockfile for production deployments |
288
+ | Runtime | Use a supported Node.js runtime |
289
+ | Connection handling | Monitor connection events; handle logout separately from recoverable disconnects; avoid uncontrolled parallel sockets on reconnect |
280
290
 
281
- Clone or extract the source archive, then install the package dependencies in the project directory:
291
+ ## Development workflow
282
292
 
283
293
  ```bash
284
- npm install --ignore-scripts
294
+ npm test
285
295
  ```
286
296
 
287
- Run the package test command with:
297
+ Before submitting changes, validate ESM syntax, CommonJS compatibility where applicable, generated protocol files, and the declarations in `lib/index.d.ts`. Keep package metadata, exports, runtime requirements, and documentation synchronized. When a protocol behavior is experimental, document the fallback behavior and the client versions used during testing.
288
298
 
289
- ```bash
290
- npm test
299
+ ## Recent compatibility updates
300
+
301
+ | Update | Detail |
302
+ | --- | --- |
303
+ | Album association fix | Album child messages use association type `1`, the compatible child-association wire value, rather than treating the `MEDIA_ALBUM` message category as the association value |
304
+ | View-once preserved | Explicit view-once implementations remain unchanged |
305
+ | `mediaSpoilerMode` | New opt-in path for a view-once envelope or native spoiler flag, without altering existing defaults |
306
+
307
+ ## About Codex
308
+
309
+ This package is built and maintained by **Codex**, also known as **Dev Codex**. Codex is a developer from Nigeria who focuses on practical, accessible, and reliable software projects across the JavaScript and TypeScript ecosystem.
310
+
311
+ | | |
312
+ | --- | --- |
313
+ | Tech stack | JavaScript, HTML, TypeScript, Node.js, GitHub, Baileys, APIs, key-value stores |
314
+ | Project types | Application development, websites, WhatsApp bots, Telegram bots, API endpoints, games |
315
+ | Telegram | [@codexverified](https://t.me/codexverified) |
316
+ | Email | codexauthorized@gmail.com |
317
+
318
+ The developer's work is driven by a commitment to learning, experimentation, clear documentation, and useful software that developers can understand and extend. This package reflects that commitment through its readable source, public declarations, practical examples, and emphasis on responsible automation.
319
+
320
+ ## Package layout
321
+
322
+ | Path | Contents |
323
+ | --- | --- |
324
+ | `lib/` | JavaScript implementation, supporting utilities, public TypeScript declarations |
325
+ | `WAProto/` | Generated WhatsApp protocol definitions |
326
+ | `engine-requirements.js` | Installation-time runtime checks |
327
+ | `package.json` | Package metadata, scripts, dependencies, exports |
328
+ | `README.md` | User-facing installation and usage guide |
329
+
330
+ ## Security and responsible use
331
+
332
+ This library interacts with WhatsApp accounts and user communications.
333
+
334
+ | Guideline | Detail |
335
+ | --- | --- |
336
+ | Authorization | Use only with accounts and data you are authorized to control |
337
+ | Compliance | Respect WhatsApp's terms, applicable law, and message participants' privacy expectations |
338
+ | Messaging conduct | Avoid unsolicited messaging |
339
+ | Credential safety | Protect authentication state and never commit session files, tokens, private keys, or personal data to a public repository |
340
+ | Media access | Limit access to stored media |
341
+ | Transparency | Provide clear notice when an application performs automated actions |
342
+ | Dependency review | Review installation scripts and optional dependencies before deploying to production; use pinned versions for repeatable builds |
343
+
344
+ ## License and maintenance
345
+
346
+ This distribution is provided under the license declared in `package.json` and the accompanying license file. Review those terms before redistributing or combining this package with third-party code.
347
+
348
+ **@codexverified/baileys is built and maintained by Codex under the CodexVerified organization.** Contributions, bug reports, and carefully documented improvements are welcome through the project repository.
349
+
350
+ ## Compatibility additions
351
+
352
+ The current source includes several independently implemented compatibility helpers identified during comparison with the published upstream package. These additions preserve the Codex package identity and do not copy package-specific attribution enforcement or remote licensing checks.
353
+
354
+ ### Copy-to-clipboard rich response
355
+
356
+ `sendCopyButton` creates a forwarded GenAI-style rich response with a copy-to-clipboard addon action.
357
+
358
+ | Option | Purpose |
359
+ | --- | --- |
360
+ | `text` | The content that gets copied |
361
+ | `label` | Optional visible button text |
362
+ | `alignment` | `END`, `START`, or `CENTER` |
363
+
364
+ ```javascript
365
+ await sock.sendCopyButton(jid, {
366
+ text: 'npm install @codexverified/baileys',
367
+ label: 'Copy install command',
368
+ alignment: 'END'
369
+ })
291
370
  ```
292
371
 
293
- Before submitting changes, check the following:
372
+ As with other private or experimental WhatsApp rich-response layouts, clients may fall back to plain rendering or ignore the addon action.
294
373
 
295
- 1. Preserve the public API unless a breaking change is intentional.
296
- 2. Keep runtime requirements and package metadata synchronized.
297
- 3. Keep authentication data and personal account information out of commits.
298
- 4. Validate ESM syntax and CommonJS compatibility where applicable.
299
- 5. Document user-visible behavior changes in this README.
374
+ ### Slot-machine HTML generator
300
375
 
301
- ## Package Layout
376
+ `generateSlotMachineHtml` produces a self-contained five-reel Fruit Bonanza game with adjustable starting credits. It is a standalone HTML payload and performs no network requests.
302
377
 
303
- | Path | Purpose |
378
+ | Option | Purpose |
304
379
  | --- | --- |
305
- | `lib/` | Compiled JavaScript implementation and type declarations |
306
- | `WAProto/` | WhatsApp protocol definitions and generated protocol helpers |
307
- | `engine-requirements.js` | Runtime requirement checks used during installation |
308
- | `package.json` | Package metadata, dependencies, scripts, and exports |
309
- | `README.md` | Project documentation and usage reference |
380
+ | `title` | Display title for the generated page |
381
+ | `startingCredits` | Initial credit balance |
310
382
 
311
- ## Security and Responsible Use
383
+ ```javascript
384
+ import { generateSlotMachineHtml } from '@codexverified/baileys'
312
385
 
313
- This library interacts with WhatsApp accounts and user communications. Use it only with accounts and data you are authorized to control. Protect authentication files, avoid unsolicited messaging, respect platform rules, and provide clear notice when an application performs automated actions.
386
+ const html = generateSlotMachineHtml({
387
+ title: 'Codex Fruit Bonanza',
388
+ startingCredits: 500
389
+ })
390
+ ```
314
391
 
315
- Do not commit session files, access tokens, private keys, phone numbers, or other personal information to a public repository.
392
+ The generator does not by itself send HTML through WhatsApp. Applications should only use an HTML-capable message primitive when that primitive is available and authorized for their deployment.
316
393
 
317
- ## License
394
+ ### Optional ban-status checker
318
395
 
319
- This project is distributed under the MIT License. See the package license metadata for the applicable terms.
396
+ `checkStatusWA` is an explicit, caller-invoked diagnostic helper. It is never called during installation, socket creation, reconnection, or message sending. The endpoint is configurable, credentials are not embedded, and callers should review the endpoint's terms and privacy implications before sending a phone number.
320
397
 
321
- ## Maintained by Codex
398
+ ```javascript
399
+ import { checkStatusWA } from '@codexverified/baileys'
322
400
 
323
- **@codexverified/baileys is built and maintained by Codex.** Contributions, bug reports, and carefully documented improvements are welcome through the project repository once it is published.
401
+ const result = await checkStatusWA('+447700900123', {
402
+ diagnostic: true
403
+ })
404
+ console.log(result.status) // active, banned, blocked, not_registered, rate_limited, or unknown
405
+ ```
406
+
407
+ | Status value | Meaning |
408
+ | --- | --- |
409
+ | `active` | Number appears active on WhatsApp |
410
+ | `banned` | Number appears banned |
411
+ | `blocked` | Number appears blocked |
412
+ | `not_registered` | Number is not registered on WhatsApp |
413
+ | `rate_limited` | Check was rate limited |
414
+ | `unknown` | Status could not be determined |
415
+
416
+ This helper is not an anti-ban guarantee, does not bypass enforcement, and should not be used for bulk enumeration or unsolicited checking.
417
+
418
+ ## Comparison references
419
+
420
+ The feature comparison was based on the published package metadata and documentation available from [npm][1] and the independent package analysis page at [Socket][2]. The Codex implementation adds compatible behavior through readable, package-owned code rather than copying upstream-specific integrity, attribution, or remote-verification mechanisms.
421
+
422
+ [1]: https://www.npmjs.com/
423
+ [2]: https://socket.dev/
324
424
 
425
+ ## Additional functional compatibility helpers
325
426
 
427
+ The source also exposes portable helpers for native-flow responses, view-once inspection, rich content preparation, HTML payload construction, and website previews. These are functional compatibility APIs only; package-specific identity checks, attribution enforcement, remote license gates, trusted-channel auto-follow behavior, and other ownership structures are not included.
326
428
 
429
+ | Helper | Purpose |
430
+ | --- | --- |
431
+ | `parseNativeFlowResponse` | Normalize quick-reply, single-select, and Flow response envelopes |
432
+ | `parseWhatsAppFlowResponse` | Return only responses identified as WhatsApp Flow responses |
433
+ | `buildWhatsAppFlowButton` / `makeWhatsAppFlowButton` | Build published Flow button parameters for a caller-owned Flow ID and token |
434
+ | `prepareRichTextMessage` | Build a forwarded rich text response |
435
+ | `prepareRichImageMessage` | Build a forwarded rich image response |
436
+ | `prepareRichLinkMessage` | Build a forwarded response with inline link entities |
437
+ | `prepareRichGenerationMessage` | Build a rich response from caller-provided rich content |
438
+ | `prepareHtmlMessage` | Build an HTML primitive payload for clients that support the experimental structure |
439
+ | `prepareSlotMachineMessage` | Wrap the local slot-machine generator as an HTML message payload |
440
+ | `generateLinkPreviewHtml` / `generateWebsitePreviewHtml` | Create escaped link cards or an explicitly requested metadata preview |
441
+ | `parseViewOnceInfo` and related helpers | Inspect, download, reconstruct, and apply explicit view-once policies |
442
+
443
+ All networked helpers are opt-in. Website previews fetch only when explicitly called, and Flow helpers require credentials and identifiers owned by the application. Experimental WhatsApp layouts remain client-dependent and should always have a plain-text fallback.
444
+
445
+ ## AI generation primitive
446
+
447
+ `buildImaginePrimitive` creates the Meta-style AI image or animation generation-state payload used by rich responses. It is a pure payload builder — it does not call a generation service itself, generate media, or send anything on its own; callers wire it up to whatever AI generation backend they use, then pass the resulting primitive into a rich-response message.
448
+
449
+ | Field | Purpose |
450
+ | --- | --- |
451
+ | `state` | Generation status: `GENERATING`, `COMPLETE`, or `ERROR` |
452
+ | `mediaUrl` | URL of the generated media
@@ -36,7 +36,7 @@ const makeWASocket = (config) => {
36
36
  };
37
37
  console.log(
38
38
  `\n${yellow}${center('CODEX TECHNOLOGY')}${reset}\n` +
39
- `${blue}${center('@codexverified/Baileys')}${reset}\n` +
39
+ `${blue}${center('@codexverified/baileys')}${reset}\n` +
40
40
  `${yellow}${center('premium baileys built by codex')}${reset}\n`
41
41
  );
42
42
  }
@@ -4,7 +4,6 @@ import { randomBytes } from 'crypto';
4
4
  import { proto } from '../../WAProto/index.js';
5
5
  import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
6
6
  import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
7
- import { AssociationType } from '../Types/index.js';
8
7
  import { getUrlInfo } from '../Utils/link-preview.js';
9
8
  import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
10
9
  import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/reporting-utils.js';
@@ -17,7 +16,7 @@ import { collectMetaAIBotParticipantJids, isMetaAIBotResponse, META_AI_BOT_JID }
17
16
  import { makeUsernameSocket } from './username.js';
18
17
 
19
18
  const STATUS_JID = 'status@broadcast';
20
- const normalizeStatusJidList = (value) => {
19
+ export const normalizeStatusJidList = (value) => {
21
20
  if (!Array.isArray(value) || value.length === 0) {
22
21
  throw new Boom('statusJidList must contain at least one recipient JID', { statusCode: 400 });
23
22
  }
@@ -1224,6 +1223,13 @@ export const makeMessagesSocket = (config) => {
1224
1223
  await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata });
1225
1224
  return fullMsg;
1226
1225
  },
1226
+ sendCopyButton: async (jid, content = {}, options = {}) => {
1227
+ const { prepareCopyToClipboardMessage } = await import('../Utils/rich-message-utils.js');
1228
+ const message = prepareCopyToClipboardMessage(content);
1229
+ const fullMsg = await generateWAMessageFromContent(jid, message, { logger, userJid: authState.creds.me?.id, messageId: options.messageId || generateMessageIDV2(authState.creds.me?.id), ...options });
1230
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata });
1231
+ return fullMsg;
1232
+ },
1227
1233
  sendInteractiveTable: async (jid, table, options = {}) => {
1228
1234
  const { title = '', headers = [], rows = [], image, buttons = [], footer } = table || {};
1229
1235
  if (!Array.isArray(headers) || !Array.isArray(rows) || !Array.isArray(buttons)) throw new Boom('sendInteractiveTable expects headers, rows, and buttons arrays', { statusCode: 400 });
@@ -2040,7 +2046,9 @@ export const makeMessagesSocket = (config) => {
2040
2046
  albumMsg.message.messageContextInfo ||= {};
2041
2047
  albumMsg.message.messageContextInfo.messageAssociation = {
2042
2048
  parentMessageKey: fullMsg.key,
2043
- associationType: AssociationType.MEDIA_ALBUM
2049
+ // WhatsApp album child messages use association type 1.
2050
+ // MEDIA_ALBUM is a message category, not the child-association wire value.
2051
+ associationType: 1
2044
2052
  };
2045
2053
  await relayMessage(jid, albumMsg.message, {
2046
2054
  messageId: albumMsg.key.id,
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Optional WhatsApp registration-status checker.
3
+ *
4
+ * This module is deliberately opt-in. It does not run during installation,
5
+ * connection setup, or message sending, and it does not contain credentials.
6
+ * Callers should review the endpoint and applicable terms before use.
7
+ */
8
+
9
+ const cleanNumber = (value) => String(value ?? '').replace(/[\s().\-/]/g, '').replace(/^00/, '').replace(/^\+/, '');
10
+
11
+ export const normalizeBanCheckNumber = (value) => {
12
+ const number = cleanNumber(typeof value === 'object' ? value.number : value);
13
+ if (!/^\d{6,15}$/.test(number)) throw new TypeError('number must be an international phone number');
14
+ return `+${number}`;
15
+ };
16
+
17
+ export const checkStatusWA = async (number, options = {}) => {
18
+ const normalized = normalizeBanCheckNumber(number);
19
+ const endpoint = options.endpoint || 'https://v.whatsapp.net/v2/exist';
20
+ const fetchImpl = options.fetch || globalThis.fetch;
21
+ if (typeof fetchImpl !== 'function') throw new TypeError('a fetch implementation is required');
22
+ const url = new URL(endpoint);
23
+ url.searchParams.set('in', normalized.slice(1));
24
+ const response = await fetchImpl(url, {
25
+ method: 'GET',
26
+ headers: { ...(options.headers || {}) },
27
+ signal: options.signal
28
+ });
29
+ let body = null;
30
+ try { body = await response.json(); } catch { body = null; }
31
+ const reason = String(body?.reason || body?.error || body?.status || '').toLowerCase();
32
+ let status = 'unknown';
33
+ if (response.status === 429 || /rate.?limit|too many/.test(reason)) status = 'rate_limited';
34
+ else if (/blocked|official|banned|ban|temporar|perman/.test(reason)) status = /banned|ban|temporar|perman/.test(reason) ? 'banned' : 'blocked';
35
+ else if (/not.?registered|does.?not.?exist/.test(reason)) status = 'not_registered';
36
+ else if (response.ok) status = 'active';
37
+ return {
38
+ number: normalized,
39
+ status,
40
+ isBanned: status === 'banned',
41
+ isNeedOfficialWa: status === 'blocked',
42
+ diagnostics: options.diagnostic === true ? {
43
+ httpStatus: response.status,
44
+ ok: response.ok,
45
+ bodyKeys: body && typeof body === 'object' ? Object.keys(body).sort() : []
46
+ } : undefined
47
+ };
48
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Self-contained, dependency-free slot-machine HTML generator.
3
+ * The generated page is local-only and makes no network requests.
4
+ */
5
+
6
+ const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (character) => ({
7
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
8
+ }[character]));
9
+
10
+ export const generateSlotMachineHtml = (options = {}) => {
11
+ const title = escapeHtml(options.title || 'FRUIT BONANZA');
12
+ const startingCredits = Number.isFinite(Number(options.startingCredits)) && Number(options.startingCredits) >= 0
13
+ ? Math.floor(Number(options.startingCredits)) : 500;
14
+ return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>
15
+ *{box-sizing:border-box}body{margin:0;padding:12px;background:#160704;color:#ffe8a3;font:14px system-ui,sans-serif}.machine{max-width:540px;margin:auto;padding:16px;border:4px solid #e6a139;border-radius:22px;background:linear-gradient(135deg,#230805,#8c3515,#2b0906);box-shadow:0 8px 18px #000a}.title{text-align:center;font-size:24px;font-weight:900;color:#fff2a1;text-shadow:0 2px #8f1c0c}.stats{display:flex;justify-content:space-around;margin:10px 0;padding:8px;border:2px solid #a55c19;border-radius:8px;background:#100303}.reels{display:grid;grid-template-columns:repeat(5,1fr);gap:5px;padding:8px;border:5px solid #9b4e12;border-radius:14px;background:#140604}.reel{height:78px;display:grid;place-items:center;border-radius:6px;background:linear-gradient(#fffce4,#d7bf87);color:#b20f1c;font-size:38px;font-weight:900;overflow:hidden}.reel.spin{animation:spin .16s linear infinite}.message{min-height:30px;margin:10px;text-align:center;font-weight:800}.controls{display:flex;gap:8px}.controls button{flex:1;padding:12px;border:2px solid #351006;border-radius:10px;font-weight:900;cursor:pointer}.bet{background:#1685a5;color:white}.spin{background:#27a93b;color:white}.spin:disabled{opacity:.5}@keyframes spin{50%{transform:translateY(5px);filter:blur(1px)}}small{display:block;margin-top:10px;text-align:center;color:#d6a15b}</style></head><body><main class="machine"><div class="title">${title}</div><div class="stats"><span>Credits <b id="credits">${startingCredits}</b></span><span>Bet <b id="bet">10</b></span><span>Best <b id="best">0</b></span></div><div class="reels">${[0,1,2,3,4].map((index) => `<div class="reel" id="r${index}">🍒</div>`).join('')}</div><div class="message" id="message">SPIN TO PLAY</div><div class="controls"><button class="bet" id="betButton" type="button">BET</button><button class="spin" id="spinButton" type="button">SPIN</button></div><small>Three matching symbols win. This is a local chat-embedded game.</small></main><script>
16
+ (()=>{const symbols=['🍒','🍋','🔔','💎','7️⃣','🅱️'];let credits=${startingCredits},bet=10,best=0,busy=false;const $=id=>document.getElementById(id);const ui=()=>{$('credits').textContent=credits;$('bet').textContent=bet;$('best').textContent=best};$('betButton').onclick=()=>{if(busy)return;bet=bet===10?20:bet===20?50:10;if(bet>credits)bet=10;ui()};$('spinButton').onclick=()=>{if(busy||credits<bet)return;busy=true;credits-=bet;$('message').textContent='GOOD LUCK';ui();const reels=[0,1,2,3,4].map(i=>$('r'+i));reels.forEach(r=>r.classList.add('spin'));setTimeout(()=>{const values=reels.map(r=>{r.classList.remove('spin');const value=symbols[Math.floor(Math.random()*symbols.length)];r.textContent=value;return value});const counts=values.reduce((map,value)=>(map[value]=(map[value]||0)+1,map),{});const match=Math.max(...Object.values(counts));const win=match>=3?bet*(match===5?20:match===4?8:3):0;credits+=win;best=Math.max(best,win);$('message').textContent=win?'WIN +'+win:(credits?'TRY AGAIN':'GAME OVER');busy=false;ui()},700)};ui()})();</script></body></html>`;
17
+ };
18
+
19
+ export default generateSlotMachineHtml;
@@ -32,3 +32,9 @@ export * from './browser-utils.js';
32
32
  export * from './companion-reg-client-utils.js';
33
33
  export * from './identity-change-handler.js';
34
34
  export * from './stanza-ack.js';
35
+ export * from './games/slot-machine.js';
36
+ export * from './ban-checker.js';
37
+ export * from './native-flow.js';
38
+ export * from './view-once-utils.js';
39
+ export * from './website-preview.js';
40
+ export * from './portable-compat.js';
@@ -1363,6 +1363,31 @@ export const generateWAMessageContent = async (message, options) => {
1363
1363
  };
1364
1364
  delete message.interactiveAsTemplate;
1365
1365
  }
1366
+ // Codex compatibility: expose the public media-spoiler mode without changing
1367
+ // the existing explicit viewOnce/viewOnceV2 behavior. The mode is opt-in.
1368
+ // Supported values are `viewOnce` and `native` for image, video, document,
1369
+ // and sticker messages. Existing `spoiler` and view-once flags take priority.
1370
+ if (hasOptionalProperty(message, 'mediaSpoilerMode') &&
1371
+ !message.viewOnce &&
1372
+ !message.viewOnceV2 &&
1373
+ !message.viewOnceV2Extension) {
1374
+ const messageType = Object.keys(m)[0];
1375
+ const isSpoilerMedia = ['imageMessage', 'videoMessage', 'documentMessage', 'stickerMessage'].includes(messageType);
1376
+ const mode = message.mediaSpoilerMode;
1377
+ if (isSpoilerMedia && mode === 'viewOnce') {
1378
+ m = { viewOnceMessage: { message: m } };
1379
+ }
1380
+ else if (isSpoilerMedia && mode === 'native') {
1381
+ const key = m[messageType];
1382
+ if (key && 'contextInfo' in key && key.contextInfo) {
1383
+ key.contextInfo.isSpoiler = true;
1384
+ }
1385
+ else if (key) {
1386
+ key.contextInfo = { isSpoiler: true };
1387
+ }
1388
+ }
1389
+ delete message.mediaSpoilerMode;
1390
+ }
1366
1391
  // Lia@Changes 30-01-26 --- Add "ephemeral" boolean to wrap message into ephemeralMessage like "viewOnce"
1367
1392
  if (hasOptionalProperty(message, 'ephemeral') && !!message.ephemeral) {
1368
1393
  m = { ephemeralMessage: { message: m } };
@@ -0,0 +1,48 @@
1
+ const parseJsonObject = (value) => {
2
+ if (!value) return {};
3
+ if (typeof value === 'object') return value;
4
+ try {
5
+ const parsed = JSON.parse(value);
6
+ return parsed && typeof parsed === 'object' ? parsed : {};
7
+ } catch { return {}; }
8
+ };
9
+
10
+ export const parseNativeFlowResponse = (message) => {
11
+ const content = message?.message || message;
12
+ const response = content?.interactiveResponseMessage?.nativeFlowResponseMessage || content?.nativeFlowResponseMessage;
13
+ if (!response) return null;
14
+ const params = parseJsonObject(response.paramsJson);
15
+ const actionPayload = params.flow_action_payload || params.flowActionPayload || {};
16
+ const data = params.data || params.response || params.form_data || params.formData || actionPayload.data || {};
17
+ return {
18
+ name: response.name || '', version: response.version, paramsJson: response.paramsJson || '', params,
19
+ isFlow: response.name === 'galaxy_message' || response.name === 'flow' || Boolean(params.flow_id || params.flow_token || params.flow_message_version),
20
+ flowId: params.flow_id || params.flowId, flowToken: params.flow_token || params.flowToken,
21
+ screen: params.screen || actionPayload.screen, action: params.flow_action || params.flowAction || actionPayload.action,
22
+ actionPayload, data, buttonId: params.id || params.button_id || params.buttonId,
23
+ displayText: params.display_text || params.displayText, raw: response
24
+ };
25
+ };
26
+
27
+ export const parseWhatsAppFlowResponse = (message) => {
28
+ const response = parseNativeFlowResponse(message);
29
+ return response?.isFlow ? response : null;
30
+ };
31
+
32
+ export const buildWhatsAppFlowButton = ({ flowId, flowToken, cta = 'Open form', action = 'navigate', actionPayload, mode = 'published', flowMessageVersion = '3', metadata, name = 'galaxy_message' } = {}) => {
33
+ if (!flowId) throw new TypeError('flowId is required to launch a WhatsApp Flow');
34
+ if (!flowToken) throw new TypeError('flowToken is required to launch a WhatsApp Flow');
35
+ return {
36
+ name, flow_message_version: String(flowMessageVersion), flow_token: String(flowToken), flow_id: String(flowId),
37
+ flow_cta: String(cta), flow_action: action,
38
+ ...(actionPayload ? { flow_action_payload: actionPayload } : {}),
39
+ ...(metadata ? { flow_metadata: metadata } : {}),
40
+ ...(mode ? { flow_mode: String(mode) } : {})
41
+ };
42
+ };
43
+
44
+ export const makeWhatsAppFlowButton = (flow) => ({
45
+ name: flow?.nativeFlowName || 'galaxy_message',
46
+ buttonParamsJson: JSON.stringify(buildWhatsAppFlowButton(flow))
47
+ });
48
+
@@ -0,0 +1,12 @@
1
+ import { generateRichMenuContent } from './message-composer.js';
2
+ import { prepareRichResponseMessage } from './rich-message-utils.js';
3
+
4
+ /** Build a prepared rich-menu payload for direct message generation. */
5
+ export const prepareRichMenuMessage = (content = {}, quoted, options = {}) => generateRichMenuContent(content, quoted, options);
6
+
7
+ /** Convert unsupported premium content to a safe plain-text rich response. */
8
+ export const downgradePremiumContent = (content = {}) => {
9
+ if (typeof content === 'string') return prepareRichResponseMessage({ contentText: content, noDonation: true });
10
+ const text = content.text || content.contentText || content.caption || '';
11
+ return prepareRichResponseMessage({ contentText: String(text), noDonation: true });
12
+ };
@@ -299,7 +299,7 @@ export const prepareRichResponseMessage = (content) => {
299
299
  const defaultDonationLink = {
300
300
  text: '',
301
301
  url: DONATE_URL,
302
- title: 'PAIR CRYSNVA AI :',
302
+ title: 'PAIR CODEX AI :',
303
303
  displayName: 'pair bot'
304
304
  };
305
305
  const resolvedLinks = noDonation ? links : [...(links || []), defaultDonationLink];
@@ -436,4 +436,110 @@ export const wrapToBotForwardedMessage = (richResponseMessage) => ({
436
436
  message: { richResponseMessage }
437
437
  }
438
438
  });
439
- //# sourceMappingURL=rich-message-utils.js.map
439
+ //# sourceMappingURL=rich-message-utils.js.map
440
+
441
+ /**
442
+ * Build a forwarded rich response with an inline copy-to-clipboard action.
443
+ * The payload follows WhatsApp's GenAI addon-action layout and is opt-in.
444
+ * @param {{text?: string, label?: string, alignment?: 'END'|'START'|'CENTER'}} options
445
+ * @returns {{messageContextInfo: object, botForwardedMessage: object}}
446
+ */
447
+ export const prepareCopyToClipboardMessage = (options = {}) => {
448
+ const text = String(options.text ?? '');
449
+ const label = String(options.label ?? text);
450
+ const alignment = ['END', 'START', 'CENTER'].includes(options.alignment) ? options.alignment : 'END';
451
+ const unified = {
452
+ response_id: randomUUID(),
453
+ sections: [{
454
+ __typename: 'GenAIUnifiedResponseSection',
455
+ view_model: {
456
+ __typename: 'GenAIAddonActionLayoutViewModel',
457
+ addon_action_type: 'COPY_TO_CLIPBOARD',
458
+ addon_action_alignment: alignment,
459
+ primitives: [{
460
+ __typename: 'GenAIMarkdownTextUXPrimitive',
461
+ text: label,
462
+ inline_entities: []
463
+ }]
464
+ }
465
+ }]
466
+ };
467
+ const richResponseMessage = proto.AIRichResponseMessage.create({
468
+ submessages: [],
469
+ messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
470
+ unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
471
+ contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 }
472
+ });
473
+ return wrapToBotForwardedMessage(richResponseMessage);
474
+ };
475
+
476
+ /** Build a plain rich-text forwarded response. */
477
+ export const prepareRichTextMessage = ({ text = '' } = {}) => prepareRichResponseMessage({ contentText: String(text), noDonation: true });
478
+
479
+ /** Build a rich image forwarded response using a GenAI image primitive. */
480
+ export const prepareRichImageMessage = ({ url = '', mimeType = 'image/png' } = {}) => {
481
+ const media = { __typename: 'GenAIMediaItem', mime_type: mimeType, url: String(url), url_fallback: String(url) };
482
+ const unified = { response_id: randomUUID(), sections: [{ __typename: 'GenAIUnifiedResponseSection', view_model: { __typename: 'GenAISingleLayoutViewModel', primitive: { __typename: 'GenAIImagePrimitive', preview_image: media, full_image: media } } }] };
483
+ const rich = proto.AIRichResponseMessage.create({ submessages: [], messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD, unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) }, contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 } });
484
+ return wrapToBotForwardedMessage(rich);
485
+ };
486
+
487
+ /** Build a rich response containing clickable inline links. */
488
+ export const prepareRichLinkMessage = ({ links = [], text = '' }= {}) => {
489
+ const entities = [];
490
+ let combined = '';
491
+ for (const [index, link] of links.entries()) {
492
+ const key = `INLINE_HYPERLINK_${index}`;
493
+ const display = String(link?.text || link?.displayName || link?.url || '');
494
+ combined += `{{${key}}}${display}{{/${key}}}`;
495
+ entities.push({ key, metadata: { display_name: display, is_trusted: link?.isTrusted !== false, url: String(link?.url || ''), __typename: 'GenAIInlineLinkItem' } });
496
+ }
497
+ return prepareRichResponseMessage({ contentText: combined || String(text), links: [], noDonation: true, noHeading: true, richResponse: [{ text: combined || String(text), inlineEntities: entities }] });
498
+ };
499
+
500
+ /** Build a rich-generation response from existing rich-response content. */
501
+ export const prepareRichGenerationMessage = (content = {}) => prepareRichResponseMessage({ ...content, noDonation: true });
502
+
503
+ /** Build an HTML primitive payload. Use only with an HTML-capable, authorized client. */
504
+ export const prepareHtmlMessage = ({ html = '' } = {}) => {
505
+ const unified = { response_id: randomUUID(), sections: [{ view_model: { primitive: { __typename: 'FOAHtmlPrimitiveDemoDONOTUSE', html: String(html) }, __typename: 'GenAISingleLayoutViewModel' } }] };
506
+ const rich = proto.AIRichResponseMessage.create({ submessages: [], messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD, unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) }, contextInfo: { isForwarded: true, forwardingScore: 1, forwardOrigin: 4 } });
507
+ return wrapToBotForwardedMessage(rich);
508
+ };
509
+
510
+ /** Convenience wrapper for a slot-machine HTML message payload. */
511
+ export const prepareSlotMachineMessage = async (options = {}) => {
512
+ const { generateSlotMachineHtml } = await import('./games/slot-machine.js');
513
+ return prepareHtmlMessage({ html: generateSlotMachineHtml(options) });
514
+ };
515
+
516
+ /**
517
+ * Build a Meta-style AI image/video generation primitive.
518
+ * The payload is useful for displaying generation progress without making any
519
+ * network request or enabling a hidden background process.
520
+ */
521
+ export const buildImaginePrimitive = ({
522
+ mediaType = 'video',
523
+ url = '',
524
+ thumbnail,
525
+ mimeType,
526
+ fileLength = 0,
527
+ duration = 0,
528
+ status = 'GENERATING',
529
+ estimatedMs,
530
+ imagineType
531
+ } = {}) => {
532
+ const normalizedType = String(mediaType).toLowerCase() === 'image' ? 'IMAGE' : 'ANIMATE';
533
+ return {
534
+ __typename: 'GenAIImaginePrimitive',
535
+ media_type: normalizedType,
536
+ imagine_type: imagineType || normalizedType,
537
+ status: String(status),
538
+ ...(url ? { url: String(url), url_fallback: String(url) } : {}),
539
+ ...(thumbnail ? { thumbnail_url: String(thumbnail) } : {}),
540
+ ...(mimeType ? { mime_type: String(mimeType) } : {}),
541
+ ...(fileLength ? { file_length: Number(fileLength) } : {}),
542
+ ...(duration ? { duration: Number(duration) } : {}),
543
+ ...(estimatedMs !== undefined ? { estimated_ms: Number(estimatedMs) } : {})
544
+ };
545
+ };
@@ -0,0 +1,56 @@
1
+ import { downloadContentFromMessage } from './messages-media.js';
2
+
3
+ export const isViewOnceMessage = (message) => Boolean(message?.message?.viewOnceMessage || message?.message?.viewOnceMessageV2 || message?.message?.viewOnceMessageV2Extension || message?.viewOnceMessage || message?.viewOnceMessageV2 || message?.viewOnceMessageV2Extension);
4
+
5
+ export const extractViewOnceContent = (message) => {
6
+ const content = message?.message || message;
7
+ return content?.viewOnceMessage?.message || content?.viewOnceMessageV2?.message || content?.viewOnceMessageV2Extension?.message || null;
8
+ };
9
+
10
+ export const getViewOnceMediaType = (message) => {
11
+ const content = extractViewOnceContent(message);
12
+ if (!content) return null;
13
+ for (const type of ['image', 'video', 'audio', 'document', 'sticker']) if (content[`${type}Message`]) return type;
14
+ return null;
15
+ };
16
+
17
+ export const getViewOnceMediaContent = (message) => {
18
+ const content = extractViewOnceContent(message);
19
+ if (!content) return null;
20
+ return content.imageMessage || content.videoMessage || content.audioMessage || content.documentMessage || content.stickerMessage || null;
21
+ };
22
+
23
+ export const downloadViewOnceMedia = async (message, options = {}) => {
24
+ const media = getViewOnceMediaContent(message);
25
+ const type = getViewOnceMediaType(message);
26
+ if (!media || !type) throw new Error('No supported media content found in view-once message');
27
+ const stream = await downloadContentFromMessage(media, type, options);
28
+ const chunks = [];
29
+ for await (const chunk of stream) chunks.push(chunk);
30
+ return Buffer.concat(chunks);
31
+ };
32
+
33
+ export const createRegularMessageFromViewOnce = (originalMessage, mediaBuffer) => {
34
+ const media = getViewOnceMediaContent(originalMessage);
35
+ const type = getViewOnceMediaType(originalMessage);
36
+ if (!media || !type) return null;
37
+ return {
38
+ key: originalMessage.key, messageTimestamp: originalMessage.messageTimestamp,
39
+ pushName: originalMessage.pushName, participant: originalMessage.participant,
40
+ decryptedMedia: { type, buffer: mediaBuffer, mimeType: media.mimetype, fileName: media.fileName, caption: media.caption, fileLength: media.fileLength },
41
+ originalViewOnceMessage: originalMessage.message
42
+ };
43
+ };
44
+
45
+ export const shouldAutoDecryptViewOnce = (message, config = {}) => isViewOnceMessage(message) && config.autoVV !== false && message.key?.fromMe !== true;
46
+ export const shouldDeleteViewOnce = (message, config = {}) => isViewOnceMessage(message) && config.antiVV !== false && message.key?.fromMe !== true;
47
+
48
+ export const parseViewOnceInfo = (message) => {
49
+ const media = getViewOnceMediaContent(message);
50
+ return {
51
+ isViewOnce: isViewOnceMessage(message), mediaType: getViewOnceMediaType(message), mimeType: media?.mimetype,
52
+ fileName: media?.fileName, caption: media?.caption, fileLength: media?.fileLength,
53
+ hasUrl: Boolean(media?.url), hasDirectPath: Boolean(media?.directPath), hasMediaKey: Boolean(media?.mediaKey)
54
+ };
55
+ };
56
+
@@ -0,0 +1,27 @@
1
+ const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (character) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[character]));
2
+
3
+ const validateUrl = (value) => {
4
+ const parsed = new URL(value);
5
+ if (!['http:', 'https:'].includes(parsed.protocol)) throw new TypeError('only HTTP(S) preview URLs are supported');
6
+ return parsed;
7
+ };
8
+
9
+ export const generateLinkPreviewHtml = (url, options = {}) => {
10
+ const parsed = validateUrl(url);
11
+ const title = options.title || parsed.hostname;
12
+ const description = options.description || `Open ${parsed.hostname}`;
13
+ const image = options.image ? `<img src="${escapeHtml(options.image)}" alt="" loading="lazy">` : '<div class="placeholder">🌐</div>';
14
+ return `<!doctype html><html><head><meta charset="utf-8"><style>body{margin:0;background:transparent;font:14px system-ui,sans-serif}.card{overflow:hidden;border:1px solid #333;border-radius:12px;background:#1a1a2e;color:#fff}.card img,.placeholder{display:block;width:100%;height:160px;object-fit:cover}.placeholder{display:grid;place-items:center;font-size:48px;background:linear-gradient(135deg,#1a1a2e,#2d2d44)}.body{padding:14px}.title{font-weight:700;margin-bottom:5px}.desc{color:#bbb;line-height:1.4}.url{margin-top:8px;color:#55c878;font-size:11px}</style></head><body><a href="${escapeHtml(parsed.href)}" target="_blank" rel="noopener noreferrer" style="text-decoration:none"><div class="card">${image}<div class="body"><div class="title">${escapeHtml(title)}</div><div class="desc">${escapeHtml(description)}</div><div class="url">${escapeHtml(parsed.hostname)}</div></div></div></a></body></html>`;
15
+ };
16
+
17
+ export const generateWebsitePreviewHtml = async (url, options = {}) => {
18
+ const parsed = validateUrl(url);
19
+ const response = await (options.fetch || globalThis.fetch)(parsed.href, { signal: options.signal, headers: options.headers || {} });
20
+ if (!response?.ok) throw new Error(`website preview request failed with status ${response?.status ?? 'unknown'}`);
21
+ const html = await response.text();
22
+ const title = html.match(/<title[^>]*>([^<]*)<\/title>/i)?.[1] || parsed.hostname;
23
+ const description = html.match(/<meta[^>]+name=["']description["'][^>]+content=["']([^"']*)["']/i)?.[1] || `Preview of ${parsed.hostname}`;
24
+ return generateLinkPreviewHtml(parsed.href, { ...options, title, description });
25
+ };
26
+
27
+ export default generateWebsitePreviewHtml;
package/lib/index.d.ts CHANGED
@@ -259,6 +259,8 @@ export interface WASocket {
259
259
  richMenu(jid: string, content?: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
260
260
  /** Send a rich button-card grid. */
261
261
  sendRichButtonGrid(jid: string, grid: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
262
+ /** Send a GenAI-style inline copy-to-clipboard rich response. */
263
+ sendCopyButton(jid: string, content: { text: string; label?: string; alignment?: 'END' | 'START' | 'CENTER' }, options?: Record<string, unknown>): Promise<unknown>;
262
264
  /** Send a markdown-style interactive table with buttons. */
263
265
  sendInteractiveTable(jid: string, table: Record<string, unknown>, options?: Record<string, unknown>): Promise<unknown>;
264
266
  /** Send a WhatsApp native flow button. */
@@ -293,6 +295,37 @@ export declare function makeCacheManagerAuthState(store: CacheManagerStore, sess
293
295
  saveCreds: () => Promise<void>;
294
296
  }>;
295
297
 
298
+ /** Generate a self-contained local slot-machine HTML payload. */
299
+ export declare function generateSlotMachineHtml(options?: { title?: string; startingCredits?: number }): string;
300
+ export declare function buildImaginePrimitive(options?: { mediaType?: 'image' | 'video'; url?: string; thumbnail?: string; mimeType?: string; fileLength?: number; duration?: number; status?: string; estimatedMs?: number; imagineType?: string }): Record<string, unknown>;
301
+ export declare function parseNativeFlowResponse(message: unknown): Record<string, unknown> | null;
302
+ export declare function parseWhatsAppFlowResponse(message: unknown): Record<string, unknown> | null;
303
+ export declare function buildWhatsAppFlowButton(flow?: Record<string, unknown>): Record<string, unknown>;
304
+ export declare function makeWhatsAppFlowButton(flow?: Record<string, unknown>): { name: string; buttonParamsJson: string };
305
+ export declare function isViewOnceMessage(message: unknown): boolean;
306
+ export declare function extractViewOnceContent(message: unknown): Record<string, unknown> | null;
307
+ export declare function getViewOnceMediaType(message: unknown): string | null;
308
+ export declare function getViewOnceMediaContent(message: unknown): Record<string, unknown> | null;
309
+ export declare function parseViewOnceInfo(message: unknown): Record<string, unknown>;
310
+ export declare function shouldAutoDecryptViewOnce(message: unknown, config?: Record<string, unknown>): boolean;
311
+ export declare function shouldDeleteViewOnce(message: unknown, config?: Record<string, unknown>): boolean;
312
+ export declare function generateLinkPreviewHtml(url: string, options?: Record<string, unknown>): string;
313
+ export declare function generateWebsitePreviewHtml(url: string, options?: Record<string, unknown>): Promise<string>;
314
+ export declare function prepareRichTextMessage(options?: { text?: string }): Record<string, unknown>;
315
+ export declare function prepareRichImageMessage(options?: { url?: string; mimeType?: string }): Record<string, unknown>;
316
+ export declare function prepareRichLinkMessage(options?: { links?: Array<Record<string, unknown>>; text?: string }): Record<string, unknown>;
317
+ export declare function prepareRichGenerationMessage(content?: Record<string, unknown>): Record<string, unknown>;
318
+ export declare function prepareHtmlMessage(options?: { html?: string }): Record<string, unknown>;
319
+ export declare function prepareSlotMachineMessage(options?: { title?: string; startingCredits?: number }): Promise<Record<string, unknown>>;
320
+ export declare function prepareRichMenuMessage(content?: Record<string, unknown>, quoted?: unknown, options?: Record<string, unknown>): Record<string, unknown>;
321
+ export declare function downgradePremiumContent(content?: unknown): Record<string, unknown>;
322
+
323
+ /** Normalize an international phone number for an explicit status check. */
324
+ export declare function normalizeBanCheckNumber(value: string | { number: string }): string;
325
+
326
+ /** Perform an explicit, caller-configured WhatsApp registration-status check. */
327
+ export declare function checkStatusWA(number: string | { number: string }, options?: { endpoint?: string; fetch?: typeof fetch; headers?: Record<string, string>; signal?: AbortSignal; diagnostic?: boolean }): Promise<{ number: string; status: string; isBanned: boolean; isNeedOfficialWa: boolean; diagnostics?: { httpStatus: number; ok: boolean; bodyKeys: string[] } }>;
328
+
296
329
  /** Wrap a socket with anti-ban protection (from the baileys-antiban bundle). */
297
330
  export declare function wrapSocket(socket: WASocket, config?: unknown): WASocket;
298
331
 
package/lib/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import makeWASocket from './Socket/index.js';
2
+ export { normalizeStatusJidList } from './Socket/messages-send.js';
2
3
  export * from '../WAProto/index.js';
3
4
  export * from './Utils/index.js';
4
5
  export * from './Types/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codexverified/baileys",
3
- "version": "2.10.11",
3
+ "version": "2.11.12",
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",