my-baileys 1.0.1 → 1.0.2
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 +48 -0
- package/lib/Utils/binary-codec.js +230 -0
- package/lib/Utils/index.js +1 -0
- package/package.json +3 -1
- package/scripts/self-test.js +141 -0
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ Built on top of [Baileys](https://github.com/WhiskeySockets/Baileys) (WhiskeySoc
|
|
|
37
37
|
- [Guard against unexpected group-joins and DMs](#guard-against-unexpected-group-joins-and-dms)
|
|
38
38
|
- [AntiBanned (fresh-number throttle)](#antibanned-fresh-number-send-throttle)
|
|
39
39
|
- [AntiBan (full send-safety suite)](#antiban-full-send-safety-suite)
|
|
40
|
+
- [Binary codec (Protobuf wire-format primitives)](#binary-codec-protobuf-wire-format-primitives)
|
|
40
41
|
- [Message-builder (extra send helpers)](#message-builder-extra-send-helpers)
|
|
41
42
|
- [AI watermark on button messages](#ai-watermark-on-button-messages)
|
|
42
43
|
- [ACK monitor](#ack-monitor)
|
|
@@ -529,6 +530,53 @@ for what each sub-module does and how they fit together.
|
|
|
529
530
|
|
|
530
531
|
---
|
|
531
532
|
|
|
533
|
+
## Binary codec (Protobuf wire-format primitives)
|
|
534
|
+
|
|
535
|
+
Low-level Protocol Buffers wire-format helpers, exported for building your own custom
|
|
536
|
+
binary/protobuf-shaped payloads — see [`lib/Utils/binary-codec.js`](lib/Utils/binary-codec.js).
|
|
537
|
+
This doesn't touch how Baileys encodes/decodes WhatsApp's own messages (that's still
|
|
538
|
+
`protobufjs` via `WAProto/index.js`, which you should keep using for anything WhatsApp-facing);
|
|
539
|
+
it's for when *you* need direct control over some wire bytes of your own.
|
|
540
|
+
|
|
541
|
+
```javascript
|
|
542
|
+
import { encodeVarint, decodeVarint, zigzagEncode32, zigzagDecode32,
|
|
543
|
+
encodeFixed32, encodeFixed64, encodeTag, decodeTag,
|
|
544
|
+
encodeLengthDelimited, decodeLengthDelimited,
|
|
545
|
+
BufferWriter, WireType } from '@xayz/baileys';
|
|
546
|
+
|
|
547
|
+
// varint — the base encoding used for VARINT fields and every length prefix
|
|
548
|
+
encodeVarint(300); // -> <Buffer ac 02>
|
|
549
|
+
encodeVarint(123456789012345678n); // BigInt for values a plain Number can't hold precisely
|
|
550
|
+
|
|
551
|
+
// ZigZag — for sint32/sint64 fields (keeps small negative numbers short)
|
|
552
|
+
zigzagEncode32(-1); // -> 1
|
|
553
|
+
zigzagDecode32(1); // -> -1
|
|
554
|
+
|
|
555
|
+
// fixed-width (always little-endian, matches fixed32/fixed64/float/double)
|
|
556
|
+
encodeFixed32(1); // -> <Buffer 01 00 00 00>
|
|
557
|
+
encodeFixed64(1n); // -> <Buffer 01 00 00 00 00 00 00 00>
|
|
558
|
+
|
|
559
|
+
// length-delimited framing — the spec-correct version of a manual
|
|
560
|
+
// `wrapPayload(tagBuffer, data)` helper: pass a field number, get a proper tag
|
|
561
|
+
encodeLengthDelimited(1, Buffer.from('hello')); // tag + varint length + data
|
|
562
|
+
|
|
563
|
+
// building a multi-field message without a Buffer.concat() per field
|
|
564
|
+
const w = new BufferWriter();
|
|
565
|
+
w.writeTag(1, WireType.VARINT).writeVarint(300);
|
|
566
|
+
w.writeLengthDelimited(2, Buffer.from('xayz'));
|
|
567
|
+
const message = w.finish();
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**On Buffer allocation efficiency** (`BufferWriter`'s reason for existing): chaining
|
|
571
|
+
`Buffer.concat([a, b])` calls in a loop allocates a brand-new buffer and copies *everything so
|
|
572
|
+
far* on every call — that's O(n²) total copying for n fields, and wastes the zero-fill
|
|
573
|
+
`Buffer.alloc()` normally does on bytes you're about to overwrite anyway. `BufferWriter` instead
|
|
574
|
+
pre-allocates with `Buffer.allocUnsafe()` and only grows (by doubling) when it actually runs
|
|
575
|
+
out of room, so N writes cost O(N) overall, not O(N²) — the difference matters once you're
|
|
576
|
+
writing more than a handful of fields per message.
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
532
580
|
## Message-builder (extra send helpers)
|
|
533
581
|
|
|
534
582
|
A set of convenience methods bolted onto every socket for content types that would otherwise
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/Utils/binary-codec.js — general-purpose Protocol Buffers wire-format
|
|
3
|
+
* primitives: varint, ZigZag (sint32/sint64), fixed32/fixed64, and
|
|
4
|
+
* length-delimited framing, plus a growable BufferWriter for building up a
|
|
5
|
+
* message without repeated small allocations.
|
|
6
|
+
*
|
|
7
|
+
* This is a from-scratch, standalone module — it does not replace or touch
|
|
8
|
+
* the small `encodeVarint`/`decodeVarint` pair already private to
|
|
9
|
+
* lib/Utils/reporting-utils.js (used only for one WAM-reporting feature).
|
|
10
|
+
* That pair is intentionally 32-bit-only for its narrow use case; the
|
|
11
|
+
* functions here are exported for general use and are correct up to the
|
|
12
|
+
* full 64-bit range protobuf's own spec allows (using BigInt where a
|
|
13
|
+
* regular Number would lose precision).
|
|
14
|
+
*
|
|
15
|
+
* None of this is wired into WhatsApp's own protocol handling — Baileys
|
|
16
|
+
* already encodes/decodes the real WAProto messages via `protobufjs`
|
|
17
|
+
* (see WAProto/index.js), which is the correct, spec-complete way to do
|
|
18
|
+
* that and shouldn't be replaced by hand-rolled encoding. This module is
|
|
19
|
+
* for your OWN custom binary/protobuf-shaped payloads (e.g. a custom field
|
|
20
|
+
* inside messageContextInfo, or a side-channel binary format) where you
|
|
21
|
+
* want direct control over the wire bytes.
|
|
22
|
+
*
|
|
23
|
+
* Wire format reference: https://protobuf.dev/programming-guides/encoding/
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** Protobuf wire types (the low 3 bits of every field tag). */
|
|
27
|
+
export const WireType = {
|
|
28
|
+
VARINT: 0, // int32, int64, uint32, uint64, sint32, sint64, bool, enum
|
|
29
|
+
FIXED64: 1, // fixed64, sfixed64, double
|
|
30
|
+
LENGTH_DELIMITED: 2, // string, bytes, embedded messages, packed repeated fields
|
|
31
|
+
START_GROUP: 3, // deprecated in proto3 — included for completeness only
|
|
32
|
+
END_GROUP: 4, // deprecated in proto3 — included for completeness only
|
|
33
|
+
FIXED32: 5 // fixed32, sfixed32, float
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// --- Varint (used directly for VARINT wire type, and for the length prefix
|
|
37
|
+
// of every LENGTH_DELIMITED field) ---
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Encodes a non-negative integer as a protobuf varint.
|
|
41
|
+
* Accepts a Number (must be a safe, non-negative integer) or a BigInt
|
|
42
|
+
* (use BigInt for values that don't fit in a 32-bit int, e.g. uint64/int64
|
|
43
|
+
* field values > 2^32 — a plain Number loses precision above 2^53).
|
|
44
|
+
*/
|
|
45
|
+
export const encodeVarint = (value) => {
|
|
46
|
+
let n = typeof value === 'bigint' ? value : BigInt(value);
|
|
47
|
+
if (n < 0n) {
|
|
48
|
+
throw new RangeError('encodeVarint: value must be non-negative — use zigzagEncode32/64 first for signed (sint32/sint64) fields');
|
|
49
|
+
}
|
|
50
|
+
const bytes = [];
|
|
51
|
+
while (n >= 0x80n) {
|
|
52
|
+
bytes.push(Number(n & 0x7fn) | 0x80);
|
|
53
|
+
n >>= 7n;
|
|
54
|
+
}
|
|
55
|
+
bytes.push(Number(n));
|
|
56
|
+
return Buffer.from(bytes);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Decodes a varint starting at `offset`.
|
|
61
|
+
* Returns `{ value, bytesRead }`. `value` is a Number if it fits safely
|
|
62
|
+
* (<= Number.MAX_SAFE_INTEGER), otherwise a BigInt — check
|
|
63
|
+
* `typeof result.value` if you need to know which you got.
|
|
64
|
+
*/
|
|
65
|
+
export const decodeVarint = (buffer, offset = 0) => {
|
|
66
|
+
let result = 0n;
|
|
67
|
+
let shift = 0n;
|
|
68
|
+
let bytesRead = 0;
|
|
69
|
+
while (true) {
|
|
70
|
+
if (offset + bytesRead >= buffer.length) {
|
|
71
|
+
throw new RangeError('decodeVarint: unexpected end of buffer');
|
|
72
|
+
}
|
|
73
|
+
const byte = buffer[offset + bytesRead];
|
|
74
|
+
result |= BigInt(byte & 0x7f) << shift;
|
|
75
|
+
bytesRead++;
|
|
76
|
+
if ((byte & 0x80) === 0) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
shift += 7n;
|
|
80
|
+
if (shift > 70n) {
|
|
81
|
+
throw new RangeError('decodeVarint: varint is too long (more than 10 bytes)');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const value = result <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(result) : result;
|
|
85
|
+
return { value, bytesRead };
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// --- ZigZag encoding (for sint32/sint64 — maps signed values to unsigned
|
|
89
|
+
// ones so small-magnitude negative numbers still encode as short varints) ---
|
|
90
|
+
|
|
91
|
+
/** ZigZag-encodes a 32-bit signed integer. `n` must be in the int32 range. */
|
|
92
|
+
export const zigzagEncode32 = (n) => ((n << 1) ^ (n >> 31)) >>> 0;
|
|
93
|
+
|
|
94
|
+
/** Decodes a ZigZag-encoded 32-bit unsigned integer back to a signed int32. */
|
|
95
|
+
export const zigzagDecode32 = (n) => (n >>> 1) ^ -(n & 1);
|
|
96
|
+
|
|
97
|
+
/** ZigZag-encodes a 64-bit signed integer (BigInt in, BigInt out). */
|
|
98
|
+
export const zigzagEncode64 = (n) => {
|
|
99
|
+
const v = typeof n === 'bigint' ? n : BigInt(n);
|
|
100
|
+
return BigInt.asUintN(64, (v << 1n) ^ (v >> 63n));
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/** Decodes a ZigZag-encoded 64-bit unsigned BigInt back to a signed BigInt. */
|
|
104
|
+
export const zigzagDecode64 = (n) => {
|
|
105
|
+
const v = typeof n === 'bigint' ? n : BigInt(n);
|
|
106
|
+
return (v >> 1n) ^ -(v & 1n);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// --- Fixed-width encodings (always little-endian, per the protobuf spec) ---
|
|
110
|
+
|
|
111
|
+
/** Encodes a 32-bit value as 4 fixed little-endian bytes (fixed32/sfixed32/float use this width). */
|
|
112
|
+
export const encodeFixed32 = (n) => {
|
|
113
|
+
const buf = Buffer.allocUnsafe(4);
|
|
114
|
+
buf.writeUInt32LE(n >>> 0, 0);
|
|
115
|
+
return buf;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** Decodes 4 little-endian bytes at `offset` back to an unsigned 32-bit integer. */
|
|
119
|
+
export const decodeFixed32 = (buffer, offset = 0) => buffer.readUInt32LE(offset);
|
|
120
|
+
|
|
121
|
+
/** Encodes a 64-bit value (BigInt) as 8 fixed little-endian bytes (fixed64/sfixed64/double use this width). */
|
|
122
|
+
export const encodeFixed64 = (n) => {
|
|
123
|
+
const buf = Buffer.allocUnsafe(8);
|
|
124
|
+
buf.writeBigUInt64LE(BigInt.asUintN(64, typeof n === 'bigint' ? n : BigInt(n)), 0);
|
|
125
|
+
return buf;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/** Decodes 8 little-endian bytes at `offset` back to an unsigned 64-bit BigInt. */
|
|
129
|
+
export const decodeFixed64 = (buffer, offset = 0) => buffer.readBigUInt64LE(offset);
|
|
130
|
+
|
|
131
|
+
// --- Field tags and length-delimited framing ---
|
|
132
|
+
|
|
133
|
+
/** Builds a protobuf field tag: `(fieldNumber << 3) | wireType`, varint-encoded. */
|
|
134
|
+
export const encodeTag = (fieldNumber, wireType) => encodeVarint((fieldNumber << 3) | wireType);
|
|
135
|
+
|
|
136
|
+
/** Splits a decoded tag varint back into `{ fieldNumber, wireType }`. */
|
|
137
|
+
export const decodeTag = (tagValue) => {
|
|
138
|
+
const n = typeof tagValue === 'bigint' ? Number(tagValue) : tagValue;
|
|
139
|
+
return { fieldNumber: n >>> 3, wireType: n & 0x7 };
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Frames `data` as a protobuf LENGTH_DELIMITED field: tag + varint length + data.
|
|
144
|
+
* This is the generalized, spec-correct version of the `wrapPayload(tag, data)`
|
|
145
|
+
* helper — pass a real field number instead of a raw tag Buffer and this
|
|
146
|
+
* builds a proper varint tag for you:
|
|
147
|
+
*
|
|
148
|
+
* wrapPayload(tagBuffer, data) // your original
|
|
149
|
+
* encodeLengthDelimited(fieldNumber, data) // spec-correct equivalent
|
|
150
|
+
*/
|
|
151
|
+
export const encodeLengthDelimited = (fieldNumber, data) => (
|
|
152
|
+
Buffer.concat([encodeTag(fieldNumber, WireType.LENGTH_DELIMITED), encodeVarint(data.length), data])
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Reads one length-delimited field's payload starting at `offset` (which
|
|
157
|
+
* must point at the length varint, i.e. right after the tag). Returns
|
|
158
|
+
* `{ data, bytesRead }` where `bytesRead` covers the length prefix AND the
|
|
159
|
+
* payload, so `offset + bytesRead` is the start of the next field.
|
|
160
|
+
*/
|
|
161
|
+
export const decodeLengthDelimited = (buffer, offset = 0) => {
|
|
162
|
+
const { value: length, bytesRead: lengthBytes } = decodeVarint(buffer, offset);
|
|
163
|
+
const len = typeof length === 'bigint' ? Number(length) : length;
|
|
164
|
+
const dataStart = offset + lengthBytes;
|
|
165
|
+
if (dataStart + len > buffer.length) {
|
|
166
|
+
throw new RangeError('decodeLengthDelimited: declared length exceeds buffer bounds');
|
|
167
|
+
}
|
|
168
|
+
return { data: buffer.subarray(dataStart, dataStart + len), bytesRead: lengthBytes + len };
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// --- Efficient buffer building ---
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* A growable buffer writer for building up a message field-by-field without
|
|
175
|
+
* a `Buffer.concat()` (and therefore a full copy) on every single write.
|
|
176
|
+
*
|
|
177
|
+
* Why this matters: `Buffer.concat([a, b])` allocates a brand-new buffer and
|
|
178
|
+
* copies both `a` and `b` into it every time. Chaining many small
|
|
179
|
+
* `Buffer.concat()` calls in a loop (once per field) is O(n²) in the total
|
|
180
|
+
* bytes written — fine for a handful of fields, wasteful for a message with
|
|
181
|
+
* hundreds. `BufferWriter` instead pre-allocates a working buffer with
|
|
182
|
+
* `Buffer.allocUnsafe` (skips the zero-fill `Buffer.alloc` normally does,
|
|
183
|
+
* safe here because every byte gets overwritten before being read) and
|
|
184
|
+
* doubles its capacity only when it actually runs out — so the amortized
|
|
185
|
+
* cost of N writes is O(N), not O(N²), and there's no wasted zero-filling.
|
|
186
|
+
*/
|
|
187
|
+
export class BufferWriter {
|
|
188
|
+
constructor(initialCapacity = 256) {
|
|
189
|
+
this._buf = Buffer.allocUnsafe(Math.max(initialCapacity, 16));
|
|
190
|
+
this._len = 0;
|
|
191
|
+
}
|
|
192
|
+
_ensure(extra) {
|
|
193
|
+
const needed = this._len + extra;
|
|
194
|
+
if (needed <= this._buf.length) return;
|
|
195
|
+
let newCapacity = this._buf.length * 2;
|
|
196
|
+
while (newCapacity < needed) newCapacity *= 2;
|
|
197
|
+
const grown = Buffer.allocUnsafe(newCapacity);
|
|
198
|
+
this._buf.copy(grown, 0, 0, this._len);
|
|
199
|
+
this._buf = grown;
|
|
200
|
+
}
|
|
201
|
+
writeBytes(data) {
|
|
202
|
+
this._ensure(data.length);
|
|
203
|
+
data.copy(this._buf, this._len);
|
|
204
|
+
this._len += data.length;
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
writeVarint(value) {
|
|
208
|
+
return this.writeBytes(encodeVarint(value));
|
|
209
|
+
}
|
|
210
|
+
writeTag(fieldNumber, wireType) {
|
|
211
|
+
return this.writeBytes(encodeTag(fieldNumber, wireType));
|
|
212
|
+
}
|
|
213
|
+
writeFixed32(n) {
|
|
214
|
+
return this.writeBytes(encodeFixed32(n));
|
|
215
|
+
}
|
|
216
|
+
writeFixed64(n) {
|
|
217
|
+
return this.writeBytes(encodeFixed64(n));
|
|
218
|
+
}
|
|
219
|
+
/** Writes a full LENGTH_DELIMITED field (tag + length + bytes) in one call. */
|
|
220
|
+
writeLengthDelimited(fieldNumber, data) {
|
|
221
|
+
return this.writeBytes(encodeLengthDelimited(fieldNumber, data));
|
|
222
|
+
}
|
|
223
|
+
get length() {
|
|
224
|
+
return this._len;
|
|
225
|
+
}
|
|
226
|
+
/** Returns the written bytes as a Buffer. Copies — safe to keep using the writer afterward. */
|
|
227
|
+
finish() {
|
|
228
|
+
return Buffer.from(this._buf.subarray(0, this._len));
|
|
229
|
+
}
|
|
230
|
+
}
|
package/lib/Utils/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-baileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"description": "A WebSockets library for interacting with WhatsApp Web — XYCoolcraft fork of Baileys",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"xycoolcraft",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"lib/**/*",
|
|
27
27
|
"WAProto/**/*",
|
|
28
|
+
"scripts/**/*",
|
|
28
29
|
"engine-requirements.js"
|
|
29
30
|
],
|
|
30
31
|
"scripts": {
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
"prepack": "",
|
|
40
41
|
"prepare": "",
|
|
41
42
|
"preinstall": "node ./engine-requirements.js",
|
|
43
|
+
"postinstall": "node ./scripts/self-test.js || exit 0",
|
|
42
44
|
"release": "release-it",
|
|
43
45
|
"test": "jest",
|
|
44
46
|
"publish:npm": "bash upload-npm.sh"
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* self-test.js — runs automatically right after `npm install` (via the
|
|
4
|
+
* "postinstall" script in package.json). Checks, BEFORE you write a single
|
|
5
|
+
* line of bot code:
|
|
6
|
+
* 1. The package's own files loaded correctly (no broken install).
|
|
7
|
+
* 2. This machine can actually open a WebSocket to WhatsApp's servers.
|
|
8
|
+
*
|
|
9
|
+
* Why: the single most common "why doesn't my bot work" report is a
|
|
10
|
+
* hosting/network problem that has nothing to do with your bot code —
|
|
11
|
+
* finding that out AFTER writing your whole bot is a waste of your time.
|
|
12
|
+
* This catches it at install time instead, with a clear pass/fail printed
|
|
13
|
+
* right in your terminal / panel console.
|
|
14
|
+
*
|
|
15
|
+
* This never fails the install itself (always exits 0) — a failing
|
|
16
|
+
* connectivity check here doesn't mean your files are broken, and blocking
|
|
17
|
+
* `npm install` over a transient network hiccup would be worse than useless
|
|
18
|
+
* in CI/CD pipelines. It just makes sure you SEE the warning before you go
|
|
19
|
+
* looking for bugs in the wrong place.
|
|
20
|
+
*
|
|
21
|
+
* Skip this entirely with: BAILEYS_SKIP_SELFTEST=1 npm install
|
|
22
|
+
*/
|
|
23
|
+
import chalk from 'chalk';
|
|
24
|
+
import WebSocket from 'ws';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
import path from 'node:path';
|
|
27
|
+
|
|
28
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
30
|
+
|
|
31
|
+
const results = [];
|
|
32
|
+
const record = (name, pass, detail = '') => results.push({ name, pass, detail });
|
|
33
|
+
|
|
34
|
+
function banner() {
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log(chalk.hex('#a855f7')('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
37
|
+
console.log(chalk.hex('#a855f7').bold(' @xayz/baileys — post-install self-test'));
|
|
38
|
+
console.log(chalk.gray(' Checking your environment before you start building your bot.'));
|
|
39
|
+
console.log(chalk.hex('#a855f7')('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
40
|
+
console.log('');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Check 1: did the package's own files load without throwing? */
|
|
44
|
+
async function testModuleIntegrity() {
|
|
45
|
+
try {
|
|
46
|
+
const mod = await import(path.join(packageRoot, 'lib', 'index.js'));
|
|
47
|
+
const ok = typeof mod.default === 'function';
|
|
48
|
+
record('Package installed correctly (makeWASocket loaded)', ok,
|
|
49
|
+
ok ? '' : 'lib/index.js loaded, but makeWASocket is not a function — the install may be corrupted. Try a clean `npm install` again.');
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
record('Package installed correctly (makeWASocket loaded)', false,
|
|
53
|
+
`Failed to import lib/index.js: ${e.message} — try removing node_modules and package-lock.json, then \`npm install\` again.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Check 2: can this machine actually open a WebSocket to WhatsApp's servers? */
|
|
58
|
+
function testNetworkReachability() {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
const url = 'wss://web.whatsapp.com/ws/chat';
|
|
61
|
+
const start = Date.now();
|
|
62
|
+
let done = false;
|
|
63
|
+
|
|
64
|
+
let ws;
|
|
65
|
+
try {
|
|
66
|
+
ws = new WebSocket(url, {
|
|
67
|
+
origin: 'https://web.whatsapp.com',
|
|
68
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' }
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
record('This server can reach WhatsApp', false, `Failed to open a connection: ${e.message}`);
|
|
73
|
+
resolve();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const finish = (pass, detail) => {
|
|
78
|
+
if (done) return;
|
|
79
|
+
done = true;
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
record('This server can reach WhatsApp', pass, detail);
|
|
82
|
+
try { ws.terminate(); } catch { }
|
|
83
|
+
resolve();
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const timer = setTimeout(() => {
|
|
87
|
+
finish(false, `Timed out after ${Date.now() - start}ms — the socket never opened. ` +
|
|
88
|
+
'This strongly suggests this network/host is blocking or throttling connections to ' +
|
|
89
|
+
'WhatsApp, NOT a code problem. Try a different server/IP if this keeps happening.');
|
|
90
|
+
}, 12000);
|
|
91
|
+
|
|
92
|
+
ws.on('open', () => finish(true, `Succeeded in ${Date.now() - start}ms`));
|
|
93
|
+
ws.on('error', (err) => finish(false, `${err.message} (after ${Date.now() - start}ms) — check your hosting's firewall/proxy.`));
|
|
94
|
+
ws.on('unexpected-response', (req, res) => {
|
|
95
|
+
finish(false, `Server responded, but it wasn't a WebSocket upgrade (HTTP ${res.statusCode}) — ` +
|
|
96
|
+
'an ISP or hosting proxy/firewall is likely intercepting this connection.');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function printResults() {
|
|
102
|
+
for (const r of results) {
|
|
103
|
+
const icon = r.pass ? chalk.green('✅') : chalk.red('❌');
|
|
104
|
+
console.log(`${icon} ${r.name}`);
|
|
105
|
+
if (r.detail) console.log(chalk.gray(` ${r.detail}`));
|
|
106
|
+
}
|
|
107
|
+
console.log('');
|
|
108
|
+
|
|
109
|
+
const allPass = results.every(r => r.pass);
|
|
110
|
+
if (allPass) {
|
|
111
|
+
console.log(chalk.green.bold(' All checks passed. You\'re good to go — start building/running your bot.'));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log(chalk.yellow.bold(' ⚠ Something above failed.'));
|
|
115
|
+
console.log(chalk.yellow(' This does NOT stop the install (so it won\'t break your CI/CD pipeline),'));
|
|
116
|
+
console.log(chalk.yellow(' but if your bot later fails to connect or pair, check the point above'));
|
|
117
|
+
console.log(chalk.yellow(' before you start debugging your code — it\'s the most likely cause.'));
|
|
118
|
+
}
|
|
119
|
+
console.log(chalk.hex('#a855f7')('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
120
|
+
console.log('');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
(async () => {
|
|
124
|
+
if (process.env.BAILEYS_SKIP_SELFTEST === '1') {
|
|
125
|
+
console.log(chalk.gray('[@xayz/baileys] Self-test skipped (BAILEYS_SKIP_SELFTEST=1).'));
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
banner();
|
|
130
|
+
await testModuleIntegrity();
|
|
131
|
+
await testNetworkReachability();
|
|
132
|
+
printResults();
|
|
133
|
+
|
|
134
|
+
// Always exit 0 — see the comment at the top of this file for why.
|
|
135
|
+
process.exit(0);
|
|
136
|
+
})().catch((e) => {
|
|
137
|
+
// Safety net: nothing that goes wrong in this TEST script itself should
|
|
138
|
+
// ever fail the user's `npm install`.
|
|
139
|
+
console.log(chalk.red(`[@xayz/baileys] Self-test error (ignored): ${e.message}`));
|
|
140
|
+
process.exit(0);
|
|
141
|
+
});
|