@codexverified/baileys 2.10.12 → 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 +216 -99
- package/lib/Socket/index.js +1 -1
- package/lib/Socket/messages-send.js +8 -1
- package/lib/Utils/ban-checker.js +48 -0
- package/lib/Utils/games/slot-machine.js +19 -0
- package/lib/Utils/index.js +6 -0
- package/lib/Utils/native-flow.js +48 -0
- package/lib/Utils/portable-compat.js +12 -0
- package/lib/Utils/rich-message-utils.js +108 -2
- package/lib/Utils/view-once-utils.js +56 -0
- package/lib/Utils/website-preview.js +27 -0
- package/lib/index.d.ts +33 -0
- package/lib/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,19 +1,44 @@
|
|
|
1
1
|
# @codexverified/baileys
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@codexverified/baileys)
|
|
4
|
+
[](#at-a-glance)
|
|
5
|
+
[](#license-and-maintenance)
|
|
6
|
+
[](#at-a-glance)
|
|
7
|
+
|
|
3
8
|
> A readable, carefully maintained Baileys distribution for building reliable WhatsApp integrations with codexverified/baileys.
|
|
4
9
|
|
|
5
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.
|
|
6
11
|
|
|
7
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.
|
|
8
13
|
|
|
9
|
-
##
|
|
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)
|
|
10
35
|
|
|
11
|
-
|
|
36
|
+
## At a glance
|
|
12
37
|
|
|
13
38
|
| Property | Value |
|
|
14
39
|
| --- | --- |
|
|
15
40
|
| Package | `@codexverified/baileys` |
|
|
16
|
-
| Version | `2.
|
|
41
|
+
| Version | `2.11.12` |
|
|
17
42
|
| Runtime | Node.js 20 or newer |
|
|
18
43
|
| Module format | ESM, with CommonJS compatibility where supported |
|
|
19
44
|
| Type declarations | Included at `lib/index.d.ts` |
|
|
@@ -24,30 +49,18 @@ This release is version **2.10.12**. It uses ECMAScript modules, supports Common
|
|
|
24
49
|
|
|
25
50
|
## Installation
|
|
26
51
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
npm install
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
To install a local package archive, place the `.tgz` file beside your application and run:
|
|
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 |
|
|
34
57
|
|
|
35
|
-
|
|
36
|
-
npm install ./codex-baileys-2.10.12.tgz
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Both installation methods use the same import name:
|
|
58
|
+
Both npm and archive installs use the same import name:
|
|
40
59
|
|
|
41
60
|
```javascript
|
|
42
61
|
import { makeWASocket } from '@codexverified/baileys'
|
|
43
62
|
```
|
|
44
63
|
|
|
45
|
-
For local source auditing, install dependencies without executing package installation hooks:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npm install --ignore-scripts
|
|
49
|
-
```
|
|
50
|
-
|
|
51
64
|
## Quick start
|
|
52
65
|
|
|
53
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.
|
|
@@ -99,8 +112,6 @@ start().catch(console.error)
|
|
|
99
112
|
|
|
100
113
|
## CommonJS usage
|
|
101
114
|
|
|
102
|
-
For supported Node.js versions, the package can also be loaded through CommonJS:
|
|
103
|
-
|
|
104
115
|
```javascript
|
|
105
116
|
const {
|
|
106
117
|
makeWASocket,
|
|
@@ -112,88 +123,52 @@ If your runtime or bundler does not support this interop path, use the ESM impor
|
|
|
112
123
|
|
|
113
124
|
## Core capabilities
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
The package includes interactive buttons, lists, native flows, hydrated templates, carousel layouts, button grids, and other structured message formats. Interactive identifiers should be stable and unique within the application. Receiving code should handle the possibility that different WhatsApp clients deliver a selected value through different response envelopes.
|
|
130
|
-
|
|
131
|
-
### Rich content and previews
|
|
132
|
-
|
|
133
|
-
Rich-response utilities cover code blocks, tables, inline entities, LaTeX-oriented content, link previews, and structured response arrays. Rich previews can fetch a title, description, and image for a URL when the optional dependency and network access are available. Applications should retain a plain-text fallback for clients that do not render rich content.
|
|
134
|
-
|
|
135
|
-
### Rich menus
|
|
136
|
-
|
|
137
|
-
The experimental `richMenu` helper builds a structured rich-response envelope with an optional header image, row or carousel cards, stable button identifiers, toast metadata, disclaimers, and a footer action. The package also exposes lower-level preparation utilities for applications that need more control. Rich menus are client-dependent and should be tested against the WhatsApp versions used by the application.
|
|
138
|
-
|
|
139
|
-
### Groups and communities
|
|
140
|
-
|
|
141
|
-
Group operations include group creation, participant management, settings, metadata, invites, labels, and community relationships. Community helpers support linked groups and subgroup operations where the connected account and current protocol permit them.
|
|
142
|
-
|
|
143
|
-
### Newsletters and channel operations
|
|
144
|
-
|
|
145
|
-
Newsletter utilities cover channel metadata, following and unfollowing, posts, reactions, media, and polls. Following is consumer-controlled: the library does not silently follow a trusted channel, inject a fallback channel identifier, or add an automatic channel pill to generated media. Applications should request newsletter actions explicitly and validate identifiers before sending requests.
|
|
146
|
-
|
|
147
|
-
### Account, business, and privacy tools
|
|
148
|
-
|
|
149
|
-
The package includes profile and business helpers, product and catalog operations, privacy controls, username utilities, account-layer and interoperation helpers, status publishing, favorites management, and selected account-management operations. Availability depends on the connected account, WhatsApp rollout, and the permissions associated with that account.
|
|
150
|
-
|
|
151
|
-
### Storage and protocol utilities
|
|
152
|
-
|
|
153
|
-
The distribution includes in-memory and ordered-dictionary stores, cache-manager support, authentication persistence, LID and phone-number resolution, event utilities, message normalization, media retry handling, protocol helpers, and TypeScript declarations in `lib/index.d.ts`.
|
|
126
|
+
| Area | What it covers |
|
|
127
|
+
| --- | --- |
|
|
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 |
|
|
154
139
|
|
|
155
140
|
## Everyday message usage
|
|
156
141
|
|
|
157
|
-
|
|
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 |
|
|
158
149
|
|
|
159
150
|
```javascript
|
|
160
151
|
await sock.sendMessage(jid, {
|
|
161
152
|
text: 'A message from Codex'
|
|
162
153
|
})
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
Send media with a caption:
|
|
166
154
|
|
|
167
|
-
```javascript
|
|
168
155
|
await sock.sendMessage(jid, {
|
|
169
156
|
image: { url: './media/photo.jpg' },
|
|
170
157
|
caption: 'A photo message'
|
|
171
158
|
})
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Send a video with GIF-style playback enabled:
|
|
175
159
|
|
|
176
|
-
```javascript
|
|
177
160
|
await sock.sendMessage(jid, {
|
|
178
161
|
video: { url: './media/animation.mp4' },
|
|
179
162
|
gifPlayback: true,
|
|
180
163
|
caption: 'Animated media'
|
|
181
164
|
})
|
|
182
|
-
```
|
|
183
165
|
|
|
184
|
-
Use the existing explicit view-once options when you want the media to use a view-once envelope:
|
|
185
|
-
|
|
186
|
-
```javascript
|
|
187
166
|
await sock.sendMessage(jid, {
|
|
188
167
|
image: { url: './media/private-image.jpg' },
|
|
189
168
|
caption: 'Open once',
|
|
190
169
|
viewOnce: true
|
|
191
170
|
})
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
The compatible `mediaSpoilerMode` option provides an additional explicit path. Set it to `viewOnce` for supported image, video, document, or sticker media, or set it to `native` to apply the native spoiler context flag. The option is intentionally opt-in and does not change the default behavior of existing applications.
|
|
195
171
|
|
|
196
|
-
```javascript
|
|
197
172
|
await sock.sendMessage(jid, {
|
|
198
173
|
video: { url: './media/clip.mp4' },
|
|
199
174
|
caption: 'View-once video',
|
|
@@ -206,11 +181,16 @@ await sock.sendMessage(jid, {
|
|
|
206
181
|
})
|
|
207
182
|
```
|
|
208
183
|
|
|
209
|
-
|
|
184
|
+
`mediaSpoilerMode` is an additional, opt-in path for supported image, video, document, or sticker media:
|
|
210
185
|
|
|
211
|
-
|
|
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.
|
|
212
192
|
|
|
213
|
-
|
|
193
|
+
## Rich menu example
|
|
214
194
|
|
|
215
195
|
```javascript
|
|
216
196
|
await sock.richMenu(jid, {
|
|
@@ -245,9 +225,21 @@ await sock.richMenu(jid, {
|
|
|
245
225
|
})
|
|
246
226
|
```
|
|
247
227
|
|
|
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
|
+
|
|
248
235
|
## Status, grids, tables, and flows
|
|
249
236
|
|
|
250
|
-
|
|
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 |
|
|
251
243
|
|
|
252
244
|
```javascript
|
|
253
245
|
await sock.sendStatus({ text: 'New Codex status' }, {
|
|
@@ -287,14 +279,17 @@ These helpers are protocol- and client-dependent. Use graceful fallbacks when an
|
|
|
287
279
|
|
|
288
280
|
## Authentication and deployment guidance
|
|
289
281
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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 |
|
|
293
290
|
|
|
294
291
|
## Development workflow
|
|
295
292
|
|
|
296
|
-
Run the package tests with:
|
|
297
|
-
|
|
298
293
|
```bash
|
|
299
294
|
npm test
|
|
300
295
|
```
|
|
@@ -303,33 +298,155 @@ Before submitting changes, validate ESM syntax, CommonJS compatibility where app
|
|
|
303
298
|
|
|
304
299
|
## Recent compatibility updates
|
|
305
300
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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 |
|
|
309
306
|
|
|
310
307
|
## About Codex
|
|
311
308
|
|
|
312
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.
|
|
313
310
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
317
|
|
|
318
|
-
|
|
319
|
-
Email: codexauthorized@gmail.com
|
|
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.
|
|
320
319
|
|
|
321
320
|
## Package layout
|
|
322
321
|
|
|
323
|
-
|
|
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 |
|
|
324
329
|
|
|
325
330
|
## Security and responsible use
|
|
326
331
|
|
|
327
|
-
This library interacts with WhatsApp accounts and user communications.
|
|
332
|
+
This library interacts with WhatsApp accounts and user communications.
|
|
328
333
|
|
|
329
|
-
|
|
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 |
|
|
330
343
|
|
|
331
344
|
## License and maintenance
|
|
332
345
|
|
|
333
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.
|
|
334
347
|
|
|
335
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
|
+
})
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
As with other private or experimental WhatsApp rich-response layouts, clients may fall back to plain rendering or ignore the addon action.
|
|
373
|
+
|
|
374
|
+
### Slot-machine HTML generator
|
|
375
|
+
|
|
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.
|
|
377
|
+
|
|
378
|
+
| Option | Purpose |
|
|
379
|
+
| --- | --- |
|
|
380
|
+
| `title` | Display title for the generated page |
|
|
381
|
+
| `startingCredits` | Initial credit balance |
|
|
382
|
+
|
|
383
|
+
```javascript
|
|
384
|
+
import { generateSlotMachineHtml } from '@codexverified/baileys'
|
|
385
|
+
|
|
386
|
+
const html = generateSlotMachineHtml({
|
|
387
|
+
title: 'Codex Fruit Bonanza',
|
|
388
|
+
startingCredits: 500
|
|
389
|
+
})
|
|
390
|
+
```
|
|
391
|
+
|
|
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.
|
|
393
|
+
|
|
394
|
+
### Optional ban-status checker
|
|
395
|
+
|
|
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.
|
|
397
|
+
|
|
398
|
+
```javascript
|
|
399
|
+
import { checkStatusWA } from '@codexverified/baileys'
|
|
400
|
+
|
|
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/
|
|
424
|
+
|
|
425
|
+
## Additional functional compatibility helpers
|
|
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.
|
|
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
|
package/lib/Socket/index.js
CHANGED
|
@@ -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/
|
|
39
|
+
`${blue}${center('@codexverified/baileys')}${reset}\n` +
|
|
40
40
|
`${yellow}${center('premium baileys built by codex')}${reset}\n`
|
|
41
41
|
);
|
|
42
42
|
}
|
|
@@ -16,7 +16,7 @@ import { collectMetaAIBotParticipantJids, isMetaAIBotResponse, META_AI_BOT_JID }
|
|
|
16
16
|
import { makeUsernameSocket } from './username.js';
|
|
17
17
|
|
|
18
18
|
const STATUS_JID = 'status@broadcast';
|
|
19
|
-
const normalizeStatusJidList = (value) => {
|
|
19
|
+
export const normalizeStatusJidList = (value) => {
|
|
20
20
|
if (!Array.isArray(value) || value.length === 0) {
|
|
21
21
|
throw new Boom('statusJidList must contain at least one recipient JID', { statusCode: 400 });
|
|
22
22
|
}
|
|
@@ -1223,6 +1223,13 @@ export const makeMessagesSocket = (config) => {
|
|
|
1223
1223
|
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata });
|
|
1224
1224
|
return fullMsg;
|
|
1225
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
|
+
},
|
|
1226
1233
|
sendInteractiveTable: async (jid, table, options = {}) => {
|
|
1227
1234
|
const { title = '', headers = [], rows = [], image, buttons = [], footer } = table || {};
|
|
1228
1235
|
if (!Array.isArray(headers) || !Array.isArray(rows) || !Array.isArray(buttons)) throw new Boom('sendInteractiveTable expects headers, rows, and buttons arrays', { statusCode: 400 });
|
|
@@ -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
|
+
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
|
|
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;
|
package/lib/Utils/index.js
CHANGED
|
@@ -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';
|
|
@@ -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
|
|
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) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codexverified/baileys",
|
|
3
|
-
"version": "2.
|
|
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",
|