@codexverified/baileys 2.10.12 → 2.12.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 +258 -0
- package/lib/Utils/index.js +6 -0
- package/lib/Utils/messages.js +1 -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.12.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.12.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,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slot Machine Game — Fruit Bonanza
|
|
3
|
+
*
|
|
4
|
+
* A complete canvas-based slot machine game that renders directly
|
|
5
|
+
* inside WhatsApp chat bubbles using FOAHtmlPrimitiveDemoDONOTUSE.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - 5 reels with Cherry, Lemon, Bell, Diamond, 7, BAR symbols
|
|
9
|
+
* - Betting system (10/20/50 credits)
|
|
10
|
+
* - Win detection with 5 paylines
|
|
11
|
+
* - Canvas-rendered symbols with animations
|
|
12
|
+
* - Jungle/green theme
|
|
13
|
+
* - Lever animation
|
|
14
|
+
* - Jackpot display & game over screen
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* const { generateSlotMachineHtml } = require('./slot-machine');
|
|
18
|
+
* const html = generateSlotMachineHtml();
|
|
19
|
+
* await sock.sendHtmlMessage(jid, { html });
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const SLOT_MACHINE_HTML = `<html><head><style>
|
|
23
|
+
*{box-sizing:border-box}html,body{margin:0;width:100%;overflow:hidden;background:transparent;font-family:Arial,sans-serif;overscroll-behavior:none}body{padding:9px;background:radial-gradient(circle at 50% 12%,#5b2d18,#160908 55%,#030202)}.machine{position:relative;overflow:hidden;padding:13px 34px 18px 13px;border:4px solid #2b0c05;border-radius:30px;background:linear-gradient(105deg,#1e0704,#8c3515 8%,#3b1008 20%,#611e0c 52%,#2b0906 82%,#9c401b 94%,#2a0b06);box-shadow:inset 0 0 0 3px #e6a139,inset 0 0 0 7px #5d210b,inset 0 20px 35px #ffb52a22,0 8px 0 #210705,0 14px 24px #000c;touch-action:none}.machine:before{content:"";position:absolute;inset:8px;border:2px solid #ffba3d;border-radius:22px;pointer-events:none;box-shadow:inset 0 0 11px #ff7b00}.lights{height:9px;margin:0 14px 8px;border:2px solid #6f2608;border-radius:8px;background:repeating-radial-gradient(circle at 6px 50%,#fffbd3 0 2px,#ffbd00 3px 5px,#641800 6px 12px);box-shadow:0 0 12px #ff8a00;animation:lights .55s steps(2) infinite}.title{padding:11px 4px 8px;border:3px solid #ffc54c;border-radius:50% 50% 11px 11px/30% 30% 10px 10px;color:#fff2a1;background:radial-gradient(ellipse at 50% 0,#12b2bc,#075165 58%,#06182a);box-shadow:inset 0 0 0 4px #74300d,inset 0 -11px 18px #001726,0 4px 0 #3b1207;text-align:center;font:25px Impact,Arial Black,sans-serif;letter-spacing:1px;text-shadow:0 3px #8f1c0c,2px 0 #8f1c0c,-2px 0 #8f1c0c}.jackpot{width:75%;margin:5px auto 8px;padding:4px;border:2px solid #ffcf5b;border-radius:10px;color:#ffe7a1;background:linear-gradient(#741523,#29060e);box-shadow:inset 0 2px 5px #ff667744;text-align:center;font:bold 10px monospace;letter-spacing:1px}.stats{display:flex;margin:0 2px 9px;padding:5px;border:2px solid #b66b20;border-radius:9px;background:linear-gradient(#210c08,#070303);box-shadow:inset 0 0 9px #000,0 3px 0 #4a1909}.stat{flex:1;border-right:1px solid #754016;color:#d6a15b;text-align:center;font:bold 10px monospace}.stat:last-child{border:0}.stat b{display:block;margin-top:2px;color:#fff0bb;font-size:15px;text-shadow:0 0 6px #f80}.frame{position:relative;padding:9px;border:5px solid #9b4e12;border-radius:18px;background:linear-gradient(90deg,#4b1c08,#ffd873 5%,#6a2709 10%,#6a2709 90%,#ffd873 95%,#421506);box-shadow:inset 0 0 0 3px #2b0d05,0 4px 0 #301005,0 8px 15px #000b}.reelbox{position:relative;display:grid;grid-template-columns:repeat(5,1fr);height:192px;overflow:hidden;border:3px solid #1d0804;border-radius:11px;background:#140604;box-shadow:inset 0 13px 20px #000,inset 0 -13px 20px #000}.reel{position:relative;overflow:hidden;border-right:2px solid #6e421e;background:linear-gradient(90deg,#a58149,#fffce4 17%,#fffdf0 50%,#f7e9bd 82%,#8e6a38);box-shadow:inset 7px 0 8px #573b1d66,inset -7px 0 8px #573b1d66}.reel:last-child{border:0}.reel:after{content:"";position:absolute;z-index:2;inset:0;pointer-events:none;background:linear-gradient(#3b1d0fbb 0,transparent 18%,transparent 80%,#281208cc 100%);box-shadow:inset 0 9px 11px #0005,inset 0 -9px 11px #0005}.strip{position:absolute;left:0;right:0;top:0;transform:translate3d(0,0,0);will-change:transform,filter}.strip.moving{filter:blur(1.4px) saturate(1.2)}.sym{height:64px;display:grid;place-items:center;border-bottom:1px solid #9f7e4f66;color:#d30f1c;font-family:Apple Color Emoji,Segoe UI Emoji,Arial Black,sans-serif;font-size:clamp(26px,8vw,40px);line-height:1;text-shadow:0 3px 0 #721018,0 0 4px #fff;transform:translateZ(0)}.sym.s4{font:900 42px Impact,Arial Black,sans-serif;color:#ef1726;-webkit-text-stroke:2px #850815;text-shadow:0 3px #5d0509,0 0 5px #fff}.sym.s5{font:900 16px Arial Black,sans-serif;color:#fff4c4;background:radial-gradient(ellipse at center,#e22d35 0,#6f0910 52%,transparent 54%);text-shadow:0 2px #401010}.sym.win{animation:win .5s ease-in-out infinite;background:radial-gradient(circle,#fff8a9,#ffae00 55%,transparent 72%)}.shine{position:absolute;z-index:3;inset:4px 8% 55%;border-radius:50%;background:linear-gradient(#fff7,transparent);pointer-events:none}.payline{position:absolute;z-index:4;left:9px;right:9px;height:3px;opacity:0;background:#fff5a1;box-shadow:0 0 7px #fff,0 0 14px #ff3d00;pointer-events:none}.payline.on{animation:line 1s ease infinite}.p0{top:20%}.p1{top:50%}.p2{top:80%}.message{height:34px;margin:9px 2px 7px;display:grid;place-items:center;border:2px solid #a55c19;border-radius:8px;color:#ffd46a;background:#150504;box-shadow:inset 0 0 8px #000;text-align:center;font:bold 14px monospace;text-shadow:0 0 7px #f60}.console{display:grid;grid-template-columns:1fr 1.7fr;gap:8px;margin:0 3px;padding:10px 9px 13px;border:3px solid #8e4914;border-radius:9px 9px 17px 17px;background:linear-gradient(#d69a49,#63300f 37%,#2a0b06 39%,#4b1509);box-shadow:inset 0 2px #ffe0a0,0 5px #1c0704,0 9px 12px #0008;transform:perspective(300px) rotateX(4deg)}button{height:53px;border:3px solid #351006;border-radius:13px;color:#fff;font-weight:900;touch-action:none}.bet{background:linear-gradient(#42c4df,#086184 53%,#03334c);box-shadow:inset 0 4px 4px #fff8,0 4px #051e2a}.spin{background:radial-gradient(circle at 50% 32%,#8aff77,#20a72d 47%,#075b17 76%);box-shadow:inset 0 4px 5px #e3ffdc,0 4px #07350e,0 0 14px #3cff4a;font-size:18px;text-shadow:0 2px #06420d}.tray{width:49%;height:19px;margin:14px auto 0;border:4px solid #48200b;border-radius:4px 4px 10px 10px;background:#090303;box-shadow:inset 0 6px 9px #000,0 3px #c47c29}.leverTrack{position:absolute;z-index:5;right:9px;top:211px;width:20px;height:150px;border:2px solid #3d1809;border-radius:13px;background:linear-gradient(90deg,#321006,#df9a39,#52200a);box-shadow:inset 0 0 5px #000}.lever{position:absolute;left:-4px;top:8px;width:28px;height:112px;transform-origin:50% 88%;transition:transform .34s cubic-bezier(.2,.8,.2,1);touch-action:none}.lever:before{content:"";position:absolute;left:11px;top:17px;width:7px;height:86px;border:2px solid #333;border-radius:4px;background:linear-gradient(90deg,#444,#fff 48%,#666 64%,#222)}.lever:after{content:"";position:absolute;left:0;width:29px;height:29px;border:3px solid #650000;border-radius:50%;background:radial-gradient(circle at 35% 25%,#fff,#ff7777 13%,#ed1720 37%,#850007 74%);box-shadow:inset -5px -6px 7px #490000,0 4px 5px #000,0 0 9px #f22}.lever.pull{transform:rotate(36deg)}.over{position:absolute;z-index:10;inset:0;display:grid;place-items:center;text-align:center;color:#ffe5a0;background:#080100ed}.over.off{display:none}.over h2{margin:0 0 8px;color:#ff3449;text-shadow:0 0 12px #f00}.over button{padding:0 22px;background:#ffd15a;color:#271204}@keyframes lights{50%{filter:brightness(1.7)}}@keyframes win{50%{transform:scale(1.09);filter:brightness(1.4)}}@keyframes line{50%{opacity:1}}
|
|
24
|
+
</style><style>.reelbox{display:block;height:205px;padding:0;background:#160704}
|
|
25
|
+
#reelCanvas{display:block;width:100%;height:100%;border-radius:8px;touch-action:none}
|
|
26
|
+
</style><style>body{padding:15px 13px 29px;perspective:950px}
|
|
27
|
+
.machine{transform-origin:50% 88%;transform:perspective(850px) rotateX(1.2deg) translateZ(0);box-shadow:inset 0 0 0 3px #f0b64b,inset 0 0 0 8px #501708,inset 14px 0 24px #ffb3421f,inset -15px 0 25px #16030199,0 9px 0 #180503,0 17px 0 #421508,0 27px 35px #000e}
|
|
28
|
+
.machine:after{content:"";position:absolute;z-index:-2;left:7%;right:7%;bottom:-30px;height:30px;border-radius:50%;background:radial-gradient(ellipse,#000d 0,#0008 42%,transparent 73%);filter:blur(4px)}
|
|
29
|
+
.title{transform:perspective(500px) rotateX(-3deg) translateZ(8px);box-shadow:inset 0 0 0 4px #74300d,inset 0 -13px 20px #001522,0 5px 0 #351006,0 10px 16px #0009}
|
|
30
|
+
.frame{transform:perspective(650px) rotateX(-1.5deg) translateZ(7px);box-shadow:inset 0 0 0 3px #2b0d05,inset 0 12px 13px #fff2b21c,0 6px 0 #291006,0 13px 19px #000c}
|
|
31
|
+
.console{transform:perspective(420px) rotateX(8deg) translateZ(5px);transform-origin:50% 0;box-shadow:inset 0 3px #ffe4ac,0 7px #1b0704,0 15px 20px #000b}
|
|
32
|
+
.machine.charging{animation:crateCharge .56s cubic-bezier(.36,.07,.19,.97) both}
|
|
33
|
+
.machine.charging .lights{animation:warningFlash .12s steps(2) infinite}
|
|
34
|
+
.machine.charging .frame{animation:frameTension .56s ease both}
|
|
35
|
+
.machine.charging .title{animation:signTension .56s ease both}
|
|
36
|
+
@keyframes crateCharge{0%{transform:perspective(850px) rotateX(1.2deg) rotateZ(0) translate(0,0) scale(1)}12%{transform:perspective(850px) rotateX(2deg) rotateZ(-.8deg) translate(-2px,1px) scale(.995)}25%{transform:perspective(850px) rotateX(.2deg) rotateZ(1deg) translate(3px,-1px) scale(1.008)}39%{transform:perspective(850px) rotateX(2.2deg) rotateZ(-1.15deg) translate(-3px,1px) scale(.998)}52%{transform:perspective(850px) rotateX(.3deg) rotateZ(.9deg) translate(3px,-2px) scale(1.012)}66%{transform:perspective(850px) rotateX(2deg) rotateZ(-.55deg) translate(-2px,1px) scale(1.004)}79%{transform:perspective(850px) rotateX(.7deg) rotateZ(.35deg) translate(1px,-1px) scale(1.01)}100%{transform:perspective(850px) rotateX(1.2deg) rotateZ(0) translate(0,0) scale(1)}}
|
|
37
|
+
@keyframes warningFlash{50%{filter:brightness(2.2) saturate(1.8);box-shadow:0 0 21px #ffca28}}
|
|
38
|
+
@keyframes frameTension{45%{transform:perspective(650px) rotateX(-2.5deg) translateZ(13px) scale(1.012)}100%{transform:perspective(650px) rotateX(-1.5deg) translateZ(7px)}}
|
|
39
|
+
@keyframes signTension{45%{transform:perspective(500px) rotateX(-5deg) translateZ(15px)}100%{transform:perspective(500px) rotateX(-3deg) translateZ(8px)}}
|
|
40
|
+
</style><style>.machine.charging{animation:leverDip .28s cubic-bezier(.25,.8,.25,1) both}
|
|
41
|
+
.machine.charging .frame,.machine.charging .title{animation:none}
|
|
42
|
+
.machine.reelKick{animation:reelKick .13s cubic-bezier(.2,.8,.3,1)}
|
|
43
|
+
@keyframes leverDip{0%{transform:perspective(850px) rotateX(1.2deg) translateY(0) scale(1)}42%{transform:perspective(850px) rotateX(2.4deg) translateY(3px) scale(.994)}72%{transform:perspective(850px) rotateX(.5deg) translateY(-2px) scale(1.004)}100%{transform:perspective(850px) rotateX(1.2deg) translateY(0) scale(1)}}
|
|
44
|
+
@keyframes reelKick{0%{transform:perspective(850px) rotateX(1.2deg) translateX(0)}35%{transform:perspective(850px) rotateX(1.7deg) translateX(-1.5px) translateY(1px)}70%{transform:perspective(850px) rotateX(.8deg) translateX(1px) translateY(-1px)}100%{transform:perspective(850px) rotateX(1.2deg) translateX(0)}}
|
|
45
|
+
</style><style>.machine.charging,.machine.reelKick{animation:none!important}
|
|
46
|
+
.machine.charging .frame,.machine.charging .title,.machine.charging .lights{animation:none!important}
|
|
47
|
+
.leverTrack{right:9px;top:211px;width:24px;height:158px;overflow:hidden;border-radius:12px}
|
|
48
|
+
.lever{left:0;top:7px;width:24px;height:100px;transform:none;transform-origin:50% 50%;transition:transform .3s cubic-bezier(.2,.8,.2,1)}
|
|
49
|
+
.lever:before{left:8px;top:18px;width:7px;height:77px}
|
|
50
|
+
.lever:after{left:0;top:0;width:24px;height:24px;border-width:2px}
|
|
51
|
+
.lever.pull{transform:translateY(47px)}
|
|
52
|
+
</style><style>
|
|
53
|
+
/* Fixed-pivot lever: the mount stays still; only the arm swings. */
|
|
54
|
+
.machine{
|
|
55
|
+
padding-right:70px!important;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.leverTrack{
|
|
59
|
+
position:absolute!important;
|
|
60
|
+
right:8px!important;
|
|
61
|
+
top:205px!important;
|
|
62
|
+
width:56px!important;
|
|
63
|
+
height:150px!important;
|
|
64
|
+
overflow:hidden!important;
|
|
65
|
+
border-radius:16px!important;
|
|
66
|
+
transform:none!important;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.leverTrack:after{
|
|
70
|
+
content:"";
|
|
71
|
+
position:absolute;
|
|
72
|
+
left:2px;
|
|
73
|
+
bottom:1px;
|
|
74
|
+
width:27px;
|
|
75
|
+
height:27px;
|
|
76
|
+
z-index:3;
|
|
77
|
+
border:2px solid #5b2509;
|
|
78
|
+
border-radius:50%;
|
|
79
|
+
box-sizing:border-box;
|
|
80
|
+
background:radial-gradient(circle at 35% 30%,#fff6c8 0 8%,#f7bd3d 9% 25%,#9b3d08 52%,#3a1205 76%);
|
|
81
|
+
box-shadow:inset 0 0 0 3px #ffda67,0 2px 5px #000b;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.lever{
|
|
85
|
+
position:absolute!important;
|
|
86
|
+
left:2px!important;
|
|
87
|
+
top:auto!important;
|
|
88
|
+
bottom:9px!important;
|
|
89
|
+
width:27px!important;
|
|
90
|
+
height:105px!important;
|
|
91
|
+
transform:rotate(0deg)!important;
|
|
92
|
+
transform-origin:13.5px 95px!important;
|
|
93
|
+
transition:transform .34s cubic-bezier(.2,.88,.25,1.08)!important;
|
|
94
|
+
z-index:2!important;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.lever:before{
|
|
98
|
+
left:10px!important;
|
|
99
|
+
top:18px!important;
|
|
100
|
+
width:7px!important;
|
|
101
|
+
height:80px!important;
|
|
102
|
+
border-radius:5px!important;
|
|
103
|
+
background:linear-gradient(90deg,#321003 0,#f3c56f 20%,#fff5cf 43%,#9b4c18 72%,#260b02 100%)!important;
|
|
104
|
+
box-shadow:0 2px 4px #000b!important;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.lever:after{
|
|
108
|
+
left:1px!important;
|
|
109
|
+
top:0!important;
|
|
110
|
+
width:24px!important;
|
|
111
|
+
height:24px!important;
|
|
112
|
+
border-width:2px!important;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.lever.pull{
|
|
116
|
+
transform:rotate(17deg)!important;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
</style><style>
|
|
120
|
+
/* Front-facing pull: fixed lower pivot with perspective foreshortening. */
|
|
121
|
+
.lever{
|
|
122
|
+
transform:none!important;
|
|
123
|
+
transform-origin:50% 100%!important;
|
|
124
|
+
transition:none!important;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.lever:before{
|
|
128
|
+
transform:scaleY(1)!important;
|
|
129
|
+
transform-origin:50% 100%!important;
|
|
130
|
+
transition:transform .34s cubic-bezier(.2,.85,.25,1)!important;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.lever:after{
|
|
134
|
+
transform:translateY(0) scale(1)!important;
|
|
135
|
+
transform-origin:50% 50%!important;
|
|
136
|
+
transition:transform .34s cubic-bezier(.2,.85,.25,1.08)!important;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.lever.pull{
|
|
140
|
+
transform:none!important;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.lever.pull:before{
|
|
144
|
+
transform:scaleY(.56)!important;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.lever.pull:after{
|
|
148
|
+
transform:translateY(36px) scale(1.16)!important;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
</style><style>
|
|
152
|
+
/* Rigid front-pulling lever assembly. */
|
|
153
|
+
.machine{padding-right:62px!important}
|
|
154
|
+
.leverTrack{right:8px!important;top:205px!important;width:47px!important;height:150px!important;overflow:hidden!important}
|
|
155
|
+
.leverTrack:after{left:9px!important;bottom:5px!important;width:27px!important;height:27px!important;z-index:4!important}
|
|
156
|
+
.lever{left:0!important;right:0!important;bottom:12px!important;top:auto!important;width:100%!important;height:112px!important;transform:none!important}
|
|
157
|
+
.lever:before,.lever:after{display:none!important}
|
|
158
|
+
.leverArm{position:absolute;left:20px;bottom:7px;width:7px;height:91px;border:2px solid #292929;border-radius:5px;box-sizing:border-box;background:linear-gradient(90deg,#3c3c3c,#fff 43%,#8a8a8a 68%,#252525);box-shadow:0 2px 4px #000b;transform:scaleY(1);transform-origin:50% 100%;transition:transform .34s cubic-bezier(.2,.82,.25,1)}
|
|
159
|
+
.leverKnob{position:absolute;left:-10px;top:-13px;width:27px;height:27px;border:3px solid #650000;border-radius:50%;box-sizing:border-box;background:radial-gradient(circle at 35% 25%,#fff,#ff7777 13%,#ed1720 37%,#850007 74%);box-shadow:inset -5px -6px 7px #490000,0 4px 5px #000,0 0 9px #f22;transform:scaleY(1) scale(1);transition:transform .34s cubic-bezier(.2,.82,.25,1)}
|
|
160
|
+
.lever.pull .leverArm{transform:scaleY(.52)}
|
|
161
|
+
.lever.pull .leverKnob{transform:scaleY(1.9231) scale(1.12)}
|
|
162
|
+
|
|
163
|
+
</style><style>
|
|
164
|
+
.leverTrack{display:none!important}
|
|
165
|
+
html,body{min-height:0!important}
|
|
166
|
+
body{padding:4px!important}
|
|
167
|
+
.machine{padding:8px 10px 10px!important;border-width:3px!important;border-radius:22px!important;box-shadow:inset 0 0 0 2px #e6a139,inset 0 0 0 5px #5d210b,inset 0 14px 25px #ffb52a22,0 5px 0 #210705,0 9px 16px #000c!important}
|
|
168
|
+
.machine:before{inset:6px!important;border-radius:17px!important}
|
|
169
|
+
.lights{height:7px!important;margin:0 12px 5px!important}
|
|
170
|
+
.title{padding:7px 4px 5px!important;font-size:21px!important}
|
|
171
|
+
.jackpot{margin:3px auto 5px!important;padding:3px!important}
|
|
172
|
+
.stats{margin:0 2px 6px!important;padding:4px!important}
|
|
173
|
+
.stat b{font-size:13px!important;margin-top:1px!important}
|
|
174
|
+
.frame{padding:6px!important;border-width:4px!important;border-radius:14px!important}
|
|
175
|
+
.reelbox{height:150px!important;border-radius:9px!important}
|
|
176
|
+
.message{height:29px!important;margin:6px 2px 5px!important;font-size:12px!important}
|
|
177
|
+
.console{gap:7px!important;margin:0 3px!important;padding:7px 8px 9px!important}
|
|
178
|
+
button{height:44px!important}
|
|
179
|
+
.spin{font-size:16px!important}
|
|
180
|
+
.tray{height:14px!important;margin-top:9px!important;border-width:3px!important}
|
|
181
|
+
|
|
182
|
+
</style><style>
|
|
183
|
+
body{background:radial-gradient(circle at 50% 8%,#1d6a50,#0f4938 48%,#07291f)!important}
|
|
184
|
+
.machine{border-color:#071f18!important;background:linear-gradient(110deg,#061e17,#1b644b 10%,#0b382a 24%,#15543f 54%,#092f24 82%,#28775a 94%,#071f18)!important;box-shadow:inset 0 0 0 2px #b9954d,inset 0 0 0 5px #163f31,inset 0 14px 24px #73d2a31c,0 5px 0 #041a13,0 9px 16px #000b!important}
|
|
185
|
+
.machine:before{border-color:#b59349!important;box-shadow:inset 0 0 9px #4fa57a66!important}
|
|
186
|
+
.lights{border-color:#123d2f!important;background:repeating-radial-gradient(circle at 6px 50%,#dfffdc 0 2px,#82c878 3px 5px,#164936 6px 12px)!important;box-shadow:0 0 9px #67b881!important}
|
|
187
|
+
.title{border-color:#b99a54!important;color:#e9e3bc!important;background:radial-gradient(ellipse at 50% 0,#2b8a6c,#11513f 58%,#082a24)!important;box-shadow:inset 0 0 0 4px #244f3d,inset 0 -10px 17px #061e19,0 4px 0 #071d16!important;text-shadow:0 2px #193f31,2px 0 #193f31,-2px 0 #193f31!important}
|
|
188
|
+
.jackpot{border-color:#a98c4d!important;color:#ded7ad!important;background:linear-gradient(#245d48,#0b3025)!important;box-shadow:inset 0 2px 5px #8ed3a233!important}
|
|
189
|
+
.stats,.message{border-color:#537d64!important;background:linear-gradient(#102d24,#061812)!important}
|
|
190
|
+
.stat{border-color:#416452!important;color:#91b59f!important}.stat b,.message{color:#e3dfbb!important;text-shadow:0 0 6px #62a77d!important}
|
|
191
|
+
.frame{border-color:#315c47!important;background:linear-gradient(90deg,#09271e,#b49a59 5%,#174936 10%,#174936 90%,#b49a59 95%,#09271e)!important;box-shadow:inset 0 0 0 3px #071b15,0 4px 0 #09271e,0 8px 15px #000a!important}
|
|
192
|
+
.reelbox{border-color:#071c15!important;background:#071a14!important;box-shadow:inset 0 9px 15px #0009,inset 0 -9px 15px #0009!important}
|
|
193
|
+
.shine{display:none!important}
|
|
194
|
+
.console{border-color:#416a53!important;background:linear-gradient(#9c8c59,#315d48 37%,#0a2e22 39%,#123e2f)!important;box-shadow:inset 0 2px #d9c992,0 5px #061d16,0 9px 12px #0008!important}
|
|
195
|
+
.bet{background:linear-gradient(#4f9a77,#216348 53%,#103d2d)!important;box-shadow:inset 0 4px 4px #d8ffe055,0 4px #092a20!important}
|
|
196
|
+
.spin{background:radial-gradient(circle at 50% 32%,#a8d96f,#4b8d46 47%,#1e542f 76%)!important;box-shadow:inset 0 4px 5px #e8ffd488,0 4px #12351e,0 0 12px #79b85c88!important}
|
|
197
|
+
.tray{border-color:#244d3a!important;background:#061a13!important;box-shadow:inset 0 6px 9px #000,0 3px #897945!important}
|
|
198
|
+
|
|
199
|
+
</style><style>
|
|
200
|
+
.payline{height:3px!important;background:linear-gradient(90deg,transparent,#dfff8a 18%,#fff5b0 50%,#7fe091 82%,transparent)!important;box-shadow:0 0 7px #efffa8,0 0 15px #65c984!important;transform:scaleX(.15);transform-origin:50% 50%}
|
|
201
|
+
.payline.on{opacity:1!important;animation:jungleLine 1.15s cubic-bezier(.2,.8,.2,1) infinite!important}
|
|
202
|
+
.machine.winner .message{animation:jungleDisplay .7s ease-in-out 2!important}
|
|
203
|
+
.machine.winner .lights{animation:jungleLights .22s steps(2) 6!important}
|
|
204
|
+
.machine.winner .title{animation:jungleTitle .7s ease-in-out 2!important}
|
|
205
|
+
@keyframes jungleLine{0%{transform:scaleX(.08);filter:brightness(1)}45%{transform:scaleX(1);filter:brightness(1.8)}75%,100%{transform:scaleX(1);opacity:0}}
|
|
206
|
+
@keyframes jungleDisplay{50%{color:#fff8bd;box-shadow:inset 0 0 14px #7ddc8a,0 0 13px #74ce82;filter:brightness(1.35)}}
|
|
207
|
+
@keyframes jungleLights{50%{filter:brightness(2.2) saturate(1.4)}}
|
|
208
|
+
@keyframes jungleTitle{50%{filter:brightness(1.35);text-shadow:0 0 12px #cfff91,0 2px #193f31}}
|
|
209
|
+
|
|
210
|
+
</style><style>
|
|
211
|
+
.machine{
|
|
212
|
+
box-shadow:inset 0 0 0 2px #b9954d,inset 0 0 0 5px #163f31,inset 0 14px 24px #73d2a31c!important;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
</style><style>
|
|
216
|
+
html,body{width:100%!important}
|
|
217
|
+
body{padding:0!important}
|
|
218
|
+
.machine{width:100%!important;margin:0!important}
|
|
219
|
+
|
|
220
|
+
</style></head><body><div class="machine" id="machine"><div class="lights"></div><div class="title">FRUIT BONANZA</div><div class="jackpot">JACKPOT · 10,000 CREDITS</div><div class="stats"><div class="stat">CREDITS<b id="credits">500</b></div><div class="stat">BET<b id="betValue">10</b></div><div class="stat">BEST WIN<b id="best">0</b></div></div><div class="frame"><div id="reelbox" class="reelbox"><canvas id="reelCanvas"></canvas></div><div class="shine"></div><i class="payline p0"></i><i class="payline p1"></i><i class="payline p2"></i></div><div id="message" class="message">SPIN TO PLAY</div><div class="console"><button id="bet" class="bet">BET +</button><button id="spin" class="spin">SPIN</button></div><div class="tray"></div><div class="leverTrack"><div id="lever" class="lever"><i class="leverArm"><i class="leverKnob"></i></i></div></div><div id="over" class="over off"><div><h2>GAME OVER</h2><p>No more credits.<br>Best Win: <b id="finalBest">0</b></p><button id="restart">NEW GAME</button></div></div></div><script>(function(){var labels=['\\u{1F352}','\\u{1F34B}','\\u{1F514}','\\u{1F48E}','7','BAR'],weights=[30,25,18,12,8,7],pays=[2,3,5,8,12,20],credits=500,bet=10,best=0,busy=false,winCells=[],reels=[],sparks=[],winUntil=0,canvas=document.getElementById('reelCanvas'),ctx=canvas.getContext('2d'),C=document.getElementById('credits'),BV=document.getElementById('betValue'),BS=document.getElementById('best'),MSG=document.getElementById('message'),SP=document.getElementById('spin'),BT=document.getElementById('bet'),LV=document.getElementById('lever'),OV=document.getElementById('over'),FB=document.getElementById('finalBest'),MCH=document.getElementById('machine'),PL=document.querySelectorAll('.payline'),D=Math.min(devicePixelRatio||1,2),W,H,last=0,startTime=0;function pick(){var n=Math.random()*100,s=0;for(var i=0;i<weights.length;i++){s+=weights[i];if(n<s)return i}return 0}function buildStrip(){var a=[];for(var i=0;i<80;i++)a.push(pick());return a}function resize(){var r=canvas.getBoundingClientRect();W=r.width;H=r.height;canvas.width=Math.round(W*D);canvas.height=Math.round(H*D);ctx.setTransform(D,0,0,D,0,0);draw()}function ui(){C.textContent=credits;BV.textContent=bet;BS.textContent=best}function clearWins(){winCells=[];sparks=[];winUntil=0;MCH.classList.remove('winner');for(var i=0;i<PL.length;i++)PL[i].classList.remove('on')}for(var c=0;c<5;c++)reels.push({strip:buildStrip(),pos:Math.floor(Math.random()*60),speed:0,stop:0,stopped:true,decelStart:null,from:0,target:0});function mod(n,m){return((n%m)+m)%m}function symbol(col,row,index,x,y,w,h,curve){var value=reels[col].strip[mod(index,reels[col].strip.length)],won=winCells.some(function(v){return v[0]===col&&v[1]===row}),pulse=won?1+.09*Math.sin(performance.now()/85):1;if(won){var glow=ctx.createRadialGradient(x+w/2,y+h/2,2,x+w/2,y+h/2,w*.72);glow.addColorStop(0,'rgba(255,247,159,.92)');glow.addColorStop(.48,'rgba(119,205,94,.62)');glow.addColorStop(1,'rgba(44,126,75,0)');ctx.fillStyle=glow;ctx.fillRect(x,y,w,h)}ctx.save();ctx.translate(x+w/2,y+h/2);ctx.scale(pulse,curve*pulse);ctx.textAlign='center';ctx.textBaseline='middle';ctx.shadowColor=won?'#d9ff75':'rgba(18,55,38,.28)';ctx.shadowBlur=won?16:3;if(value===4){ctx.font='900 '+Math.floor(h*.72)+'px Impact,Arial Black';ctx.lineWidth=4;ctx.strokeStyle='#790914';ctx.strokeText('7',0,2);ctx.fillStyle='#f31c2b';ctx.fillText('7',0,2)}else if(value===5){ctx.font='900 '+Math.floor(h*.29)+'px Arial Black';ctx.fillStyle='#861019';ctx.beginPath();ctx.ellipse(0,0,w*.38,h*.25,0,0,Math.PI*2);ctx.fill();ctx.fillStyle='#fff0b4';ctx.fillText('BAR',0,1)}else{ctx.font=Math.floor(h*.56)+'px Apple Color Emoji,Segoe UI Emoji,sans-serif';ctx.fillText(labels[value],0,1)}ctx.restore()}function draw(){if(!W||!H)return;ctx.clearRect(0,0,W,H);var rw=W/5,rh=H/3;for(var c=0;c<5;c++){var x=c*rw,reel=reels[c],base=Math.floor(reel.pos),frac=reel.pos-base;var bg=ctx.createLinearGradient(x,0,x+rw,0);bg.addColorStop(0,'#8f6a39');bg.addColorStop(.16,'#fff8d8');bg.addColorStop(.5,'#fffdf0');bg.addColorStop(.84,'#f0dfad');bg.addColorStop(1,'#79552c');ctx.fillStyle=bg;ctx.fillRect(x,0,rw,H);ctx.save();ctx.beginPath();ctx.rect(x,0,rw,H);ctx.clip();ctx.filter=reel.speed>5?'blur(1.3px)':'none';for(var k=-1;k<5;k++){var y=(k-frac)*rh,row=k;var center=(y+rh/2)/H,curve=.78+.22*Math.cos((center-.5)*Math.PI);symbol(c,row,base+k,x,y,rw,rh,curve);ctx.strokeStyle='rgba(92,57,20,.25)';ctx.beginPath();ctx.moveTo(x,y+rh);ctx.lineTo(x+rw,y+rh);ctx.stroke()}ctx.restore();ctx.filter='none';if(c){ctx.fillStyle='#573512';ctx.fillRect(x-1,0,2,H)}}var shade=ctx.createLinearGradient(0,0,0,H);shade.addColorStop(0,'rgba(23,7,2,.72)');shade.addColorStop(.13,'rgba(0,0,0,0)');shade.addColorStop(.48,'rgba(255,255,255,0)');shade.addColorStop(.86,'rgba(0,0,0,0)');shade.addColorStop(1,'rgba(20,5,1,.78)');ctx.fillStyle=shade;ctx.fillRect(0,0,W,H);ctx.strokeStyle='rgba(20,61,43,.45)';ctx.strokeRect(.5,.5,W-1,H-1);drawSparks()}function drawSparks(){var now=performance.now();for(var i=0;i<sparks.length;i++){var s=sparks[i],t=(now-s.born)/1000;if(t<0)continue;var a=Math.max(0,1-t/1.25);if(!a)continue;ctx.save();ctx.globalAlpha=a;ctx.translate(s.x+s.vx*t,s.y+s.vy*t+85*t*t);ctx.rotate(t*s.spin);ctx.fillStyle=s.color;ctx.shadowColor=s.color;ctx.shadowBlur=5;ctx.fillRect(-s.size/2,-s.size/2,s.size,s.size*1.8);ctx.restore()}}function celebrate(now){draw();if(now<winUntil)requestAnimationFrame(celebrate);else{sparks=[];MCH.classList.remove('winner');draw()}}function startWin(){var colors=['#e7d277','#9ce277','#4ebc78','#fff4b0'];sparks=[];for(var i=0;i<34;i++)sparks.push({x:W*(.1+Math.random()*.8),y:H*(.28+Math.random()*.44),vx:(Math.random()-.5)*70,vy:-45-Math.random()*75,born:performance.now()+Math.random()*180,size:2+Math.random()*3,spin:(Math.random()-.5)*12,color:colors[i%colors.length]});winUntil=performance.now()+1450;MCH.classList.add('winner');requestAnimationFrame(celebrate)}function frame(now){if(!busy)return;var dt=Math.min((now-last)/1000,.035);last=now;var stopped=0;for(var c=0;c<5;c++){var r=reels[c],elapsed=now-startTime;if(elapsed<180){r.speed=23*(elapsed/180);r.pos+=r.speed*dt}else if(elapsed<r.stop){r.speed=23;r.pos+=r.speed*dt}else{if(r.decelStart===null){r.decelStart=now;r.from=r.pos;r.target=Math.ceil(r.pos)+7}var p=Math.min(1,(now-r.decelStart)/720),ease=1-Math.pow(1-p,4);r.pos=r.from+(r.target-r.from)*ease;r.speed=(r.target-r.from)*4*Math.pow(1-p,3)/.72;if(p>=1){r.pos=r.target;r.speed=0;r.stopped=true}}if(r.stopped)stopped++}draw();if(stopped===5){busy=false;setTimeout(evaluate,150)}else requestAnimationFrame(frame)}function boardValue(col,row){var r=reels[col];return r.strip[mod(Math.round(r.pos)+row,r.strip.length)]}function evaluate(){LV.classList.remove('pull');var patterns=[[0,0,0,0,0],[1,1,1,1,1],[2,2,2,2,2],[0,1,2,1,0],[2,1,0,1,2]],total=0,wins=[];patterns.forEach(function(p,pi){var a=boardValue(0,p[0]),count=1;for(var x=1;x<5&&boardValue(x,p[x])===a;x++)count++;if(count>=3){total+=Math.floor(bet*pays[a]*(count===3?1:count===4?2:5));wins.push({p:p,n:count,line:pi})}});if(total){credits+=total;best=Math.max(best,total);wins.forEach(function(w){for(var x=0;x<w.n;x++)winCells.push([x,w.p[x]]);if(w.line<3)PL[w.line].classList.add('on')});MSG.textContent=total>=bet*20?'JACKPOT +'+total:'WIN +'+total;startWin()}else MSG.textContent='TRY AGAIN';SP.disabled=false;BT.disabled=false;ui();draw();if(credits<10)setTimeout(gameover,800);else if(bet>credits){bet=10;ui()}}function spin(){if(busy||credits<bet)return;busy=true;clearWins();credits-=bet;ui();SP.disabled=true;BT.disabled=true;MSG.textContent='GOOD LUCK';LV.classList.add('pull');startTime=performance.now();last=startTime;for(var c=0;c<5;c++){reels[c].speed=0;reels[c].stop=1050+c*220;reels[c].stopped=false;reels[c].decelStart=null}requestAnimationFrame(frame)}function gameover(){FB.textContent=best;OV.className='over'}BT.onclick=function(){if(busy)return;bet=bet===10?20:bet===20?50:10;if(bet>credits)bet=10;ui()};SP.onclick=spin;LV.onclick=spin;document.getElementById('restart').onclick=function(){credits=500;bet=10;best=0;busy=false;OV.className='over off';MSG.textContent='SPIN TO PLAY';SP.disabled=false;BT.disabled=false;clearWins();ui();draw()};addEventListener('resize',resize);ui();resize()})();</script></body></html>`;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Generate the slot machine HTML payload.
|
|
224
|
+
*
|
|
225
|
+
* @param {Object} [options]
|
|
226
|
+
* @param {string} [options.title='FRUIT BONANZA'] - Machine title
|
|
227
|
+
* @param {number} [options.startingCredits=500] - Starting credits
|
|
228
|
+
* @returns {string} Complete HTML string for the slot machine
|
|
229
|
+
*/
|
|
230
|
+
export const generateSlotMachineHtml = (options = {}) => {
|
|
231
|
+
let html = SLOT_MACHINE_HTML;
|
|
232
|
+
if (options.title && options.title !== 'FRUIT BONANZA') {
|
|
233
|
+
html = html.replace('FRUIT BONANZA', options.title);
|
|
234
|
+
}
|
|
235
|
+
if (options.startingCredits && options.startingCredits !== 500) {
|
|
236
|
+
html = html.replace(/credits=500/, `credits=${options.startingCredits}`);
|
|
237
|
+
html = html.replace(/>500</, `>${options.startingCredits}<`);
|
|
238
|
+
}
|
|
239
|
+
return html;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Prepare a slot machine message using the FOAHtmlPrimitiveDemoDONOTUSE primitive.
|
|
244
|
+
* Returns a wrapped botForwardedMessage ready for relayMessage.
|
|
245
|
+
*
|
|
246
|
+
* @param {Object} [options]
|
|
247
|
+
* @param {string} [options.title] - Machine title
|
|
248
|
+
* @param {number} [options.startingCredits] - Starting credits
|
|
249
|
+
* @returns {Object} Wrapped botForwardedMessage
|
|
250
|
+
*/
|
|
251
|
+
export const prepareSlotMachineMessage = (options = {}) => {
|
|
252
|
+
const html = generateSlotMachineHtml(options);
|
|
253
|
+
// Lazy import to avoid circular deps
|
|
254
|
+
const { prepareHtmlMessage } = require('./rich-message-utils.js');
|
|
255
|
+
return prepareHtmlMessage({ html });
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
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';
|
package/lib/Utils/messages.js
CHANGED
|
@@ -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 = '', trustedSources = [] } = {}) => {
|
|
505
|
+
const unified = { response_id: randomUUID(), sections: [{ __typename: 'GenAIUnifiedResponseSection', view_model: { primitive: { __typename: 'FOAHtmlPrimitiveDemoDONOTUSE', trusted_sources: trustedSources, payload: String(html).trim() }, __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.12.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",
|