whalibmob 5.23.5 → 5.24.0
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 +3 -2
- package/index.d.ts +1114 -0
- package/package.json +13 -2
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ code, and bring the account into being. Both transports, one API.
|
|
|
11
11
|
[](https://www.npmjs.com/package/whalibmob)
|
|
12
12
|
[](https://nodejs.org)
|
|
13
13
|
[](LICENSE)
|
|
14
|
+
[](index.d.ts)
|
|
14
15
|
|
|
15
16
|
[](https://github.com/Kunboruto20/whalibmob/blob/main/Brasil.md)
|
|
16
17
|
|
|
@@ -49,8 +50,8 @@ If you want to talk with me contact me on Telegram my username îs @brtyu545
|
|
|
49
50
|
> [!CAUTION]
|
|
50
51
|
> Use a dedicated phone number with this library. Connecting with a number that is already active on a real device will cause WhatsApp to log that device out.
|
|
51
52
|
|
|
52
|
-
> [!
|
|
53
|
-
>
|
|
53
|
+
> [!NOTE]
|
|
54
|
+
> **Actively developed.** WhatsApp changed the mobile protocol recently, and whalibmob is being kept in step with it release by release. Contributions are welcome — pull requests are accepted.
|
|
54
55
|
|
|
55
56
|
> [!IMPORTANT]
|
|
56
57
|
> This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or affiliates. "WhatsApp" and related names are registered trademarks of their respective owners. Use at your own discretion.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,1114 @@
|
|
|
1
|
+
// Type definitions for whalibmob
|
|
2
|
+
// Project: https://github.com/Kunboruto20/whalibmob
|
|
3
|
+
//
|
|
4
|
+
// These declarations are derived from the implementation in lib/, not from the
|
|
5
|
+
// documentation. Where a shape was verified against the code it is described
|
|
6
|
+
// precisely; the Signal, WAM and protobuf internals are exported as `any`
|
|
7
|
+
// rather than guessed at, because a wrong type is worse than no type.
|
|
8
|
+
|
|
9
|
+
/// <reference types="node" />
|
|
10
|
+
|
|
11
|
+
import { EventEmitter } from 'events';
|
|
12
|
+
|
|
13
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
// Core aliases
|
|
15
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A WhatsApp address. Accepted anywhere a recipient is expected:
|
|
19
|
+
* - bare digits, country code first, no `+` — `'919634847671'`
|
|
20
|
+
* - a contact JID — `'919634847671@s.whatsapp.net'`
|
|
21
|
+
* - a group JID — `'120363000000000000@g.us'`
|
|
22
|
+
* - a LID — `'112713111982325@lid'`
|
|
23
|
+
* - a newsletter — `'120363000000000004@newsletter'`
|
|
24
|
+
* - status — `'status@broadcast'`
|
|
25
|
+
*/
|
|
26
|
+
export type Jid = string;
|
|
27
|
+
|
|
28
|
+
/** Anything the media senders accept: a file path, or the bytes themselves. */
|
|
29
|
+
export type MediaSource = string | Buffer | Uint8Array;
|
|
30
|
+
|
|
31
|
+
/** Delivery method for a verification code. */
|
|
32
|
+
export type CodeMethod = 'sms' | 'voice' | 'wa_old' | 'flash';
|
|
33
|
+
|
|
34
|
+
/** Result of a number-status lookup. */
|
|
35
|
+
export type NumberStatus =
|
|
36
|
+
| 'registered'
|
|
37
|
+
| 'registered_blocked'
|
|
38
|
+
| 'not_registered'
|
|
39
|
+
| 'cooldown'
|
|
40
|
+
| 'unknown';
|
|
41
|
+
|
|
42
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
// Store / device
|
|
44
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
export interface KeyPair {
|
|
47
|
+
private: Buffer;
|
|
48
|
+
public: Buffer;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SignedPreKey extends KeyPair {
|
|
52
|
+
id: number;
|
|
53
|
+
signature: Buffer;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The device profile a session announces. Built by `getDeviceConfig()`. */
|
|
57
|
+
export interface DeviceConfig {
|
|
58
|
+
os: 'ios' | 'android';
|
|
59
|
+
platform: number;
|
|
60
|
+
model: string;
|
|
61
|
+
manufacturer: string;
|
|
62
|
+
osVersion?: string;
|
|
63
|
+
build?: string;
|
|
64
|
+
modelId?: string;
|
|
65
|
+
business?: boolean;
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A registered (SMS / mobile) session, **in memory** — what `createNewStore`,
|
|
71
|
+
* `initAuthCreds`, `loadStore` and `storeFromJson` hand back.
|
|
72
|
+
*
|
|
73
|
+
* The binary fields are `Buffer`s here. The JSON `saveStore` writes holds the
|
|
74
|
+
* same fields base64-encoded, so a value read straight out of the session file
|
|
75
|
+
* with `JSON.parse` is a string where this says `Buffer`. Go through
|
|
76
|
+
* `loadStore` / `storeFromJson` and the Buffers are restored for you.
|
|
77
|
+
*/
|
|
78
|
+
export interface WhalibmobStore {
|
|
79
|
+
phoneNumber: string;
|
|
80
|
+
noiseKeyPair: KeyPair;
|
|
81
|
+
identityKeyPair: KeyPair;
|
|
82
|
+
signedPreKey: SignedPreKey;
|
|
83
|
+
registrationId: number;
|
|
84
|
+
/** A UUID string, not bytes. */
|
|
85
|
+
fdid: string;
|
|
86
|
+
deviceId: Buffer;
|
|
87
|
+
identityId: Buffer;
|
|
88
|
+
/** A UUID string, not bytes. */
|
|
89
|
+
advertisingId: string;
|
|
90
|
+
backupToken: Buffer;
|
|
91
|
+
/** `true` once `verifyCode` has succeeded. */
|
|
92
|
+
registered: boolean;
|
|
93
|
+
/** `true` between requesting a code and confirming it. */
|
|
94
|
+
codePending: boolean;
|
|
95
|
+
/** Display name announced on connect; `'User'` is the placeholder when none was given. */
|
|
96
|
+
name: string;
|
|
97
|
+
version: string;
|
|
98
|
+
device: DeviceConfig;
|
|
99
|
+
/** Signed device identity bytes, `null` until the server sends them in `<success>`. */
|
|
100
|
+
advIdentity: Buffer | null;
|
|
101
|
+
[key: string]: any;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** A companion (pairing-code / QR) session. */
|
|
105
|
+
export interface WhalibmobWebStore {
|
|
106
|
+
phoneNumber: string;
|
|
107
|
+
registered: boolean;
|
|
108
|
+
me?: { id: string; lid?: string; name?: string } | null;
|
|
109
|
+
advSecretKey?: string;
|
|
110
|
+
deviceIndex?: number;
|
|
111
|
+
platform?: string;
|
|
112
|
+
[key: string]: any;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
116
|
+
// Client options
|
|
117
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
export interface WhalibmobClientOptions {
|
|
120
|
+
/** Authentication folder. Each number gets its own subfolder. Default `~/.waSession`. */
|
|
121
|
+
sessionDir?: string;
|
|
122
|
+
/** Re-file the session when the server reports the account under a different number. Default `true`. */
|
|
123
|
+
autoFixNumber?: boolean;
|
|
124
|
+
/** Send read receipts for incoming messages. Default `true`. */
|
|
125
|
+
autoRead?: boolean;
|
|
126
|
+
/** Refresh the announced build from the platform's store before every handshake. Default `true`. */
|
|
127
|
+
refreshVersion?: boolean;
|
|
128
|
+
/** `true` enables debug logging; an object is handed to `pino` as-is. */
|
|
129
|
+
pino?: boolean | object;
|
|
130
|
+
/** How many sent messages keep their plaintext for retry receipts. Default `2000`. */
|
|
131
|
+
sentCacheSize?: number;
|
|
132
|
+
/** How many times one message may be re-sent for retry receipts. Default `5`. */
|
|
133
|
+
maxRetryResends?: number;
|
|
134
|
+
/** How long a first message waits for its trusted-contact token, in ms. Default `5000`. */
|
|
135
|
+
tcTokenPresendTimeoutMs?: number;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface ConnectWebOptions {
|
|
139
|
+
/** Ask the phone for the full archive. Default `true`. */
|
|
140
|
+
syncFullHistory?: boolean;
|
|
141
|
+
/** `[os, client, version]` — shown to the owner under Linked Devices. */
|
|
142
|
+
browser?: [string, string, string];
|
|
143
|
+
/** Web client revision to announce, e.g. `[2, 3000, 1035194821]`. */
|
|
144
|
+
version?: [number, number, number];
|
|
145
|
+
/** Set `false` to skip the live revision lookup. Default `true`. */
|
|
146
|
+
fetchVersion?: boolean;
|
|
147
|
+
/** Emit the QR as a `wa.me/settings/linked_devices#…` link instead of the bare fields. */
|
|
148
|
+
qrWrapUrl?: boolean;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface DisconnectOptions {
|
|
152
|
+
/** Allow the reconnect loop to run afterwards. */
|
|
153
|
+
reconnect?: boolean;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
157
|
+
// Messages
|
|
158
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
export interface ContextInfo {
|
|
161
|
+
quotedMessageId?: string;
|
|
162
|
+
participant?: Jid;
|
|
163
|
+
remoteJid?: Jid;
|
|
164
|
+
mentionedJid?: Jid[];
|
|
165
|
+
[key: string]: any;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface SendOptions {
|
|
169
|
+
/** Use a message id you generated yourself instead of a fresh one. */
|
|
170
|
+
id?: string;
|
|
171
|
+
contextInfo?: ContextInfo;
|
|
172
|
+
/** JIDs to mention; also written into `contextInfo.mentionedJid`. */
|
|
173
|
+
mentions?: Jid[];
|
|
174
|
+
[key: string]: any;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface MediaSendOptions extends SendOptions {
|
|
178
|
+
caption?: string;
|
|
179
|
+
mimetype?: string;
|
|
180
|
+
width?: number;
|
|
181
|
+
height?: number;
|
|
182
|
+
seconds?: number;
|
|
183
|
+
/** JPEG bytes for the inline preview. */
|
|
184
|
+
thumbnail?: Buffer;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface DocumentSendOptions extends SendOptions {
|
|
188
|
+
fileName?: string;
|
|
189
|
+
title?: string;
|
|
190
|
+
mimetype?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface AudioSendOptions extends SendOptions {
|
|
194
|
+
/** Render as a push-to-talk voice note with a waveform. */
|
|
195
|
+
ptt?: boolean;
|
|
196
|
+
mimetype?: string;
|
|
197
|
+
seconds?: number;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface VideoSendOptions extends MediaSendOptions {
|
|
201
|
+
/** Send as a GIF — labelled mediatype `gif` rather than `video`. */
|
|
202
|
+
gifPlayback?: boolean;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface LocationSendOptions extends SendOptions {
|
|
206
|
+
name?: string;
|
|
207
|
+
address?: string;
|
|
208
|
+
url?: string;
|
|
209
|
+
isLive?: boolean;
|
|
210
|
+
accuracyInMeters?: number;
|
|
211
|
+
/** Map image for the bubble; WhatsApp draws a blank card without one. */
|
|
212
|
+
thumbnail?: Buffer;
|
|
213
|
+
jpegThumbnail?: Buffer;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** What every `send*` call resolves to once the server has acked the stanza. */
|
|
217
|
+
export interface SendResult {
|
|
218
|
+
id: string;
|
|
219
|
+
/** `'sent'` on a normal send; `'deleted_locally'` from a local-only delete. */
|
|
220
|
+
status: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface PollSendResult extends SendResult {
|
|
224
|
+
/** 32-byte secret needed to decrypt incoming votes. */
|
|
225
|
+
encKey: Buffer;
|
|
226
|
+
/** The same value under the name the protocol uses. */
|
|
227
|
+
messageSecret: Buffer;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface DecodedBase {
|
|
231
|
+
type: string;
|
|
232
|
+
[key: string]: any;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface DecodedText extends DecodedBase {
|
|
236
|
+
type: 'text';
|
|
237
|
+
text: string;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export interface DecodedMedia extends DecodedBase {
|
|
241
|
+
type: 'image' | 'video' | 'audio' | 'voice' | 'document' | 'sticker';
|
|
242
|
+
url: string;
|
|
243
|
+
mimetype: string;
|
|
244
|
+
mediaKey: Buffer;
|
|
245
|
+
directPath: string;
|
|
246
|
+
caption?: string;
|
|
247
|
+
fileName?: string;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface DecodedReaction extends DecodedBase {
|
|
251
|
+
type: 'reaction';
|
|
252
|
+
emoji: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface DecodedLocation extends DecodedBase {
|
|
256
|
+
type: 'location';
|
|
257
|
+
latitude: number;
|
|
258
|
+
longitude: number;
|
|
259
|
+
name: string;
|
|
260
|
+
address: string;
|
|
261
|
+
url: string;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface DecodedContact extends DecodedBase {
|
|
265
|
+
type: 'contact';
|
|
266
|
+
displayName: string;
|
|
267
|
+
vcard: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export interface DecodedGroupInvite extends DecodedBase {
|
|
271
|
+
type: 'groupInvite';
|
|
272
|
+
groupJid: Jid;
|
|
273
|
+
inviteCode: string;
|
|
274
|
+
inviteExpiration: number;
|
|
275
|
+
groupName: string;
|
|
276
|
+
jpegThumbnail: Buffer | null;
|
|
277
|
+
caption: string;
|
|
278
|
+
isCommunity: boolean;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface DecodedProtocol extends DecodedBase {
|
|
282
|
+
type: 'protocol';
|
|
283
|
+
subtype: string;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export type DecodedMessage =
|
|
287
|
+
| DecodedText
|
|
288
|
+
| DecodedMedia
|
|
289
|
+
| DecodedReaction
|
|
290
|
+
| DecodedLocation
|
|
291
|
+
| DecodedContact
|
|
292
|
+
| DecodedGroupInvite
|
|
293
|
+
| DecodedProtocol
|
|
294
|
+
| DecodedBase;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* The payload of the `message` event.
|
|
298
|
+
*
|
|
299
|
+
* It arrives in one of three shapes, so `decoded` and `text` are each optional
|
|
300
|
+
* and you should check before reading either:
|
|
301
|
+
*
|
|
302
|
+
* - a plaintext body that was never Signal-encoded — carries `text`, no `decoded`
|
|
303
|
+
* - a decoded direct message — carries `decoded`
|
|
304
|
+
* - a decoded group message — carries `decoded` and `isGroup`
|
|
305
|
+
*/
|
|
306
|
+
export interface IncomingMessage {
|
|
307
|
+
id: string;
|
|
308
|
+
/** Sender JID — may be a LID. Read `node.attrs.sender_pn` for the phone JID. */
|
|
309
|
+
from: Jid;
|
|
310
|
+
/** Group member JID; equals `from` in DMs. */
|
|
311
|
+
participant: Jid;
|
|
312
|
+
/** Unix timestamp, seconds. */
|
|
313
|
+
ts: number;
|
|
314
|
+
/** Raw binary node. `node.attrs.sender_pn` holds the real phone JID. */
|
|
315
|
+
node: any;
|
|
316
|
+
/** The structured payload. Absent on the plaintext-body variant. */
|
|
317
|
+
decoded?: DecodedMessage | null;
|
|
318
|
+
/** Raw body text. Present only on the plaintext-body variant. */
|
|
319
|
+
text?: string | null;
|
|
320
|
+
/** `true` on a group message. */
|
|
321
|
+
isGroup?: boolean;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
325
|
+
// Groups
|
|
326
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
327
|
+
|
|
328
|
+
export interface GroupAddRequest {
|
|
329
|
+
code: string;
|
|
330
|
+
expiration: number;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** One participant's outcome. Stringifies to its JID. */
|
|
334
|
+
export declare class GroupParticipantResult {
|
|
335
|
+
jid: Jid;
|
|
336
|
+
/** `'200'` when the action went through. */
|
|
337
|
+
status: string;
|
|
338
|
+
/** `null` on success. */
|
|
339
|
+
error: number | null;
|
|
340
|
+
admin: 'admin' | 'superadmin' | null;
|
|
341
|
+
phoneNumber: Jid | null;
|
|
342
|
+
lid: Jid | null;
|
|
343
|
+
displayName: string | null;
|
|
344
|
+
/** Present only on an add refused for privacy: the code an invitation is built from. */
|
|
345
|
+
addRequest: GroupAddRequest | null;
|
|
346
|
+
/** `true` when this add was refused but a personal invitation could be sent. */
|
|
347
|
+
invited?: boolean;
|
|
348
|
+
inviteError?: string;
|
|
349
|
+
readonly ok: boolean;
|
|
350
|
+
readonly needsInvite: boolean;
|
|
351
|
+
toString(): string;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** A pending join request. Stringifies to its JID. */
|
|
355
|
+
export declare class GroupJoinRequest {
|
|
356
|
+
jid: Jid;
|
|
357
|
+
/** Unix seconds, or `0` when the server did not say. */
|
|
358
|
+
requestedAt: number;
|
|
359
|
+
toString(): string;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export interface GroupParticipant {
|
|
363
|
+
jid: Jid;
|
|
364
|
+
role: 'admin' | 'superadmin' | 'member';
|
|
365
|
+
isAdmin: boolean;
|
|
366
|
+
isSuperAdmin: boolean;
|
|
367
|
+
phoneNumber: Jid | null;
|
|
368
|
+
lid: Jid | null;
|
|
369
|
+
displayName: string | null;
|
|
370
|
+
username: string | null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export interface GroupMetadata {
|
|
374
|
+
jid: Jid;
|
|
375
|
+
subject: string;
|
|
376
|
+
size: number;
|
|
377
|
+
creation: number;
|
|
378
|
+
creator: Jid | null;
|
|
379
|
+
subjectTime?: number;
|
|
380
|
+
subjectBy?: Jid;
|
|
381
|
+
description?: string;
|
|
382
|
+
descriptionId?: string;
|
|
383
|
+
descriptionBy?: Jid;
|
|
384
|
+
descriptionTime?: number;
|
|
385
|
+
/** Disappearing-message timer in seconds; `0` when off. */
|
|
386
|
+
ephemeral: number;
|
|
387
|
+
onlyAdminsSend: boolean;
|
|
388
|
+
onlyAdminsEdit: boolean;
|
|
389
|
+
joinApprovalMode: boolean;
|
|
390
|
+
memberAddMode: 'admin_add' | 'all_member_add' | null;
|
|
391
|
+
isCommunity: boolean;
|
|
392
|
+
isCommunityAnnounce: boolean;
|
|
393
|
+
linkedParent: Jid | null;
|
|
394
|
+
/** Members' phone numbers hidden from each other. */
|
|
395
|
+
isIncognito: boolean;
|
|
396
|
+
/** The group has been taken down; every send is refused. */
|
|
397
|
+
isSuspended: boolean;
|
|
398
|
+
addressingMode: 'lid' | 'pn';
|
|
399
|
+
participants: GroupParticipant[];
|
|
400
|
+
[key: string]: any;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export interface GroupInviteInfo {
|
|
404
|
+
jid: Jid;
|
|
405
|
+
subject: string;
|
|
406
|
+
creator: Jid;
|
|
407
|
+
creation: number;
|
|
408
|
+
description: string;
|
|
409
|
+
participants: Array<{ jid: Jid; role: string }>;
|
|
410
|
+
[key: string]: any;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export type GroupSetting =
|
|
414
|
+
| 'edit_group_info'
|
|
415
|
+
| 'send_messages'
|
|
416
|
+
| 'add_participants'
|
|
417
|
+
| 'approve_participants';
|
|
418
|
+
|
|
419
|
+
export type GroupPolicy = 'admins' | 'all';
|
|
420
|
+
|
|
421
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
422
|
+
// Privacy / profile / account
|
|
423
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
424
|
+
|
|
425
|
+
export type PrivacyType =
|
|
426
|
+
| 'last_seen'
|
|
427
|
+
| 'profile_picture'
|
|
428
|
+
| 'status'
|
|
429
|
+
| 'online'
|
|
430
|
+
| 'read_receipts'
|
|
431
|
+
| 'groups_add'
|
|
432
|
+
| 'call_add'
|
|
433
|
+
| 'messages'
|
|
434
|
+
| 'defense'
|
|
435
|
+
| 'stickers';
|
|
436
|
+
|
|
437
|
+
export type PrivacyValue =
|
|
438
|
+
| 'all'
|
|
439
|
+
| 'contacts'
|
|
440
|
+
| 'contact_blacklist'
|
|
441
|
+
| 'contact_allowlist'
|
|
442
|
+
| 'none'
|
|
443
|
+
| 'match_last_seen'
|
|
444
|
+
| 'known'
|
|
445
|
+
| 'on_standard'
|
|
446
|
+
| 'off';
|
|
447
|
+
|
|
448
|
+
export interface PrivacySettings {
|
|
449
|
+
lastSeen: string | null;
|
|
450
|
+
profile: string | null;
|
|
451
|
+
status: string | null;
|
|
452
|
+
online: string | null;
|
|
453
|
+
readReceipts: string | null;
|
|
454
|
+
groupAdd: string | null;
|
|
455
|
+
callAdd: string | null;
|
|
456
|
+
messages: string | null;
|
|
457
|
+
defense: string | null;
|
|
458
|
+
stickers: string | null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export interface StatusPrivacyEntry {
|
|
462
|
+
type: 'contacts' | 'blacklist' | 'whitelist';
|
|
463
|
+
isDefault: boolean;
|
|
464
|
+
list: Jid[];
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export interface BusinessProfile {
|
|
468
|
+
jid: Jid;
|
|
469
|
+
description: string | null;
|
|
470
|
+
email: string | null;
|
|
471
|
+
website: string | null;
|
|
472
|
+
address: string | null;
|
|
473
|
+
category: string | null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export interface SessionAliveProbe {
|
|
477
|
+
alive: boolean;
|
|
478
|
+
status: string | null;
|
|
479
|
+
/** The number this session is filed under locally. */
|
|
480
|
+
current?: string;
|
|
481
|
+
/** The number WhatsApp files the account under. */
|
|
482
|
+
canonical?: string;
|
|
483
|
+
/** `true` when the two differ — see `adoptCanonicalNumber`. */
|
|
484
|
+
mismatch?: boolean;
|
|
485
|
+
raw: any;
|
|
486
|
+
error?: string;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Account restriction state — see `fetchReachoutTimelock`. */
|
|
490
|
+
export interface ReachoutTimelockState {
|
|
491
|
+
active: boolean;
|
|
492
|
+
endsAt: number | null;
|
|
493
|
+
endsAtDate: Date | null;
|
|
494
|
+
remainingMs: number;
|
|
495
|
+
/** `HH:MM:SS`; hours are not wrapped at 24. */
|
|
496
|
+
remaining: string;
|
|
497
|
+
enforcementType: string;
|
|
498
|
+
reason: string;
|
|
499
|
+
/** `true` when the server said there is a restriction but withheld the end time. */
|
|
500
|
+
expiryUnknown: boolean;
|
|
501
|
+
checkedAt: number | null;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export interface CallLink {
|
|
505
|
+
token: string;
|
|
506
|
+
link: string;
|
|
507
|
+
type: 'audio' | 'video';
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export interface AppStateSyncResult {
|
|
511
|
+
applied: number;
|
|
512
|
+
collections: Record<string, {
|
|
513
|
+
version: number;
|
|
514
|
+
applied: number;
|
|
515
|
+
skipped: number;
|
|
516
|
+
snapshot: boolean;
|
|
517
|
+
macOk: boolean;
|
|
518
|
+
}>;
|
|
519
|
+
/** Present when the phone has not shared an app-state key yet. */
|
|
520
|
+
waitingForKeys?: boolean;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export interface StatusContent {
|
|
524
|
+
image?: MediaSource;
|
|
525
|
+
video?: MediaSource;
|
|
526
|
+
audio?: MediaSource;
|
|
527
|
+
caption?: string;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export interface StatusOptions extends SendOptions {
|
|
531
|
+
/** ARGB background for a styled text status. */
|
|
532
|
+
backgroundArgb?: number;
|
|
533
|
+
font?: number;
|
|
534
|
+
/** Post to an explicit list instead of the privacy-derived one. */
|
|
535
|
+
recipients?: Jid[];
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
539
|
+
// History sync
|
|
540
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
541
|
+
|
|
542
|
+
export interface HistoryChat {
|
|
543
|
+
id: Jid;
|
|
544
|
+
name?: string;
|
|
545
|
+
unreadCount: number;
|
|
546
|
+
lastMsgTimestamp: number;
|
|
547
|
+
messageCount: number;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export interface HistoryContact {
|
|
551
|
+
id: Jid;
|
|
552
|
+
name?: string;
|
|
553
|
+
username?: string;
|
|
554
|
+
pnJid?: Jid;
|
|
555
|
+
lidJid?: Jid;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export interface HistorySyncResult {
|
|
559
|
+
syncType: number;
|
|
560
|
+
syncTypeName:
|
|
561
|
+
| 'INITIAL_BOOTSTRAP'
|
|
562
|
+
| 'RECENT'
|
|
563
|
+
| 'FULL'
|
|
564
|
+
| 'PUSH_NAME'
|
|
565
|
+
| 'NON_BLOCKING_DATA'
|
|
566
|
+
| 'ON_DEMAND'
|
|
567
|
+
| string;
|
|
568
|
+
progress: number;
|
|
569
|
+
chunkOrder: number;
|
|
570
|
+
chats: HistoryChat[];
|
|
571
|
+
contacts: HistoryContact[];
|
|
572
|
+
pushNames: Array<{ id: Jid; pushname: string }>;
|
|
573
|
+
lidPnMappings: Array<{ lidJid: Jid; pnJid: Jid }>;
|
|
574
|
+
merged: any;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export interface MediaRetryNotification {
|
|
578
|
+
messageId: string;
|
|
579
|
+
chatJid: Jid;
|
|
580
|
+
fromMe: boolean;
|
|
581
|
+
participant?: Jid;
|
|
582
|
+
ciphertext?: Buffer;
|
|
583
|
+
iv?: Buffer;
|
|
584
|
+
/** Set instead of a payload when the phone no longer has the file either. */
|
|
585
|
+
error?: any;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
export interface MediaRetryResult {
|
|
589
|
+
ok: boolean;
|
|
590
|
+
directPath?: string;
|
|
591
|
+
url?: string;
|
|
592
|
+
[key: string]: any;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
596
|
+
// Events
|
|
597
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
598
|
+
|
|
599
|
+
export interface WhalibmobEvents {
|
|
600
|
+
connected: () => void;
|
|
601
|
+
disconnected: () => void;
|
|
602
|
+
reconnecting: (info: { attempt: number; delay: number }) => void;
|
|
603
|
+
reconnected: () => void;
|
|
604
|
+
close: () => void;
|
|
605
|
+
error: (err: Error) => void;
|
|
606
|
+
auth_failure: (info: { reason: string }) => void;
|
|
607
|
+
stream_error: (info: { reason: string }) => void;
|
|
608
|
+
connection_replaced: () => void;
|
|
609
|
+
|
|
610
|
+
message: (msg: IncomingMessage) => void;
|
|
611
|
+
receipt: (r: { type: string; id: string; from: Jid }) => void;
|
|
612
|
+
presence: (p: { from: Jid; available: boolean }) => void;
|
|
613
|
+
call: (c: { from: Jid }) => void;
|
|
614
|
+
notification: (node: any) => void;
|
|
615
|
+
decrypt_error: (e: { id: string; from: Jid; participant?: Jid; err: Error }) => void;
|
|
616
|
+
session_refresh: (e: { node: any }) => void;
|
|
617
|
+
|
|
618
|
+
group_update: (u: {
|
|
619
|
+
type: string;
|
|
620
|
+
groupJid: Jid;
|
|
621
|
+
actor?: Jid;
|
|
622
|
+
participants?: Jid[];
|
|
623
|
+
subject?: string;
|
|
624
|
+
timestamp?: number;
|
|
625
|
+
}) => void;
|
|
626
|
+
|
|
627
|
+
chat_read: (u: { jid: Jid; read: boolean; remote?: boolean; synced?: boolean }) => void;
|
|
628
|
+
chat_muted: (u: { jid: Jid; muted: boolean; until: number; remote?: boolean; synced?: boolean }) => void;
|
|
629
|
+
chat_pinned: (u: { jid: Jid; pinned: boolean; remote?: boolean; synced?: boolean }) => void;
|
|
630
|
+
chat_archived: (u: { jid: Jid; archived: boolean; remote?: boolean; synced?: boolean }) => void;
|
|
631
|
+
chat_removed: (u: { jid: Jid; kind: string; remote: boolean }) => void;
|
|
632
|
+
message_starred: (u: {
|
|
633
|
+
msgId: string; chatJid: Jid; starred: boolean;
|
|
634
|
+
fromMe?: boolean; remote?: boolean; synced?: boolean;
|
|
635
|
+
}) => void;
|
|
636
|
+
contact_update: (u: {
|
|
637
|
+
jid: Jid; name?: string; firstName?: string; lid?: Jid;
|
|
638
|
+
username?: string; removed?: boolean; remote?: boolean;
|
|
639
|
+
}) => void;
|
|
640
|
+
push_name_update: (u: { name: string; remote?: boolean }) => void;
|
|
641
|
+
|
|
642
|
+
blocklist: (b: { action?: string; dhash?: string; prevDhash?: string; changes: Array<{ jid: Jid; action: string }> }) => void;
|
|
643
|
+
privacy_settings: (p: { changes: any; settings: PrivacySettings }) => void;
|
|
644
|
+
|
|
645
|
+
app_state_sync: (r: AppStateSyncResult) => void;
|
|
646
|
+
app_state_mutation: (m: { collection: string; index: any; action: any; removed: boolean }) => void;
|
|
647
|
+
app_state_key_missing: (m: { collection: string; keyId: string }) => void;
|
|
648
|
+
app_state_keys: (m: { keys: any[] }) => void;
|
|
649
|
+
|
|
650
|
+
account_restriction: (r: ReachoutTimelockState & { source: 'notification' | 'query' }) => void;
|
|
651
|
+
|
|
652
|
+
history_sync: (r: HistorySyncResult) => void;
|
|
653
|
+
history_sync_error: (e: { err: Error; notification: any }) => void;
|
|
654
|
+
media_retry: (n: MediaRetryNotification) => void;
|
|
655
|
+
|
|
656
|
+
/** Companion mode: a pairing code was requested. */
|
|
657
|
+
pairing_code: (p: { code: string; phoneNumber: string }) => void;
|
|
658
|
+
/** Companion mode: a QR is ready to render; fires again on each rotation. */
|
|
659
|
+
qr: (q: { qr: string; ref: string; ttlMs: number; remaining: number }) => void;
|
|
660
|
+
qr_timeout: () => void;
|
|
661
|
+
pair_device: (p: { refs: string[] }) => void;
|
|
662
|
+
paired: (p: { jid: Jid; lid: Jid; deviceIndex: number; platform: string }) => void;
|
|
663
|
+
restart_required: (r: { reason?: string }) => void;
|
|
664
|
+
web_ready_for_pairing: () => void;
|
|
665
|
+
|
|
666
|
+
/** The server refused the client itself — `405` means the announced version is not accepted. */
|
|
667
|
+
client_rejected: (r: { reason: string; location?: string; message?: string }) => void;
|
|
668
|
+
version_update: (v: { from: string; to: string; source: string }) => void;
|
|
669
|
+
apk_material_stale: (m: { materialVersion: string; liveVersion: string; hint?: string }) => void;
|
|
670
|
+
number_corrected: (n: { from: string; to: string }) => void;
|
|
671
|
+
|
|
672
|
+
mex_notification: (m: { opName: string; data: any }) => void;
|
|
673
|
+
identity_change: (i: any) => void;
|
|
674
|
+
media_conn: (m: any) => void;
|
|
675
|
+
media_conn_error: (e: any) => void;
|
|
676
|
+
node: (n: any) => void;
|
|
677
|
+
node_error: (e: any) => void;
|
|
678
|
+
iq: (n: any) => void;
|
|
679
|
+
ib: (n: any) => void;
|
|
680
|
+
md_msg_hist: (n: any) => void;
|
|
681
|
+
skdm_error: (e: any) => void;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
685
|
+
// Client
|
|
686
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
687
|
+
|
|
688
|
+
export declare class WhalibmobClient extends EventEmitter {
|
|
689
|
+
constructor(opts?: WhalibmobClientOptions);
|
|
690
|
+
|
|
691
|
+
on<E extends keyof WhalibmobEvents>(event: E, listener: WhalibmobEvents[E]): this;
|
|
692
|
+
once<E extends keyof WhalibmobEvents>(event: E, listener: WhalibmobEvents[E]): this;
|
|
693
|
+
off<E extends keyof WhalibmobEvents>(event: E, listener: WhalibmobEvents[E]): this;
|
|
694
|
+
addListener<E extends keyof WhalibmobEvents>(event: E, listener: WhalibmobEvents[E]): this;
|
|
695
|
+
removeListener<E extends keyof WhalibmobEvents>(event: E, listener: WhalibmobEvents[E]): this;
|
|
696
|
+
emit<E extends keyof WhalibmobEvents>(event: E, ...args: Parameters<WhalibmobEvents[E]>): boolean;
|
|
697
|
+
|
|
698
|
+
/** `'mobile'` for an SMS-registered primary, `'web'` for a linked companion. */
|
|
699
|
+
readonly _mode: 'mobile' | 'web';
|
|
700
|
+
readonly store: WhalibmobStore | WhalibmobWebStore;
|
|
701
|
+
|
|
702
|
+
// ─── Connection ──────────────────────────────────────────────────────────
|
|
703
|
+
/** Connect an SMS-registered session over TCP. Resolves with the client. */
|
|
704
|
+
init(phoneNumber: string): Promise<this>;
|
|
705
|
+
/** Alias of `init`. */
|
|
706
|
+
connect(phoneNumber: string): Promise<this>;
|
|
707
|
+
/** Connect as a companion over WebSocket. */
|
|
708
|
+
connectWeb(phoneNumber: string, opts?: ConnectWebOptions): Promise<this>;
|
|
709
|
+
/** Alias of `connectWeb`. */
|
|
710
|
+
initWeb(phoneNumber: string, opts?: ConnectWebOptions): Promise<this>;
|
|
711
|
+
/** Ask for an 8-character pairing code. Throws if the session is already linked. */
|
|
712
|
+
requestPairingCode(phoneNumber?: string, customCode?: string): Promise<string>;
|
|
713
|
+
disconnect(opts?: DisconnectOptions): void;
|
|
714
|
+
|
|
715
|
+
/** Ask the server whether this session still logs in, and under which number. */
|
|
716
|
+
checkSessionAlive(): Promise<SessionAliveProbe>;
|
|
717
|
+
/** Re-file the session under the number WhatsApp uses. Keeps keys and registration. */
|
|
718
|
+
adoptCanonicalNumber(canonical: string): Promise<any>;
|
|
719
|
+
|
|
720
|
+
// ─── Sending ─────────────────────────────────────────────────────────────
|
|
721
|
+
sendText(to: Jid, text: string, opts?: SendOptions): Promise<SendResult>;
|
|
722
|
+
sendImage(to: Jid, data: MediaSource, opts?: MediaSendOptions): Promise<SendResult>;
|
|
723
|
+
sendVideo(to: Jid, data: MediaSource, opts?: VideoSendOptions): Promise<SendResult>;
|
|
724
|
+
sendAudio(to: Jid, data: MediaSource, opts?: AudioSendOptions): Promise<SendResult>;
|
|
725
|
+
sendDocument(to: Jid, data: MediaSource, opts?: DocumentSendOptions): Promise<SendResult>;
|
|
726
|
+
sendSticker(to: Jid, data: MediaSource, opts?: SendOptions): Promise<SendResult>;
|
|
727
|
+
sendReaction(to: Jid, messageId: string, emoji: string, opts?: SendOptions): Promise<SendResult>;
|
|
728
|
+
sendPoll(to: Jid, question: string, options: string[], selectableCount?: number, opts?: SendOptions): Promise<PollSendResult>;
|
|
729
|
+
sendLocation(to: Jid, latitude: number, longitude: number, opts?: LocationSendOptions): Promise<SendResult>;
|
|
730
|
+
sendContact(to: Jid, displayName: string, vcard: string, opts?: SendOptions): Promise<SendResult>;
|
|
731
|
+
sendReply(to: Jid, quotedMsgId: string, senderJid: Jid, text: string, opts?: SendOptions): Promise<SendResult>;
|
|
732
|
+
forwardMessage(to: Jid, msg: IncomingMessage | string, contextInfo?: ContextInfo): Promise<SendResult>;
|
|
733
|
+
editMessage(origMsgId: string, chatJid: Jid, newText: string, opts?: SendOptions): Promise<SendResult>;
|
|
734
|
+
deleteMessage(origMsgId: string, chatJid: Jid, fromMe: boolean, forEveryone: boolean, opts?: SendOptions): Promise<SendResult>;
|
|
735
|
+
sendStatus(content: string | StatusContent, opts?: StatusOptions): Promise<SendResult>;
|
|
736
|
+
sendCallLink(to: Jid, type?: 'audio' | 'video', opts?: SendOptions & { text?: string }): Promise<SendResult & { link: string }>;
|
|
737
|
+
createCallLink(type?: 'audio' | 'video', opts?: { startTime?: number }): Promise<CallLink>;
|
|
738
|
+
|
|
739
|
+
// ─── Receiving ───────────────────────────────────────────────────────────
|
|
740
|
+
/** Download and decrypt a media message. Accepts `msg` or `msg.decoded`. */
|
|
741
|
+
downloadMedia(decoded: DecodedMessage | IncomingMessage, opts?: { verify?: boolean }): Promise<Buffer>;
|
|
742
|
+
/** Ask the sender's phone to re-upload a file the CDN no longer has. */
|
|
743
|
+
requestMediaRetry(info: { id: string; chatJid: Jid; fromMe: boolean; participant?: Jid }, mediaKey: Buffer): Promise<void>;
|
|
744
|
+
decryptMediaRetry(notification: MediaRetryNotification, mediaKey: Buffer): MediaRetryResult;
|
|
745
|
+
|
|
746
|
+
// ─── Presence / receipts ─────────────────────────────────────────────────
|
|
747
|
+
markRead(jid: Jid, messageIds: string | string[], opts?: object): void;
|
|
748
|
+
markMessagePlayed(msgId: string, from: Jid): void;
|
|
749
|
+
setOnline(available: boolean): boolean;
|
|
750
|
+
setPresence(available: boolean): boolean;
|
|
751
|
+
setChatPresence(chatJid: Jid, presence: 'composing' | 'recording' | 'paused' | 'available' | 'unavailable'): void;
|
|
752
|
+
subscribeToPresence(jids: Jid | Jid[]): void;
|
|
753
|
+
|
|
754
|
+
// ─── Queries ─────────────────────────────────────────────────────────────
|
|
755
|
+
/** Returns the JIDs, out of those given, that are on WhatsApp. */
|
|
756
|
+
hasWhatsapp(jids: Jid[]): Promise<Jid[]>;
|
|
757
|
+
queryAbout(jid: Jid): Promise<string | null>;
|
|
758
|
+
queryOwnAbout(): Promise<string | null>;
|
|
759
|
+
queryPicture(jid: Jid, opts?: object): Promise<string | null>;
|
|
760
|
+
queryPictureInfo(jid: Jid, opts?: object): Promise<any>;
|
|
761
|
+
downloadProfilePicture(jid: Jid, opts?: object): Promise<Buffer | null>;
|
|
762
|
+
queryBusinessProfile(jid: Jid): Promise<BusinessProfile | null>;
|
|
763
|
+
|
|
764
|
+
// ─── Profile ─────────────────────────────────────────────────────────────
|
|
765
|
+
changeName(name: string): Promise<boolean>;
|
|
766
|
+
changeAbout(text: string): Promise<any>;
|
|
767
|
+
/**
|
|
768
|
+
* Pass `null` to remove. Resolves to the new picture id, `'remove'` when the
|
|
769
|
+
* picture was taken down, or `null` when the server's reply carried no id.
|
|
770
|
+
*/
|
|
771
|
+
changeProfilePicture(buf: Buffer | null, opts?: { raw?: boolean; size?: number; quality?: number }): Promise<string | null>;
|
|
772
|
+
|
|
773
|
+
// ─── Privacy ─────────────────────────────────────────────────────────────
|
|
774
|
+
queryPrivacySettings(opts?: { force?: boolean }): Promise<PrivacySettings>;
|
|
775
|
+
changePrivacySetting(type: PrivacyType, value: PrivacyValue, excluded?: Jid[]): Promise<PrivacySettings>;
|
|
776
|
+
queryStatusPrivacy(): Promise<StatusPrivacyEntry[]>;
|
|
777
|
+
blockContact(jid: Jid): Promise<Jid[]>;
|
|
778
|
+
unblockContact(jid: Jid): Promise<Jid[]>;
|
|
779
|
+
queryBlockList(): Promise<Jid[]>;
|
|
780
|
+
|
|
781
|
+
// ─── Chat state (app state) ──────────────────────────────────────────────
|
|
782
|
+
/** Each returns whether the change reached app state, and so whether other devices will see it. */
|
|
783
|
+
markChatRead(jid: Jid): Promise<boolean>;
|
|
784
|
+
markChatUnread(jid: Jid): Promise<boolean>;
|
|
785
|
+
muteChat(jid: Jid, durationMs?: number): Promise<boolean>;
|
|
786
|
+
unmuteChat(jid: Jid): Promise<boolean>;
|
|
787
|
+
pinChat(jid: Jid): Promise<boolean>;
|
|
788
|
+
unpinChat(jid: Jid): Promise<boolean>;
|
|
789
|
+
archiveChat(jid: Jid): Promise<boolean>;
|
|
790
|
+
unarchiveChat(jid: Jid): Promise<boolean>;
|
|
791
|
+
starMessage(msgId: string, chatJid: Jid, fromMe: boolean): Promise<boolean>;
|
|
792
|
+
unstarMessage(msgId: string, chatJid: Jid, fromMe: boolean): Promise<boolean>;
|
|
793
|
+
changeEphemeralTimer(jid: Jid, seconds: number): Promise<any>;
|
|
794
|
+
changeNewChatsEphemeralTimer(seconds: number): Promise<any>;
|
|
795
|
+
|
|
796
|
+
/** Pull pins/archives/mutes/stars/contact names changed elsewhere. */
|
|
797
|
+
syncAppState(names?: string[] | null, opts?: { snapshot?: boolean }): Promise<AppStateSyncResult>;
|
|
798
|
+
/** Whether an app-state key is available — `false` on an SMS session with no companion. */
|
|
799
|
+
canSyncAppState(): boolean;
|
|
800
|
+
|
|
801
|
+
// ─── Account restriction ─────────────────────────────────────────────────
|
|
802
|
+
fetchReachoutTimelock(): Promise<ReachoutTimelockState>;
|
|
803
|
+
/** The last known state, recomputed; does not ask the server again. */
|
|
804
|
+
getReachoutTimelock(): ReachoutTimelockState;
|
|
805
|
+
|
|
806
|
+
// ─── Groups ──────────────────────────────────────────────────────────────
|
|
807
|
+
createGroup(subject: string, participants: Jid[], opts?: object): Promise<GroupMetadata>;
|
|
808
|
+
leaveGroup(groupJid: Jid): Promise<any>;
|
|
809
|
+
/** `null` when the server did not answer the query. */
|
|
810
|
+
getGroupMetadata(groupJid: Jid, opts?: object): Promise<GroupMetadata | null>;
|
|
811
|
+
invalidateGroupMetadata(groupJid: Jid): void;
|
|
812
|
+
fetchAllGroups(): Promise<GroupMetadata[]>;
|
|
813
|
+
refreshGroupMembers(groupJid: Jid): Promise<any>;
|
|
814
|
+
|
|
815
|
+
addGroupParticipants(groupJid: Jid, jids: Jid[]): Promise<GroupParticipantResult[]>;
|
|
816
|
+
removeGroupParticipants(groupJid: Jid, jids: Jid[]): Promise<GroupParticipantResult[]>;
|
|
817
|
+
promoteGroupParticipants(groupJid: Jid, jids: Jid[]): Promise<GroupParticipantResult[]>;
|
|
818
|
+
demoteGroupParticipants(groupJid: Jid, jids: Jid[]): Promise<GroupParticipantResult[]>;
|
|
819
|
+
addGroupParticipantsOrInvite(groupJid: Jid, jids: Jid[], opts?: object): Promise<GroupParticipantResult[]>;
|
|
820
|
+
|
|
821
|
+
changeGroupSubject(groupJid: Jid, subject: string): Promise<any>;
|
|
822
|
+
changeGroupDescription(groupJid: Jid, description: string, opts?: object): Promise<any>;
|
|
823
|
+
/** Resolves to the new picture id, `'remove'`, or `null` when the reply carried no id. */
|
|
824
|
+
changeGroupPicture(groupJid: Jid, buf: Buffer | null, opts?: object): Promise<string | null>;
|
|
825
|
+
changeGroupSetting(groupJid: Jid, setting: GroupSetting, policy: GroupPolicy): Promise<any>;
|
|
826
|
+
setGroupAnnounce(groupJid: Jid, announce: boolean): Promise<any>;
|
|
827
|
+
setGroupLocked(groupJid: Jid, locked: boolean): Promise<any>;
|
|
828
|
+
setGroupJoinApprovalMode(groupJid: Jid, mode: boolean): Promise<any>;
|
|
829
|
+
setGroupMemberAddMode(groupJid: Jid, mode: string): Promise<any>;
|
|
830
|
+
|
|
831
|
+
/** Returns the full `https://chat.whatsapp.com/…` link, or `null`. */
|
|
832
|
+
queryGroupInviteLink(groupJid: Jid, reset?: boolean): Promise<string | null>;
|
|
833
|
+
revokeGroupInviteLink(groupJid: Jid): Promise<string | null>;
|
|
834
|
+
revokeGroupInvite(groupJid: Jid): Promise<string | null>;
|
|
835
|
+
/** Accepts a bare code or a full URL. */
|
|
836
|
+
joinGroupWithLink(inviteCodeOrUrl: string): Promise<{ jid: Jid; pendingApproval: boolean }>;
|
|
837
|
+
acceptGroupInvite(inviteCodeOrUrl: string): Promise<Jid | null>;
|
|
838
|
+
/** `null` when the invite could not be resolved. */
|
|
839
|
+
queryGroupInviteInfo(inviteCodeOrUrl: string): Promise<GroupInviteInfo | null>;
|
|
840
|
+
|
|
841
|
+
queryGroupPendingParticipants(groupJid: Jid): Promise<GroupJoinRequest[]>;
|
|
842
|
+
approveGroupParticipants(groupJid: Jid, approve: boolean, jids: Jid[]): Promise<GroupParticipantResult[]>;
|
|
843
|
+
|
|
844
|
+
sendGroupInvite(to: Jid, groupJid: Jid, inviteCode: string, inviteExpiration: number, opts?: {
|
|
845
|
+
groupName?: string; caption?: string; jpegThumbnail?: Buffer;
|
|
846
|
+
isCommunity?: boolean; id?: string; contextInfo?: ContextInfo;
|
|
847
|
+
}): Promise<SendResult>;
|
|
848
|
+
queryGroupInviteMessageInfo(groupJid: Jid, inviterJid: Jid, code: string, expiration: number): Promise<GroupMetadata>;
|
|
849
|
+
acceptGroupInviteMessage(groupJid: Jid, inviterJid: Jid, code: string, expiration: number): Promise<Jid>;
|
|
850
|
+
revokeGroupInviteForParticipant(groupJid: Jid, invitedJid: Jid): Promise<any>;
|
|
851
|
+
|
|
852
|
+
// ─── Communities ─────────────────────────────────────────────────────────
|
|
853
|
+
createCommunity(subject: string, description?: string, opts?: object): Promise<GroupMetadata>;
|
|
854
|
+
deactivateCommunity(communityJid: Jid): Promise<any>;
|
|
855
|
+
linkGroupsToCommunity(communityJid: Jid, groupJids: Jid[]): Promise<any>;
|
|
856
|
+
unlinkGroupFromCommunity(communityJid: Jid, groupJid: Jid): Promise<any>;
|
|
857
|
+
|
|
858
|
+
// ─── Newsletters ─────────────────────────────────────────────────────────
|
|
859
|
+
createNewsletter(name: string, description?: string): Promise<any>;
|
|
860
|
+
joinNewsletter(newsletterJid: Jid): Promise<any>;
|
|
861
|
+
leaveNewsletter(newsletterJid: Jid): Promise<any>;
|
|
862
|
+
queryNewsletterMetadata(newsletterJid: Jid): Promise<any>;
|
|
863
|
+
changeNewsletterDescription(newsletterJid: Jid, description: string): Promise<any>;
|
|
864
|
+
sendNewsletterText(newsletterJid: Jid, text: string): Promise<any>;
|
|
865
|
+
|
|
866
|
+
// ─── Stores on disk ──────────────────────────────────────────────────────
|
|
867
|
+
getHistoryStore(): any;
|
|
868
|
+
getMessagesStore(): any;
|
|
869
|
+
getPNForLID(lid: Jid): Jid | null;
|
|
870
|
+
getLIDForPN(pn: Jid): Jid | null;
|
|
871
|
+
|
|
872
|
+
// ─── Lower level ─────────────────────────────────────────────────────────
|
|
873
|
+
ensureTcTokenBeforeSend(tcJid: Jid, routingToJid: Jid): Promise<any>;
|
|
874
|
+
sendPeerDataOperationMessage(pdo: any): Promise<any>;
|
|
875
|
+
requestPlaceholderResend(messageKey: any, msgData?: any): Promise<any>;
|
|
876
|
+
fetchMessageHistory(count: number, oldestMsgKey: any, oldestMsgTimestampMs: number): Promise<any>;
|
|
877
|
+
sendWAMBuffer(wamBuffer: Buffer): Promise<any>;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
881
|
+
// Registration
|
|
882
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
883
|
+
|
|
884
|
+
/** The raw server reply. Extra keys vary by outcome, so it is left open. */
|
|
885
|
+
export interface RegistrationResult {
|
|
886
|
+
status?: string;
|
|
887
|
+
reason?: string;
|
|
888
|
+
/** The number WhatsApp filed the account under; may differ from the one typed. */
|
|
889
|
+
login?: string;
|
|
890
|
+
pending?: string;
|
|
891
|
+
/**
|
|
892
|
+
* Set only when the server's number differs from the one typed. Callers
|
|
893
|
+
* should use `result.store || store` — the CLI does — because a plain
|
|
894
|
+
* success carries no store of its own.
|
|
895
|
+
*/
|
|
896
|
+
store?: WhalibmobStore;
|
|
897
|
+
canonicalPhoneNumber?: string;
|
|
898
|
+
typedPhoneNumber?: string;
|
|
899
|
+
[key: string]: any;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
export interface RegistrationOptions {
|
|
903
|
+
/** Display name the account announces. Trimmed and capped at 25 characters. */
|
|
904
|
+
name?: string;
|
|
905
|
+
/** Called when the server answers with a CAPTCHA. Return the answer, or `null` to give up. */
|
|
906
|
+
solveCaptcha?: (challenge: { image: Buffer | null; audio: Buffer | null }) => Promise<string | null>;
|
|
907
|
+
/** Called when the account has two-step verification on. Return the six-digit PIN. */
|
|
908
|
+
twoFactorPin?: () => Promise<string | null>;
|
|
909
|
+
onProgress?: (line: string) => void;
|
|
910
|
+
[key: string]: any;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
export declare function requestSmsCode(store: WhalibmobStore, method?: CodeMethod, opts?: RegistrationOptions): Promise<RegistrationResult>;
|
|
914
|
+
export declare function verifyCode(store: WhalibmobStore, code: string, opts?: RegistrationOptions): Promise<RegistrationResult>;
|
|
915
|
+
export declare function checkIfRegistered(store: WhalibmobStore): Promise<RegistrationResult>;
|
|
916
|
+
|
|
917
|
+
export interface NumberStatusResult {
|
|
918
|
+
active: boolean | null;
|
|
919
|
+
usable: boolean | null;
|
|
920
|
+
status: NumberStatus;
|
|
921
|
+
note: string;
|
|
922
|
+
}
|
|
923
|
+
export declare function checkNumberStatus(phoneNumber: string): Promise<NumberStatusResult>;
|
|
924
|
+
|
|
925
|
+
/** Firebase push listener. Resolves `null` on timeout, or immediately on iOS. */
|
|
926
|
+
export declare function receivePushCode(store: WhalibmobStore, device?: DeviceConfig, opts?: { timeoutMs?: number }): Promise<string | null>;
|
|
927
|
+
/** Whether this device profile can do push verification at all. */
|
|
928
|
+
export declare function supportsPush(device: DeviceConfig): boolean;
|
|
929
|
+
|
|
930
|
+
export declare function assertRegistrationKeys(store: WhalibmobStore): void;
|
|
931
|
+
|
|
932
|
+
// ─── Version ────────────────────────────────────────────────────────────────
|
|
933
|
+
export declare function fetchWaVersion(device?: DeviceConfig): Promise<string>;
|
|
934
|
+
export declare function fetchIosVersion(business?: boolean): Promise<string>;
|
|
935
|
+
export declare function fetchAndroidVersion(business?: boolean): Promise<string>;
|
|
936
|
+
export declare function currentVersionFor(device: Partial<DeviceConfig>): Promise<{ version: string; source: string }>;
|
|
937
|
+
export declare function refreshSessionVersion(sessionFile: string, opts?: { version?: string }): Promise<any>;
|
|
938
|
+
/** The live WhatsApp Web revision, read from the service worker. */
|
|
939
|
+
export declare function fetchWaWebVersion(): Promise<{ version: [number, number, number]; isLatest: boolean }>;
|
|
940
|
+
|
|
941
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
942
|
+
// Stores
|
|
943
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
944
|
+
|
|
945
|
+
export declare function createNewStore(phoneNumber: string, opts?: { name?: string }): WhalibmobStore;
|
|
946
|
+
/** What the CLI uses for every new SMS session; prefer it over `createNewStore`. */
|
|
947
|
+
export declare function initAuthCreds(phoneNumber: string, opts?: { name?: string }): WhalibmobStore;
|
|
948
|
+
export declare function saveStore(store: WhalibmobStore, filePath: string): void;
|
|
949
|
+
export declare function loadStore(filePath: string): WhalibmobStore | null;
|
|
950
|
+
export declare function storeToJson(store: WhalibmobStore): string;
|
|
951
|
+
export declare function storeFromJson(json: string): WhalibmobStore;
|
|
952
|
+
export declare function toSixParts(store: WhalibmobStore): any;
|
|
953
|
+
export declare function fromSixParts(parts: any): WhalibmobStore;
|
|
954
|
+
|
|
955
|
+
export declare function createNewWebStore(phoneNumber: string, opts?: object): WhalibmobWebStore;
|
|
956
|
+
export declare function saveWebStore(store: WhalibmobWebStore, filePath: string): void;
|
|
957
|
+
export declare function loadWebStore(filePath: string): WhalibmobWebStore | null;
|
|
958
|
+
export declare function webSessionPath(baseDir: string, phone: string): string;
|
|
959
|
+
|
|
960
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
961
|
+
// Session paths
|
|
962
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
963
|
+
|
|
964
|
+
export interface SessionEntry {
|
|
965
|
+
phone: string;
|
|
966
|
+
dir: string;
|
|
967
|
+
storeFile: string;
|
|
968
|
+
webStoreFile: string;
|
|
969
|
+
/** `true` for a session whose files sit loose in the base directory. */
|
|
970
|
+
legacy: boolean;
|
|
971
|
+
hasMobile: boolean;
|
|
972
|
+
hasWeb: boolean;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
export interface MigrateResult {
|
|
976
|
+
phone: string;
|
|
977
|
+
from: string;
|
|
978
|
+
to: string;
|
|
979
|
+
moved: string[];
|
|
980
|
+
skipped: string[];
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
export declare function defaultBaseDir(): string;
|
|
984
|
+
export declare function sessionDirFor(baseDir: string, phone: string, opts?: { create?: boolean }): string;
|
|
985
|
+
export declare function storeFileFor(baseDir: string, phone: string): string;
|
|
986
|
+
export declare function webStoreFileFor(baseDir: string, phone: string): string;
|
|
987
|
+
export declare function listSessions(baseDir: string): SessionEntry[];
|
|
988
|
+
export declare function migrateSession(baseDir: string, phone: string): MigrateResult;
|
|
989
|
+
|
|
990
|
+
export declare const SessionPaths: {
|
|
991
|
+
defaultBaseDir: typeof defaultBaseDir;
|
|
992
|
+
isLegacyLayout: (baseDir: string, phone: string) => boolean;
|
|
993
|
+
sessionDirFor: typeof sessionDirFor;
|
|
994
|
+
storeFileFor: typeof storeFileFor;
|
|
995
|
+
webStoreFileFor: typeof webStoreFileFor;
|
|
996
|
+
listSessions: typeof listSessions;
|
|
997
|
+
migrateSession: typeof migrateSession;
|
|
998
|
+
preKeyFilesFor: (baseDir: string, phone: string) => string[];
|
|
999
|
+
/** Every per-number file the library writes. */
|
|
1000
|
+
SESSION_SUFFIXES: string[];
|
|
1001
|
+
SHARED_FILES: string[];
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1005
|
+
// Device
|
|
1006
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1007
|
+
|
|
1008
|
+
/** Reads `WA_OS`, `WA_DEVICE` and the `WA_DEVICE_*` overrides from `process.env`. */
|
|
1009
|
+
export declare function getDeviceConfig(): DeviceConfig;
|
|
1010
|
+
|
|
1011
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1012
|
+
// Media
|
|
1013
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1014
|
+
|
|
1015
|
+
/** What `encryptMedia` hands back. */
|
|
1016
|
+
export interface EncryptedMedia {
|
|
1017
|
+
/** Ciphertext with the 10-byte MAC appended — the bytes that go to the CDN. */
|
|
1018
|
+
encrypted: Buffer;
|
|
1019
|
+
/** SHA-256 over the plaintext; the message's `fileSha256`. */
|
|
1020
|
+
sha256Plain: Buffer;
|
|
1021
|
+
/** SHA-256 over `encrypted`; the message's `fileEncSha256`. */
|
|
1022
|
+
sha256Enc: Buffer;
|
|
1023
|
+
/** The key it was encrypted under, echoed back. */
|
|
1024
|
+
mediaKey: Buffer;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* `keyName` is the HKDF info string, not the media type — `'WhatsApp Image
|
|
1029
|
+
* Keys'`, `'WhatsApp Video Keys'`, and so on. A sticker is keyed as an image
|
|
1030
|
+
* and a voice note as audio; `getMediaKeyName()` in `whalibmob/lib/MediaService`
|
|
1031
|
+
* maps a media type to the right one.
|
|
1032
|
+
*/
|
|
1033
|
+
export declare function encryptMedia(plaintext: Buffer, mediaKey: Buffer, keyName: string): EncryptedMedia;
|
|
1034
|
+
/** Verifies the trailing MAC and throws if it does not match. */
|
|
1035
|
+
export declare function decryptMedia(encryptedWithMac: Buffer, mediaKey: Buffer, keyName: string): Buffer;
|
|
1036
|
+
export declare function uploadMedia(...args: any[]): Promise<any>;
|
|
1037
|
+
export declare function downloadMedia(url: string, mediaKey: Buffer, keyName: string, opts?: object): Promise<Buffer>;
|
|
1038
|
+
|
|
1039
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1040
|
+
// Message helpers
|
|
1041
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1042
|
+
|
|
1043
|
+
/** Normalises bare digits or a partial JID into a full one. */
|
|
1044
|
+
export declare function makeJid(input: string): Jid;
|
|
1045
|
+
export declare function generateMessageId(): string;
|
|
1046
|
+
export declare const MessageSender: any;
|
|
1047
|
+
|
|
1048
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1049
|
+
// Signal key store utilities
|
|
1050
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1051
|
+
|
|
1052
|
+
/** Wraps a `SignalStore` with a 5-minute in-memory cache. */
|
|
1053
|
+
export declare function makeCacheableSignalKeyStore<T>(store: T): T & { flushCache(): Promise<void> };
|
|
1054
|
+
/** Wraps a `SignalStore` with batched-write (transaction) semantics. */
|
|
1055
|
+
export declare function addTransactionCapability<T>(store: T): T & {
|
|
1056
|
+
transaction<R>(fn: () => Promise<R>, key?: string): Promise<R>;
|
|
1057
|
+
isInTransaction(): boolean;
|
|
1058
|
+
};
|
|
1059
|
+
/** The account's JID, or throws describing what is missing. */
|
|
1060
|
+
export declare function assertMeId(store: WhalibmobStore | WhalibmobWebStore): Jid;
|
|
1061
|
+
|
|
1062
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1063
|
+
// History sync
|
|
1064
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1065
|
+
|
|
1066
|
+
export declare const HistorySyncType: Record<string, number>;
|
|
1067
|
+
export declare const HistorySyncTypeName: Record<number, string>;
|
|
1068
|
+
export declare function processHistorySyncNotification(...args: any[]): Promise<any>;
|
|
1069
|
+
export declare function decodeHistorySyncNotification(buf: Buffer): any;
|
|
1070
|
+
export declare function decodeHistorySync(buf: Buffer): any;
|
|
1071
|
+
export declare function decodeAppStateSyncKeyShare(buf: Buffer): any;
|
|
1072
|
+
export declare function saveAppStateSyncKeys(...args: any[]): any;
|
|
1073
|
+
export declare function loadAppStateSyncKeys(...args: any[]): any;
|
|
1074
|
+
export declare function mergeHistoryToStore(...args: any[]): any;
|
|
1075
|
+
export declare function decryptHistoryBlob(blob: Buffer, key: Buffer): Buffer;
|
|
1076
|
+
export declare function deriveHistoryKeys(key: Buffer): any;
|
|
1077
|
+
|
|
1078
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1079
|
+
// Companion pairing internals
|
|
1080
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1081
|
+
|
|
1082
|
+
export declare function generatePairingCode(): string;
|
|
1083
|
+
export declare function derivePairingCodeKey(...args: any[]): any;
|
|
1084
|
+
export declare function buildWrappedEphemeralPub(...args: any[]): any;
|
|
1085
|
+
export declare function decipherLinkPublicKey(...args: any[]): any;
|
|
1086
|
+
export declare function buildCompanionFinishBundle(...args: any[]): any;
|
|
1087
|
+
export declare function configureSuccessfulPairing(...args: any[]): any;
|
|
1088
|
+
export declare function encodeCompanionRegisterPayload(...args: any[]): Buffer;
|
|
1089
|
+
export declare function encodeCompanionLoginPayload(...args: any[]): Buffer;
|
|
1090
|
+
|
|
1091
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1092
|
+
// Internals exported for advanced use.
|
|
1093
|
+
//
|
|
1094
|
+
// These are typed loosely on purpose: their surfaces are large and mostly
|
|
1095
|
+
// internal, and a plausible-looking wrong signature would be worse than `any`.
|
|
1096
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
1097
|
+
|
|
1098
|
+
export declare const SignalProtocol: any;
|
|
1099
|
+
export declare const SignalStore: any;
|
|
1100
|
+
export declare const SenderKeyStore: any;
|
|
1101
|
+
export declare const SenderKeyCrypto: any;
|
|
1102
|
+
export declare const DeviceManager: any;
|
|
1103
|
+
export declare const AppStateStore: any;
|
|
1104
|
+
export declare const AppStateSync: any;
|
|
1105
|
+
export declare const APP_STATE_COLLECTIONS: string[];
|
|
1106
|
+
export declare const LT_HASH: any;
|
|
1107
|
+
export declare const ReachoutTimelock: any;
|
|
1108
|
+
export declare const WAM: any;
|
|
1109
|
+
export declare const encodeWAM: any;
|
|
1110
|
+
export declare const BinaryInfo: any;
|
|
1111
|
+
export declare const WEB_EVENTS: any;
|
|
1112
|
+
export declare const WEB_GLOBALS: any;
|
|
1113
|
+
export declare function decodeArgo(buf: Buffer): any;
|
|
1114
|
+
export declare function tryDecodeArgo(buf: Buffer): any;
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whalibmob",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.24.0",
|
|
4
4
|
"description": "Node.js library for WhatsApp — register a number over SMS, or link as a companion by QR. Signal E2E encryption, media, groups, channels.",
|
|
5
5
|
"author": "Kunboruto20",
|
|
6
6
|
"main": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
7
8
|
"bin": {
|
|
8
9
|
"wa": "./cli.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"index.js",
|
|
13
|
+
"index.d.ts",
|
|
12
14
|
"cli.js",
|
|
13
15
|
"lib/**/*.js",
|
|
14
16
|
"tools/**/*.js",
|
|
@@ -17,9 +19,14 @@
|
|
|
17
19
|
".env.example"
|
|
18
20
|
],
|
|
19
21
|
"type": "commonjs",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "node --test",
|
|
24
|
+
"test:types": "tsc --noEmit --strict --skipLibCheck index.d.ts",
|
|
25
|
+
"test:all": "npm test && npm run test:types"
|
|
26
|
+
},
|
|
20
27
|
"license": "MIT",
|
|
21
28
|
"engines": {
|
|
22
|
-
"node": ">=
|
|
29
|
+
"node": ">=18.0.0"
|
|
23
30
|
},
|
|
24
31
|
"keywords": [
|
|
25
32
|
"whatsapp",
|
|
@@ -71,5 +78,9 @@
|
|
|
71
78
|
"jimp": "^1.6.0",
|
|
72
79
|
"socks": "^2.8.9",
|
|
73
80
|
"qrcode-terminal": "^0.12.0"
|
|
81
|
+
},
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"@types/node": "^22.0.0",
|
|
84
|
+
"typescript": "^5.9.0"
|
|
74
85
|
}
|
|
75
86
|
}
|