@kelvdra/baileys 1.0.3 → 1.0.4

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.
Files changed (109) hide show
  1. package/README.md +75 -1499
  2. package/lib/Defaults/index.d.ts +62 -0
  3. package/lib/Defaults/index.js +2 -2
  4. package/lib/Defaults/phonenumber-mcc.json +223 -0
  5. package/lib/Signal/Group/ciphertext-message.d.ts +10 -0
  6. package/lib/Signal/Group/group-session-builder.d.ts +15 -0
  7. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  8. package/lib/Signal/Group/index.d.ts +12 -0
  9. package/lib/Signal/Group/keyhelper.d.ts +11 -0
  10. package/lib/Signal/Group/sender-chain-key.d.ts +14 -0
  11. package/lib/Signal/Group/sender-key-distribution-message.d.ts +17 -0
  12. package/lib/Signal/Group/sender-key-message.d.ts +19 -0
  13. package/lib/Signal/Group/sender-key-name.d.ts +18 -0
  14. package/lib/Signal/Group/sender-key-record.d.ts +31 -0
  15. package/lib/Signal/Group/sender-key-state.d.ts +39 -0
  16. package/lib/Signal/Group/sender-message-key.d.ts +12 -0
  17. package/lib/Signal/libsignal.d.ts +5 -0
  18. package/lib/Signal/lid-mapping.d.ts +23 -0
  19. package/lib/Socket/Client/index.d.ts +3 -0
  20. package/lib/Socket/Client/types.d.ts +16 -0
  21. package/lib/Socket/Client/websocket.d.ts +13 -0
  22. package/lib/Socket/business.d.ts +190 -0
  23. package/lib/Socket/chats.d.ts +100 -0
  24. package/lib/Socket/chats.js +14 -13
  25. package/lib/Socket/communities.d.ts +246 -0
  26. package/lib/Socket/groups.d.ts +139 -0
  27. package/lib/Socket/groups.js +2 -3
  28. package/lib/Socket/hydra.js +1 -2
  29. package/lib/Socket/index.d.ts +233 -0
  30. package/lib/Socket/messages-recv.d.ts +175 -0
  31. package/lib/Socket/messages-recv.js +325 -515
  32. package/lib/Socket/messages-send.d.ts +171 -0
  33. package/lib/Socket/messages-send.js +104 -467
  34. package/lib/Socket/mex.d.ts +3 -0
  35. package/lib/Socket/newsletter.d.ts +149 -0
  36. package/lib/Socket/socket.d.ts +53 -0
  37. package/lib/Socket/socket.js +52 -51
  38. package/lib/Store/index.d.ts +4 -0
  39. package/lib/Store/make-cache-manager-store.d.ts +14 -0
  40. package/lib/Store/make-in-memory-store.d.ts +123 -0
  41. package/lib/Store/make-ordered-dictionary.d.ts +12 -0
  42. package/lib/Store/object-repository.d.ts +10 -0
  43. package/lib/Types/Auth.d.ts +115 -0
  44. package/lib/Types/Bussines.d.ts +25 -0
  45. package/lib/Types/Call.d.ts +14 -0
  46. package/lib/Types/Chat.d.ts +123 -0
  47. package/lib/Types/Contact.d.ts +24 -0
  48. package/lib/Types/Events.d.ts +202 -0
  49. package/lib/Types/GroupMetadata.d.ts +67 -0
  50. package/lib/Types/Label.d.ts +47 -0
  51. package/lib/Types/LabelAssociation.d.ts +30 -0
  52. package/lib/Types/Message.d.ts +382 -0
  53. package/lib/Types/Newsletter.d.ts +135 -0
  54. package/lib/Types/Product.d.ts +79 -0
  55. package/lib/Types/Signal.d.ts +76 -0
  56. package/lib/Types/Socket.d.ts +133 -0
  57. package/lib/Types/State.d.ts +39 -0
  58. package/lib/Types/USync.d.ts +26 -0
  59. package/lib/Types/index.d.ts +65 -0
  60. package/lib/Utils/auth-utils.d.ts +19 -0
  61. package/lib/Utils/browser-utils.d.ts +4 -0
  62. package/lib/Utils/business.d.ts +23 -0
  63. package/lib/Utils/chat-utils.d.ts +70 -0
  64. package/lib/Utils/crypto.d.ts +41 -0
  65. package/lib/Utils/decode-wa-message.d.ts +48 -0
  66. package/lib/Utils/decode-wa-message.js +5 -7
  67. package/lib/Utils/event-buffer.d.ts +34 -0
  68. package/lib/Utils/generics.d.ts +90 -0
  69. package/lib/Utils/history.d.ts +19 -0
  70. package/lib/Utils/index.d.ts +19 -0
  71. package/lib/Utils/link-preview.d.ts +21 -0
  72. package/lib/Utils/logger.d.ts +12 -0
  73. package/lib/Utils/lt-hash.d.ts +13 -0
  74. package/lib/Utils/make-mutex.d.ts +8 -0
  75. package/lib/Utils/message-retry-manager.d.ts +82 -0
  76. package/lib/Utils/messages-media.d.ts +114 -0
  77. package/lib/Utils/messages-media.js +69 -33
  78. package/lib/Utils/messages.d.ts +89 -0
  79. package/lib/Utils/messages.js +42 -12
  80. package/lib/Utils/noise-handler.d.ts +20 -0
  81. package/lib/Utils/pre-key-manager.d.ts +28 -0
  82. package/lib/Utils/process-message.d.ts +60 -0
  83. package/lib/Utils/signal.d.ts +34 -0
  84. package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
  85. package/lib/Utils/validate-connection.d.ts +11 -0
  86. package/lib/WABinary/constants.d.ts +28 -0
  87. package/lib/WABinary/decode.d.ts +7 -0
  88. package/lib/WABinary/encode.d.ts +3 -0
  89. package/lib/WABinary/generic-utils.d.ts +15 -0
  90. package/lib/WABinary/generic-utils.js +7 -0
  91. package/lib/WABinary/index.d.ts +6 -0
  92. package/lib/WABinary/jid-utils.d.ts +48 -0
  93. package/lib/WABinary/types.d.ts +19 -0
  94. package/lib/WAM/BinaryInfo.d.ts +9 -0
  95. package/lib/WAM/constants.d.ts +40 -0
  96. package/lib/WAM/encode.d.ts +3 -0
  97. package/lib/WAM/index.d.ts +4 -0
  98. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
  99. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
  100. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
  101. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
  102. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
  103. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
  104. package/lib/WAUSync/Protocols/index.d.ts +5 -0
  105. package/lib/WAUSync/USyncQuery.d.ts +29 -0
  106. package/lib/WAUSync/USyncUser.d.ts +13 -0
  107. package/lib/WAUSync/index.d.ts +4 -0
  108. package/lib/index.d.ts +13 -0
  109. package/package.json +3 -34
@@ -0,0 +1,19 @@
1
+ export * from './generics.js';
2
+ export * from './decode-wa-message.js';
3
+ export * from './messages.js';
4
+ export * from './messages-media.js';
5
+ export * from './validate-connection.js';
6
+ export * from './crypto.js';
7
+ export * from './signal.js';
8
+ export * from './noise-handler.js';
9
+ export * from './history.js';
10
+ export * from './chat-utils.js';
11
+ export * from './lt-hash.js';
12
+ export * from './auth-utils.js';
13
+ export * from './use-multi-file-auth-state.js';
14
+ export * from './link-preview.js';
15
+ export * from './event-buffer.js';
16
+ export * from './process-message.js';
17
+ export * from './message-retry-manager.js';
18
+ export * from './browser-utils.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,21 @@
1
+ import type { WAMediaUploadFunction, WAUrlInfo } from '../Types/index.js';
2
+ import type { ILogger } from './logger.js';
3
+ export type URLGenerationOptions = {
4
+ thumbnailWidth: number;
5
+ fetchOpts: {
6
+ /** Timeout in ms */
7
+ timeout: number;
8
+ proxyUrl?: string;
9
+ headers?: HeadersInit;
10
+ };
11
+ uploadImage?: WAMediaUploadFunction;
12
+ logger?: ILogger;
13
+ };
14
+ /**
15
+ * Given a piece of text, checks for any URL present, generates link preview for the same and returns it
16
+ * Return undefined if the fetch failed or no URL was found
17
+ * @param text first matched URL in text
18
+ * @returns the URL info required to generate link preview
19
+ */
20
+ export declare const getUrlInfo: (text: string, opts?: URLGenerationOptions) => Promise<WAUrlInfo | undefined>;
21
+ //# sourceMappingURL=link-preview.d.ts.map
@@ -0,0 +1,12 @@
1
+ export interface ILogger {
2
+ level: string;
3
+ child(obj: Record<string, unknown>): ILogger;
4
+ trace(obj: unknown, msg?: string): void;
5
+ debug(obj: unknown, msg?: string): void;
6
+ info(obj: unknown, msg?: string): void;
7
+ warn(obj: unknown, msg?: string): void;
8
+ error(obj: unknown, msg?: string): void;
9
+ }
10
+ declare const _default: import("pino").Logger<never, boolean>;
11
+ export default _default;
12
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1,13 @@
1
+ declare class LTHash {
2
+ salt: string;
3
+ constructor(e: string);
4
+ add(e: ArrayBuffer, t: ArrayBuffer[]): Promise<ArrayBuffer>;
5
+ subtract(e: ArrayBuffer, t: ArrayBuffer[]): Promise<ArrayBuffer>;
6
+ subtractThenAdd(e: ArrayBuffer, addList: ArrayBuffer[], subtractList: ArrayBuffer[]): Promise<ArrayBuffer>;
7
+ private _addSingle;
8
+ private _subtractSingle;
9
+ private performPointwiseWithOverflow;
10
+ }
11
+ export declare const LT_HASH_ANTI_TAMPERING: LTHash;
12
+ export {};
13
+ //# sourceMappingURL=lt-hash.d.ts.map
@@ -0,0 +1,8 @@
1
+ export declare const makeMutex: () => {
2
+ mutex<T>(code: () => Promise<T> | T): Promise<T>;
3
+ };
4
+ export type Mutex = ReturnType<typeof makeMutex>;
5
+ export declare const makeKeyedMutex: () => {
6
+ mutex<T>(key: string, task: () => Promise<T> | T): Promise<T>;
7
+ };
8
+ //# sourceMappingURL=make-mutex.d.ts.map
@@ -0,0 +1,82 @@
1
+ import type { proto } from '../../WAProto/index.js';
2
+ import type { ILogger } from './logger.js';
3
+ export interface RecentMessageKey {
4
+ to: string;
5
+ id: string;
6
+ }
7
+ export interface RecentMessage {
8
+ message: proto.IMessage;
9
+ timestamp: number;
10
+ }
11
+ export interface SessionRecreateHistory {
12
+ [jid: string]: number;
13
+ }
14
+ export interface RetryCounter {
15
+ [messageId: string]: number;
16
+ }
17
+ export type PendingPhoneRequest = Record<string, ReturnType<typeof setTimeout>>;
18
+ export interface RetryStatistics {
19
+ totalRetries: number;
20
+ successfulRetries: number;
21
+ failedRetries: number;
22
+ mediaRetries: number;
23
+ sessionRecreations: number;
24
+ phoneRequests: number;
25
+ }
26
+ export declare class MessageRetryManager {
27
+ private logger;
28
+ private recentMessagesMap;
29
+ private messageKeyIndex;
30
+ private sessionRecreateHistory;
31
+ private retryCounters;
32
+ private pendingPhoneRequests;
33
+ private readonly maxMsgRetryCount;
34
+ private statistics;
35
+ constructor(logger: ILogger, maxMsgRetryCount: number);
36
+ /**
37
+ * Add a recent message to the cache for retry handling
38
+ */
39
+ addRecentMessage(to: string, id: string, message: proto.IMessage): void;
40
+ /**
41
+ * Get a recent message from the cache
42
+ */
43
+ getRecentMessage(to: string, id: string): RecentMessage | undefined;
44
+ /**
45
+ * Check if a session should be recreated based on retry count and history
46
+ */
47
+ shouldRecreateSession(jid: string, retryCount: number, hasSession: boolean): {
48
+ reason: string;
49
+ recreate: boolean;
50
+ };
51
+ /**
52
+ * Increment retry counter for a message
53
+ */
54
+ incrementRetryCount(messageId: string): number;
55
+ /**
56
+ * Get retry count for a message
57
+ */
58
+ getRetryCount(messageId: string): number;
59
+ /**
60
+ * Check if message has exceeded maximum retry attempts
61
+ */
62
+ hasExceededMaxRetries(messageId: string): boolean;
63
+ /**
64
+ * Mark retry as successful
65
+ */
66
+ markRetrySuccess(messageId: string): void;
67
+ /**
68
+ * Mark retry as failed
69
+ */
70
+ markRetryFailed(messageId: string): void;
71
+ /**
72
+ * Schedule a phone request with delay
73
+ */
74
+ schedulePhoneRequest(messageId: string, callback: () => void, delay?: number): void;
75
+ /**
76
+ * Cancel pending phone request
77
+ */
78
+ cancelPendingPhoneRequest(messageId: string): void;
79
+ private keyToString;
80
+ private removeRecentMessage;
81
+ }
82
+ //# sourceMappingURL=message-retry-manager.d.ts.map
@@ -0,0 +1,114 @@
1
+ import { Boom } from '@hapi/boom';
2
+ import { Readable, Transform } from 'stream';
3
+ import { URL } from 'url';
4
+ import { proto } from '../../WAProto/index.js';
5
+ import { type MediaType } from '../Defaults/index.js';
6
+ import type { DownloadableMessage, MediaConnInfo, MediaDecryptionKeyInfo, SocketConfig, WAMediaUpload, WAMediaUploadFunction, WAMessageContent, WAMessageKey } from '../Types/index.js';
7
+ import { type BinaryNode } from '../WABinary/index.js';
8
+ import type { ILogger } from './logger.js';
9
+ export declare const hkdfInfoKey: (type: MediaType) => string;
10
+ export declare const getRawMediaUploadData: (media: WAMediaUpload, mediaType: MediaType, logger?: ILogger) => Promise<{
11
+ filePath: string;
12
+ fileSha256: Buffer<ArrayBufferLike>;
13
+ fileLength: number;
14
+ }>;
15
+ /** generates all the keys required to encrypt/decrypt & sign a media message */
16
+ export declare function getMediaKeys(buffer: Uint8Array | string | null | undefined, mediaType: MediaType): Promise<MediaDecryptionKeyInfo>;
17
+ export declare const extractImageThumb: (bufferOrFilePath: Readable | Buffer | string, width?: number) => Promise<{
18
+ buffer: any;
19
+ original: {
20
+ width: any;
21
+ height: any;
22
+ };
23
+ }>;
24
+ export declare const encodeBase64EncodedStringForUpload: (b64: string) => string;
25
+ export declare const generateProfilePicture: (mediaUpload: WAMediaUpload, dimensions?: {
26
+ width: number;
27
+ height: number;
28
+ }) => Promise<{
29
+ img: Buffer<ArrayBufferLike>;
30
+ }>;
31
+ /** gets the SHA256 of the given media message */
32
+ export declare const mediaMessageSHA256B64: (message: WAMessageContent) => string | null | undefined;
33
+ export declare function getAudioDuration(buffer: Buffer | string | Readable): Promise<number | undefined>;
34
+ /**
35
+ referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
36
+ */
37
+ export declare function getAudioWaveform(buffer: Buffer | string | Readable, logger?: ILogger): Promise<Uint8Array<ArrayBuffer> | undefined>;
38
+ export declare const toReadable: (buffer: Buffer) => Readable;
39
+ export declare const toBuffer: (stream: Readable) => Promise<Buffer<ArrayBuffer>>;
40
+ export declare const getStream: (item: WAMediaUpload, opts?: RequestInit & {
41
+ maxContentLength?: number;
42
+ }) => Promise<{
43
+ readonly stream: Readable;
44
+ readonly type: "buffer";
45
+ } | {
46
+ readonly stream: Readable;
47
+ readonly type: "readable";
48
+ } | {
49
+ readonly stream: Readable;
50
+ readonly type: "remote";
51
+ } | {
52
+ readonly stream: import("fs").ReadStream;
53
+ readonly type: "file";
54
+ }>;
55
+ /** generates a thumbnail for a given media, if required */
56
+ export declare function generateThumbnail(file: string, mediaType: 'video' | 'image', options: {
57
+ logger?: ILogger;
58
+ }): Promise<{
59
+ thumbnail: string | undefined;
60
+ originalImageDimensions: {
61
+ width: number;
62
+ height: number;
63
+ } | undefined;
64
+ }>;
65
+ export declare const getHttpStream: (url: string | URL, options?: RequestInit & {
66
+ isStream?: true;
67
+ }) => Promise<Readable>;
68
+ type EncryptedStreamOptions = {
69
+ saveOriginalFileIfRequired?: boolean;
70
+ logger?: ILogger;
71
+ opts?: RequestInit;
72
+ };
73
+ export declare const encryptedStream: (media: WAMediaUpload, mediaType: MediaType, { logger, saveOriginalFileIfRequired, opts }?: EncryptedStreamOptions) => Promise<{
74
+ mediaKey: Buffer<ArrayBufferLike>;
75
+ originalFilePath: string | undefined;
76
+ encFilePath: string;
77
+ mac: Buffer<ArrayBuffer>;
78
+ fileEncSha256: Buffer<ArrayBufferLike>;
79
+ fileSha256: Buffer<ArrayBufferLike>;
80
+ fileLength: number;
81
+ }>;
82
+ export type MediaDownloadOptions = {
83
+ startByte?: number;
84
+ endByte?: number;
85
+ options?: RequestInit;
86
+ };
87
+ export declare const getUrlFromDirectPath: (directPath: string) => string;
88
+ export declare const downloadContentFromMessage: ({ mediaKey, directPath, url }: DownloadableMessage, type: MediaType, opts?: MediaDownloadOptions) => Promise<Transform>;
89
+ /**
90
+ * Decrypts and downloads an AES256-CBC encrypted file given the keys.
91
+ * Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
92
+ * */
93
+ export declare const downloadEncryptedContent: (downloadUrl: string, { cipherKey, iv }: MediaDecryptionKeyInfo, { startByte, endByte, options }?: MediaDownloadOptions) => Promise<Transform>;
94
+ export declare function extensionForMediaMessage(message: WAMessageContent): string;
95
+ export declare const getWAUploadToServer: ({ customUploadHosts, fetchAgent, logger, options }: SocketConfig, refreshMediaConn: (force: boolean) => Promise<MediaConnInfo>) => WAMediaUploadFunction;
96
+ /**
97
+ * Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
98
+ */
99
+ export declare const encryptMediaRetryRequest: (key: WAMessageKey, mediaKey: Buffer | Uint8Array, meId: string) => Promise<BinaryNode>;
100
+ export declare const decodeMediaRetryNode: (node: BinaryNode) => {
101
+ key: WAMessageKey;
102
+ media?: {
103
+ ciphertext: Uint8Array;
104
+ iv: Uint8Array;
105
+ };
106
+ error?: Boom;
107
+ };
108
+ export declare const decryptMediaRetryData: ({ ciphertext, iv }: {
109
+ ciphertext: Uint8Array;
110
+ iv: Uint8Array;
111
+ }, mediaKey: Uint8Array, msgId: string) => Promise<proto.MediaRetryNotification>;
112
+ export declare const getStatusCodeForMediaRetry: (code: number) => 200 | 412 | 404 | 418;
113
+ export {};
114
+ //# sourceMappingURL=messages-media.d.ts.map
@@ -168,6 +168,7 @@ export const generateProfilePicture = async (mediaUpload) => {
168
168
  img: await img,
169
169
  }
170
170
  }
171
+
171
172
  /** gets the SHA256 of the given media message */
172
173
  export const mediaMessageSHA256B64 = (message) => {
173
174
  const media = Object.values(message)[0];
@@ -195,41 +196,55 @@ export async function getAudioDuration(buffer) {
195
196
  */
196
197
  export async function getAudioWaveform(buffer, logger) {
197
198
  try {
198
- // @ts-ignore
199
- const { default: decoder } = await import('audio-decode');
199
+ const { PassThrough } = require('stream');
200
+ const ff = require('fluent-ffmpeg');
201
+
200
202
  let audioData;
201
203
  if (Buffer.isBuffer(buffer)) {
202
204
  audioData = buffer;
203
- }
204
- else if (typeof buffer === 'string') {
205
- const rStream = createReadStream(buffer);
205
+ } else if (typeof buffer === 'string') {
206
+ const rStream = require('fs').createReadStream(buffer);
206
207
  audioData = await toBuffer(rStream);
207
- }
208
- else {
208
+ } else {
209
209
  audioData = await toBuffer(buffer);
210
210
  }
211
- const audioBuffer = await decoder(audioData);
212
- const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
213
- const samples = 64; // Number of samples we want to have in our final data set
214
- const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
215
- const filteredData = [];
216
- for (let i = 0; i < samples; i++) {
217
- const blockStart = blockSize * i; // the location of the first sample in the block
218
- let sum = 0;
219
- for (let j = 0; j < blockSize; j++) {
220
- sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
221
- }
222
- filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
223
- }
224
- // This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
225
- const multiplier = Math.pow(Math.max(...filteredData), -1);
226
- const normalizedData = filteredData.map(n => n * multiplier);
227
- // Generate waveform like WhatsApp
228
- const waveform = new Uint8Array(normalizedData.map(n => Math.floor(100 * n)));
229
- return waveform;
230
- }
231
- catch (e) {
232
- logger?.debug('Failed to generate waveform: ' + e);
211
+
212
+ return await new Promise((resolve, reject) => {
213
+ const inputStream = new PassThrough();
214
+ inputStream.end(audioData);
215
+ const chunks = [];
216
+ const bars = 64;
217
+
218
+ ff(inputStream)
219
+ .audioChannels(1)
220
+ .audioFrequency(16000)
221
+ .format('s16le')
222
+ .on('error', reject)
223
+ .on('end', () => {
224
+ const rawData = Buffer.concat(chunks);
225
+ const samples = rawData.length / 2;
226
+ const amplitudes = [];
227
+
228
+ for (let i = 0; i < samples; i++) {
229
+ amplitudes.push(Math.abs(rawData.readInt16LE(i * 2)) / 32768);
230
+ }
231
+
232
+ const blockSize = Math.floor(amplitudes.length / bars);
233
+ const avg = [];
234
+ for (let i = 0; i < bars; i++) {
235
+ const block = amplitudes.slice(i * blockSize, (i + 1) * blockSize);
236
+ avg.push(block.reduce((a, b) => a + b, 0) / block.length);
237
+ }
238
+
239
+ const max = Math.max(...avg);
240
+ const normalized = avg.map(v => Math.floor((v / max) * 100));
241
+ resolve(new Uint8Array(normalized));
242
+ })
243
+ .pipe()
244
+ .on('data', chunk => chunks.push(chunk));
245
+ });
246
+ } catch (e) {
247
+ logger?.debug(e);
233
248
  }
234
249
  }
235
250
  export const toReadable = (buffer) => {
@@ -294,17 +309,38 @@ export async function generateThumbnail(file, mediaType, options) {
294
309
  originalImageDimensions
295
310
  };
296
311
  }
312
+ /**
313
+ * Mengambil stream dari URL, mendukung Web ReadableStream dan Node.js Stream
314
+ */
297
315
  export const getHttpStream = async (url, options = {}) => {
298
316
  const response = await fetch(url.toString(), {
299
317
  dispatcher: options.dispatcher,
300
318
  method: 'GET',
301
319
  headers: options.headers
302
320
  });
321
+
303
322
  if (!response.ok) {
304
- throw new Boom(`Failed to fetch stream from ${url}`, { statusCode: response.status, data: { url } });
323
+ throw new Boom(`Failed to fetch stream from ${url}`, {
324
+ statusCode: response.status,
325
+ data: { url }
326
+ });
305
327
  }
306
- // @ts-ignore Node18+ Readable.fromWeb exists
307
- return response.body instanceof Readable ? response.body : Readable.fromWeb(response.body);
328
+
329
+ const body = response.body;
330
+
331
+ // Jika body adalah Web ReadableStream (Node.js 18+), konversi
332
+ if (body && typeof body === 'object' && 'pipeTo' in body && typeof body.pipeTo === 'function') {
333
+ // @ts-ignore - Readable.fromWeb exists in Node.js 18+
334
+ return Readable.fromWeb(body);
335
+ }
336
+
337
+ // Jika body sudah Node.js Readable (misal: PassThrough dari node-fetch)
338
+ if (body && typeof body.pipe === 'function' && typeof body.read === 'function') {
339
+ return body;
340
+ }
341
+
342
+ // Fallback: buat stream kosong atau error
343
+ throw new Error('Response body is not a readable stream');
308
344
  };
309
345
  export const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
310
346
  const { stream, type } = await getStream(media, opts);
@@ -660,4 +696,4 @@ const MEDIA_RETRY_STATUS_MAP = {
660
696
  [proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
661
697
  [proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418
662
698
  };
663
- //# sourceMappingURL=messages-media.js.map
699
+ //# sourceMappingURL=messages-media.js.map
@@ -0,0 +1,89 @@
1
+ import { type Transform } from 'stream';
2
+ import { proto } from '../../WAProto/index.js';
3
+ import type { AnyMediaMessageContent, AnyMessageContent, MessageContentGenerationOptions, MessageGenerationOptions, MessageGenerationOptionsFromContent, MessageUserReceipt, WAMessage, WAMessageContent, WAMessageKey } from '../Types/index.js';
4
+ import type { ILogger } from './logger.js';
5
+ import { type MediaDownloadOptions } from './messages-media.js';
6
+ /**
7
+ * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
8
+ * @param text eg. hello https://google.com
9
+ * @returns the URL, eg. https://google.com
10
+ */
11
+ export declare const extractUrlFromText: (text: string) => string | undefined;
12
+ export declare const generateLinkPreviewIfRequired: (text: string, getUrlInfo: MessageGenerationOptions["getUrlInfo"], logger: MessageGenerationOptions["logger"]) => Promise<import("../Types/index.js").WAUrlInfo | undefined>;
13
+ export declare const prepareWAMessageMedia: (message: AnyMediaMessageContent, options: MessageContentGenerationOptions) => Promise<proto.Message>;
14
+ export declare const prepareDisappearingMessageSettingContent: (ephemeralExpiration?: number) => proto.Message;
15
+ /**
16
+ * Generate forwarded message content like WA does
17
+ * @param message the message to forward
18
+ * @param options.forceForward will show the message as forwarded even if it is from you
19
+ */
20
+ export declare const generateForwardMessageContent: (message: WAMessage, forceForward?: boolean) => proto.IMessage;
21
+ export declare const generateWAMessageContent: (message: AnyMessageContent, options: MessageContentGenerationOptions) => Promise<proto.Message>;
22
+ export declare const generateWAMessageFromContent: (jid: string, message: WAMessageContent, options: MessageGenerationOptionsFromContent) => WAMessage;
23
+ export declare const generateWAMessage: (jid: string, content: AnyMessageContent, options: MessageGenerationOptions) => Promise<WAMessage>;
24
+ /** Get the key to access the true type of content */
25
+ export declare const getContentType: (content: proto.IMessage | undefined) => keyof proto.IMessage | undefined;
26
+ /**
27
+ * Normalizes ephemeral, view once messages to regular message content
28
+ * Eg. image messages in ephemeral messages, in view once messages etc.
29
+ * @param content
30
+ * @returns
31
+ */
32
+ export declare const normalizeMessageContent: (content: WAMessageContent | null | undefined) => WAMessageContent | undefined;
33
+ /**
34
+ * Extract the true message content from a message
35
+ * Eg. extracts the inner message from a disappearing message/view once message
36
+ */
37
+ export declare const extractMessageContent: (content: WAMessageContent | undefined | null) => WAMessageContent | undefined;
38
+ /**
39
+ * Returns the device predicted by message ID
40
+ */
41
+ export declare const getDevice: (id: string) => "web" | "unknown" | "android" | "ios" | "desktop";
42
+ /** Upserts a receipt in the message */
43
+ export declare const updateMessageWithReceipt: (msg: Pick<WAMessage, "userReceipt">, receipt: MessageUserReceipt) => void;
44
+ /** Update the message with a new reaction */
45
+ export declare const updateMessageWithReaction: (msg: Pick<WAMessage, "reactions">, reaction: proto.IReaction) => void;
46
+ /** Update the message with a new poll update */
47
+ export declare const updateMessageWithPollUpdate: (msg: Pick<WAMessage, "pollUpdates">, update: proto.IPollUpdate) => void;
48
+ /** Update the message with a new event response */
49
+ export declare const updateMessageWithEventResponse: (msg: Pick<WAMessage, "eventResponses">, update: proto.IEventResponse) => void;
50
+ type VoteAggregation = {
51
+ name: string;
52
+ voters: string[];
53
+ };
54
+ /**
55
+ * Aggregates all poll updates in a poll.
56
+ * @param msg the poll creation message
57
+ * @param meId your jid
58
+ * @returns A list of options & their voters
59
+ */
60
+ export declare function getAggregateVotesInPollMessage({ message, pollUpdates }: Pick<WAMessage, 'pollUpdates' | 'message'>, meId?: string): VoteAggregation[];
61
+ type ResponseAggregation = {
62
+ response: string;
63
+ responders: string[];
64
+ };
65
+ /**
66
+ * Aggregates all event responses in an event message.
67
+ * @param msg the event creation message
68
+ * @param meId your jid
69
+ * @returns A list of response types & their responders
70
+ */
71
+ export declare function getAggregateResponsesInEventMessage({ eventResponses }: Pick<WAMessage, 'eventResponses'>, meId?: string): ResponseAggregation[];
72
+ /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
73
+ export declare const aggregateMessageKeysNotFromMe: (keys: WAMessageKey[]) => {
74
+ jid: string;
75
+ participant: string | undefined;
76
+ messageIds: string[];
77
+ }[];
78
+ type DownloadMediaMessageContext = {
79
+ reuploadRequest: (msg: WAMessage) => Promise<WAMessage>;
80
+ logger: ILogger;
81
+ };
82
+ /**
83
+ * Downloads the given message. Throws an error if it's not a media message
84
+ */
85
+ export declare const downloadMediaMessage: <Type extends "buffer" | "stream">(message: WAMessage, type: Type, options: MediaDownloadOptions, ctx?: DownloadMediaMessageContext) => Promise<Type extends "buffer" ? Buffer<ArrayBufferLike> : Transform>;
86
+ /** Checks whether the given message is a media message; if it is returns the inner content */
87
+ export declare const assertMediaContent: (content: proto.IMessage | null | undefined) => proto.Message.IVideoMessage | proto.Message.IImageMessage | proto.Message.IAudioMessage | proto.Message.IDocumentMessage | proto.Message.IStickerMessage;
88
+ export {};
89
+ //# sourceMappingURL=messages.d.ts.map
@@ -86,10 +86,10 @@ export const prepareWAMessageMedia = async (message, options) => {
86
86
  uploadData.mimetype = MIMETYPE_MAP[mediaType];
87
87
  }
88
88
  if (cacheableKey) {
89
- const mediaBuff = await options.mediaCache.get(cacheableKey);
89
+ const mediaBuff = options.mediaCache.get(cacheableKey);
90
90
  if (mediaBuff) {
91
91
  logger?.debug({ cacheableKey }, 'got media cache hit');
92
- const obj = proto.Message.decode(mediaBuff);
92
+ const obj = WAProto.Message.decode(mediaBuff);
93
93
  const key = `${mediaType}Message`;
94
94
  Object.assign(obj[key], { ...uploadData, media: undefined });
95
95
  return obj;
@@ -121,12 +121,9 @@ export const prepareWAMessageMedia = async (message, options) => {
121
121
  obj.ptvMessage = obj.videoMessage;
122
122
  delete obj.videoMessage;
123
123
  }
124
- if (obj.stickerMessage) {
125
- obj.stickerMessage.stickerSentTs = Date.now();
126
- }
127
124
  if (cacheableKey) {
128
125
  logger?.debug({ cacheableKey }, 'set cache');
129
- await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
126
+ options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
130
127
  }
131
128
  return obj;
132
129
  }
@@ -211,7 +208,7 @@ export const prepareWAMessageMedia = async (message, options) => {
211
208
  }
212
209
  if (cacheableKey) {
213
210
  logger?.debug({ cacheableKey }, 'set cache');
214
- await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
211
+ options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
215
212
  }
216
213
  return obj;
217
214
  };
@@ -493,6 +490,39 @@ export const generateWAMessageContent = async (message, options) => {
493
490
  }
494
491
  }
495
492
  }
493
+ else if ('payment' in message) {
494
+ const requestPaymentMessage = {
495
+ amount: {
496
+ currencyCode: message.payment?.currency || 'IDR',
497
+ offset: message.payment?.offset || 0,
498
+ value: message.payment?.amount || 999999999
499
+ },
500
+ expiryTimestamp: message.payment?.expiry || 0,
501
+ amount1000: message.payment?.amount || 999999999 * 1000,
502
+ currencyCodeIso4217: message.payment?.currency || 'IDR',
503
+ requestFrom: message.payment?.from || '0@s.whatsapp.net',
504
+ noteMessage: {
505
+ extendedTextMessage: {
506
+ text: message.payment?.note || 'Notes'
507
+ }
508
+ },
509
+ background: {
510
+ placeholderArgb: message.payment?.image?.placeholderArgb || 4278190080,
511
+ textArgb: message.payment?.image?.textArgb || 4294967295,
512
+ subtextArgb: message.payment?.image?.subtextArgb || 4294967295,
513
+ type: 1
514
+ }
515
+ }
516
+
517
+ requestPaymentMessage.noteMessage.extendedTextMessage.contextInfo = {
518
+ ...(message.contextInfo || {}),
519
+ ...(message.mentions ? {
520
+ mentionedJid: message.mentions
521
+ } : {})
522
+ }
523
+
524
+ m.requestPaymentMessage = requestPaymentMessage
525
+ }
496
526
  else if ('sharePhoneNumber' in message) {
497
527
  m.protocolMessage = {
498
528
  type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
@@ -748,12 +778,12 @@ export const generateWAMessageFromContent = (jid, message, options) => {
748
778
  const { quoted, userJid } = options;
749
779
  if (quoted && !isJidNewsletter(jid)) {
750
780
  const participant = quoted.key.fromMe
751
- ? userJid // TODO: Add support for LIDs
781
+ ? userJid
752
782
  : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
753
783
  let quotedMsg = normalizeMessageContent(quoted.message);
754
784
  const msgType = getContentType(quotedMsg);
755
785
  // strip any redundant properties
756
- quotedMsg = proto.Message.create({ [msgType]: quotedMsg[msgType] });
786
+ quotedMsg = proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
757
787
  const quotedContent = quotedMsg[msgType];
758
788
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
759
789
  delete quotedContent.contextInfo;
@@ -788,7 +818,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
788
818
  //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
789
819
  };
790
820
  }
791
- message = WAProto.Message.create(message);
821
+ message = WAProto.Message.fromObject(message);
792
822
  const messageJSON = {
793
823
  key: {
794
824
  remoteJid: jid,
@@ -798,7 +828,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
798
828
  message: message,
799
829
  messageTimestamp: timestamp,
800
830
  messageStubParameters: [],
801
- participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined, // TODO: Add support for LIDs
831
+ participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined,
802
832
  status: WAMessageStatus.PENDING
803
833
  };
804
834
  return WAProto.WebMessageInfo.fromObject(messageJSON);
@@ -1109,4 +1139,4 @@ export const patchMessageForMdIfRequired = (message) => {
1109
1139
  }
1110
1140
  }
1111
1141
  return message
1112
- }
1142
+ }
@@ -0,0 +1,20 @@
1
+ import { proto } from '../../WAProto/index.js';
2
+ import type { KeyPair } from '../Types/index.js';
3
+ import type { BinaryNode } from '../WABinary/index.js';
4
+ import type { ILogger } from './logger.js';
5
+ export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }: {
6
+ keyPair: KeyPair;
7
+ NOISE_HEADER: Uint8Array;
8
+ logger: ILogger;
9
+ routingInfo?: Buffer | undefined;
10
+ }) => {
11
+ encrypt: (plaintext: Uint8Array) => Buffer<ArrayBuffer>;
12
+ decrypt: (ciphertext: Uint8Array) => Buffer<ArrayBuffer>;
13
+ authenticate: (data: Uint8Array) => void;
14
+ mixIntoKey: (data: Uint8Array) => Promise<void>;
15
+ finishInit: () => Promise<void>;
16
+ processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => Promise<Buffer<ArrayBuffer>>;
17
+ encodeFrame: (data: Buffer | Uint8Array) => Buffer<ArrayBuffer>;
18
+ decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => Promise<void>;
19
+ };
20
+ //# sourceMappingURL=noise-handler.d.ts.map