@vanzxy/baileys 1.6.2 → 1.6.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.

Potentially problematic release.


This version of @vanzxy/baileys might be problematic. Click here for more details.

Files changed (51) hide show
  1. package/NOTICE.md +50 -0
  2. package/lib/Utils/A2UI.js +217 -0
  3. package/lib/Utils/MessageBuilder.js +332 -46
  4. package/lib/Utils/MessageBuilder_d.ts +45 -0
  5. package/lib/Utils/PersistentStore.js +592 -0
  6. package/lib/Utils/PersistentStore_d.ts +60 -0
  7. package/lib/Utils/anti-delete.d.ts +68 -0
  8. package/lib/Utils/anti-delete.js +185 -0
  9. package/lib/Utils/auto-reply.d.ts +47 -0
  10. package/lib/Utils/auto-reply.js +155 -0
  11. package/lib/Utils/button-helper-utils.js +314 -0
  12. package/lib/Utils/button-sender.js +817 -0
  13. package/lib/Utils/chat-history-helpers.d.ts +21 -0
  14. package/lib/Utils/chat-history-helpers.js +71 -0
  15. package/lib/Utils/index.d.ts +11 -0
  16. package/lib/Utils/index.js +16 -0
  17. package/lib/Utils/media-messages.d.ts +18 -0
  18. package/lib/Utils/media-messages.js +71 -0
  19. package/lib/Utils/media-set.d.ts +13 -0
  20. package/lib/Utils/media-set.js +165 -0
  21. package/lib/Utils/message-kind.js +139 -0
  22. package/lib/Utils/message-search.d.ts +44 -0
  23. package/lib/Utils/message-search.js +174 -0
  24. package/lib/Utils/scheduling.d.ts +42 -0
  25. package/lib/Utils/scheduling.js +140 -0
  26. package/lib/Utils/status.d.ts +50 -0
  27. package/lib/Utils/status.js +108 -0
  28. package/lib/Utils/stickerpack.d.ts +51 -0
  29. package/lib/Utils/stickerpack.js +276 -0
  30. package/lib/Utils/templates.d.ts +76 -0
  31. package/lib/Utils/templates.js +151 -0
  32. package/lib/Utils/use-sqlite-auth-state.js +28 -1
  33. package/lib/Utils/vcard.d.ts +58 -0
  34. package/lib/Utils/vcard.js +94 -0
  35. package/lib/VoIP/audio-feeder.d.ts +15 -0
  36. package/lib/VoIP/audio-feeder.js +132 -0
  37. package/lib/VoIP/index.js +277 -0
  38. package/lib/VoIP/relay-transport.d.ts +43 -0
  39. package/lib/VoIP/relay-transport.js +559 -0
  40. package/lib/VoIP/signaling.js +624 -0
  41. package/lib/VoIP/types.d.ts +69 -0
  42. package/lib/VoIP/types.js +17 -0
  43. package/lib/VoIP/wasm-engine.d.ts +103 -0
  44. package/lib/VoIP/wasm-engine.js +1214 -0
  45. package/lib/VoIP/worker-bootstrap.js +1042 -0
  46. package/lib/WABinary/generic-utils.js +8 -0
  47. package/lib/assets/wasm/loader.js +5 -0
  48. package/lib/assets/wasm/whatsapp.wasm +0 -0
  49. package/lib/assets/wasm/worker-modules.js +273 -0
  50. package/lib/index.js +4 -0
  51. package/package.json +22 -1
@@ -0,0 +1,1214 @@
1
+ var _a;
2
+ /**
3
+ * WhatsApp VoIP WASM engine.
4
+ *
5
+ * Loads the WhatsApp Web VoIP WASM stack inside a Node.js `vm.Context`,
6
+ * spawns a 20-thread `worker_threads` pool to mirror the browser's pthread
7
+ * model, and exposes a callback-based JS bridge. Audio-only (no video).
8
+ *
9
+ * @author ShellTear
10
+ */
11
+ import * as vm from "node:vm";
12
+ import * as fs from "node:fs";
13
+ import * as path from "node:path";
14
+ import { randomFillSync } from "node:crypto";
15
+ import { Worker } from "node:worker_threads";
16
+ import { fileURLToPath } from "node:url";
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.dirname(__filename);
19
+ const CALL_WASM_AB_PROPS_JSON = process.env.CALL_WASM_AB_PROPS_JSON ?? "";
20
+ const PTHREAD_POOL_SIZE = 20;
21
+ const VOIP_READY_TIMEOUT_MS = 15_000;
22
+ const parseJsonObjectEnv = (raw) => {
23
+ if (!raw)
24
+ return {};
25
+ try {
26
+ const parsed = JSON.parse(raw);
27
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
28
+ return parsed;
29
+ }
30
+ catch { }
31
+ return {};
32
+ };
33
+ const toByteArray = (input) => {
34
+ if (!input)
35
+ return new Uint8Array(0);
36
+ if (input instanceof Uint8Array)
37
+ return input;
38
+ if (typeof input === "string")
39
+ return new TextEncoder().encode(input);
40
+ if (ArrayBuffer.isView(input))
41
+ return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
42
+ if (input instanceof ArrayBuffer)
43
+ return new Uint8Array(input);
44
+ if (typeof input === "object" && typeof input.length === "number") {
45
+ const arr = new Uint8Array(input.length);
46
+ for (let i = 0; i < input.length; i += 1)
47
+ arr[i] = input[i] ?? 0;
48
+ return arr;
49
+ }
50
+ return new Uint8Array(0);
51
+ };
52
+ const filterWorkerStderr = (chunk) => {
53
+ const line = chunk.toString().trim();
54
+ if (line && !line.startsWith("voip:") && !line.startsWith("still waiting")) {
55
+ process.stderr.write(chunk);
56
+ }
57
+ };
58
+ const resolveWorkerScriptPath = () => {
59
+ const compiled = path.join(__dirname, "worker-bootstrap.js");
60
+ return fs.existsSync(compiled) ? compiled : path.join(__dirname, "worker-bootstrap.mts");
61
+ };
62
+ class NodeWorkerMessagePort {
63
+ #listeners = new Map();
64
+ #worker;
65
+ fullyConnected;
66
+ name;
67
+ workerID = 0;
68
+ pthread_ptr = 0;
69
+ constructor(worker, name = "WAWebVoipWebWasmWorker") {
70
+ this.#worker = worker;
71
+ this.name = name;
72
+ this.fullyConnected = new Promise((resolve) => {
73
+ const loadedHandler = (msg) => {
74
+ if (msg && msg.cmd === "loaded") {
75
+ this.workerID = msg.workerID ?? 0;
76
+ resolve(this);
77
+ }
78
+ };
79
+ this.addMessageListener("cmd", loadedHandler);
80
+ });
81
+ if (typeof worker.on === "function") {
82
+ worker.on("message", (data) => this.#handleMessage(data));
83
+ worker.on("error", () => { });
84
+ }
85
+ else if (typeof worker.addEventListener === "function") {
86
+ worker.addEventListener("message", (ev) => this.#handleMessage(ev?.data ?? ev));
87
+ }
88
+ }
89
+ postMessage = (msg, transferList) => {
90
+ const out = msg && typeof msg === "object" && msg.cmd && !msg.type ? { ...msg, type: "cmd" } : msg;
91
+ this.#worker.postMessage(out, transferList);
92
+ };
93
+ addMessageListener = (type, handler) => {
94
+ let set = this.#listeners.get(type);
95
+ if (!set) {
96
+ set = new Set();
97
+ this.#listeners.set(type, set);
98
+ }
99
+ set.add(handler);
100
+ return handler;
101
+ };
102
+ removeMessageListener = (type, handler) => this.#listeners.get(type)?.delete(handler) ?? false;
103
+ removeAllMessageListeners = (type) => {
104
+ if (type)
105
+ this.#listeners.get(type)?.clear();
106
+ else
107
+ this.#listeners.clear();
108
+ };
109
+ terminate = () => { this.#worker.terminate(); };
110
+ close = () => { };
111
+ isWrappingVirtualMessagePort = () => false;
112
+ getWorker = () => this.#worker;
113
+ #handleMessage = (data) => {
114
+ if (!data || typeof data !== "object")
115
+ return;
116
+ if (data.type === "callback" || data.type === "waWasmWorkerCompatibleCallback") {
117
+ let callbackName;
118
+ let callbackArgs;
119
+ if (data.__name) {
120
+ callbackName = data.__name;
121
+ callbackArgs = {};
122
+ for (const key in data) {
123
+ if (key !== "type" && key !== "__name" && key !== "prototype" && key !== "args" && !key.startsWith("__")) {
124
+ callbackArgs[key] = data[key];
125
+ }
126
+ }
127
+ }
128
+ else if (data.name) {
129
+ callbackName = data.name;
130
+ callbackArgs = data.args ?? {};
131
+ }
132
+ else if (data.payload?.name) {
133
+ callbackName = data.payload.name;
134
+ callbackArgs = data.payload.args ?? {};
135
+ }
136
+ else {
137
+ return;
138
+ }
139
+ if (callbackName === "onSignalingXmpp" &&
140
+ (!callbackArgs || Object.keys(callbackArgs).length === 0)) {
141
+ callbackArgs = {
142
+ peerJid: data.peerJid, callId: data.callId, xmlPayload: data.xmlPayload,
143
+ };
144
+ }
145
+ let listenerData = callbackArgs;
146
+ if (!callbackArgs || Object.keys(callbackArgs).length === 0 ||
147
+ (Object.keys(callbackArgs).length === 1 && callbackArgs.prototype)) {
148
+ listenerData = {};
149
+ for (const key in data) {
150
+ if (key !== "type" && key !== "__name" && key !== "prototype" && key !== "args" && !key.startsWith("__")) {
151
+ listenerData[key] = data[key];
152
+ }
153
+ }
154
+ }
155
+ else if (callbackName === "sendDataToRelay") {
156
+ listenerData = { ...callbackArgs };
157
+ if (data.data !== undefined)
158
+ listenerData.data = data.data;
159
+ if (data.len !== undefined)
160
+ listenerData.len = data.len;
161
+ if (data.ip !== undefined)
162
+ listenerData.ip = data.ip;
163
+ if (data.port !== undefined)
164
+ listenerData.port = data.port;
165
+ }
166
+ else if (callbackName === "onCallEvent") {
167
+ listenerData = { ...callbackArgs };
168
+ if (data.eventType !== undefined)
169
+ listenerData.eventType = data.eventType;
170
+ if (data.userData !== undefined)
171
+ listenerData.userData = data.userData;
172
+ if (data.eventDataJson !== undefined)
173
+ listenerData.eventDataJson = data.eventDataJson;
174
+ }
175
+ WasmEngine.notifyGlobalCallbackListeners(callbackName, listenerData);
176
+ return;
177
+ }
178
+ const dispatch = (key) => {
179
+ if (!key)
180
+ return;
181
+ for (const handler of this.#listeners.get(key) ?? []) {
182
+ try {
183
+ handler(data);
184
+ }
185
+ catch { }
186
+ }
187
+ };
188
+ dispatch(data.type);
189
+ if (data.cmd !== data.type)
190
+ dispatch(data.cmd);
191
+ };
192
+ }
193
+ export class WasmEngine {
194
+ static #globalCallbackListeners = new Map();
195
+ static #globalCallbacksRegistered = false;
196
+ static registerGlobalCallbackListener = (callbackName, handler) => {
197
+ const key = `callback:${callbackName}`;
198
+ let set = _a.#globalCallbackListeners.get(key);
199
+ if (!set) {
200
+ set = new Set();
201
+ _a.#globalCallbackListeners.set(key, set);
202
+ }
203
+ set.add(handler);
204
+ };
205
+ static notifyGlobalCallbackListeners = (callbackName, data) => {
206
+ const set = _a.#globalCallbackListeners.get(`callback:${callbackName}`);
207
+ if (!set)
208
+ return;
209
+ for (const handler of set) {
210
+ try {
211
+ handler(data);
212
+ }
213
+ catch { }
214
+ }
215
+ };
216
+ #config;
217
+ #instance = null;
218
+ #initialized = false;
219
+ #moduleRegistry = new Map();
220
+ #vmContext = null;
221
+ #unusedWorkers = [];
222
+ #runningWorkers = [];
223
+ #pthreads = {};
224
+ #nextWorkerID = 1;
225
+ #wasmModule = null;
226
+ #wasmMemory = null;
227
+ #removeRunDependencyCallback = null;
228
+ #workersLoadedCount = 0;
229
+ #audioPlaybackLoopInterval = null;
230
+ #audioPlaybackBuffer = null;
231
+ #isPlaybackActive = false;
232
+ #voipStackInitialized = false;
233
+ #voipStackInitPromise = null;
234
+ #voipReadyResolver = null;
235
+ #voipReadyPromise = null;
236
+ #workerModulesCode = "";
237
+ #loaderCode = "";
238
+ constructor(config = {}) {
239
+ const basePath = config.resourcesPath
240
+ ? (path.isAbsolute(config.resourcesPath) ? config.resourcesPath : path.resolve(process.cwd(), config.resourcesPath))
241
+ : path.resolve(__dirname, "..");
242
+ const wasmPath = config.wasmPath
243
+ ? (path.isAbsolute(config.wasmPath) ? config.wasmPath : path.resolve(process.cwd(), config.wasmPath))
244
+ : path.join(basePath, "assets", "wasm", "whatsapp.wasm");
245
+ this.#config = {
246
+ ...config,
247
+ wasmPath,
248
+ resourcesPath: basePath,
249
+ enableLogs: config.enableLogs ?? true,
250
+ options: {
251
+ heartbeatInterval: 30,
252
+ lobbyTimeout: 1,
253
+ maxParticipantsScreenShare: 32,
254
+ maxGroupSizeLongRingtone: 32,
255
+ ...config.options,
256
+ },
257
+ };
258
+ }
259
+ initialize = async () => {
260
+ if (this.#initialized)
261
+ throw new Error("WasmEngine already initialized");
262
+ const voipStorageDir = "/tmp/voip";
263
+ try {
264
+ if (!fs.existsSync(voipStorageDir))
265
+ fs.mkdirSync(voipStorageDir, { recursive: true });
266
+ }
267
+ catch { }
268
+ const loaderFile = path.join(this.#config.resourcesPath, "assets", "wasm", "loader.js");
269
+ const workerFile = path.join(this.#config.resourcesPath, "assets", "wasm", "worker-modules.js");
270
+ if (!this.#config.wasmBinary && !fs.existsSync(this.#config.wasmPath)) {
271
+ throw new Error(`WASM file not found: ${this.#config.wasmPath}`);
272
+ }
273
+ const wasmBuffer = this.#config.wasmBinary
274
+ ? Buffer.from(this.#config.wasmBinary)
275
+ : fs.readFileSync(this.#config.wasmPath);
276
+ const diskWorkerCode = fs.existsSync(workerFile) ? fs.readFileSync(workerFile, "utf8") : "";
277
+ this.#workerModulesCode = this.#config.workerModulesCode ?? diskWorkerCode;
278
+ const workerBundleHasLoader = typeof this.#workerModulesCode === "string" && /WAWebVoipWebWasmLoader/.test(this.#workerModulesCode);
279
+ // Skip the on-disk loader.js if the worker bundle already has a loader —
280
+ // the standalone loader.js is older and would clobber the freshly fetched
281
+ // bindings inside worker-modules.js.
282
+ this.#loaderCode = this.#config.loaderCode ??
283
+ (workerBundleHasLoader ? "" : fs.existsSync(loaderFile) ? fs.readFileSync(loaderFile, "utf8") : "");
284
+ if (!this.#loaderCode && !this.#workerModulesCode) {
285
+ throw new Error("No loader/worker code available to initialize VoIP");
286
+ }
287
+ const memory = new WebAssembly.Memory({ initial: 256, maximum: 32768, shared: true });
288
+ this.#wasmMemory = memory;
289
+ this.#wasmModule = await WebAssembly.compile(wasmBuffer);
290
+ this.#vmContext = this.#createVMContext(memory);
291
+ const runModuleCode = (code) => { if (code)
292
+ vm.runInContext(code, this.#vmContext); };
293
+ runModuleCode(this.#workerModulesCode);
294
+ runModuleCode(this.#loaderCode);
295
+ this.#vmContext.WAWebVoipWebWasmWorkerResource = this.#requireModule("WAWebVoipWebWasmWorkerResource");
296
+ const loaderModuleNames = [
297
+ this.#config.loaderModuleName,
298
+ "WAWebVoipWebWasmLoader",
299
+ "WAWebVoipWebWasmLoader.worker",
300
+ "WAWebVoipWebWasmLoader_ProdLab_internal.worker",
301
+ "WAWebVoipWebWasmLoader_ProdLabvideo_internal.worker",
302
+ ].filter((v, i, a) => !!v && a.indexOf(v) === i);
303
+ let wasmLoader = null;
304
+ for (const moduleName of loaderModuleNames) {
305
+ const candidate = this.#requireModule(moduleName);
306
+ if (typeof candidate === "function") {
307
+ wasmLoader = candidate;
308
+ break;
309
+ }
310
+ if (typeof candidate?.default === "function") {
311
+ wasmLoader = candidate.default;
312
+ break;
313
+ }
314
+ }
315
+ if (typeof wasmLoader !== "function") {
316
+ throw new Error(`No compatible WASM loader found. Tried: ${loaderModuleNames.join(", ")}`);
317
+ }
318
+ if (!_a.#globalCallbacksRegistered)
319
+ this.#registerGlobalCallbacks();
320
+ await this.#initPThreadPool();
321
+ const workersLoadingPromise = this.#loadWasmModuleToAllWorkers();
322
+ const readyPromise = wasmLoader({
323
+ wasmBinary: wasmBuffer,
324
+ wasmMemory: memory,
325
+ locateFile: () => this.#config.wasmPath,
326
+ onRuntimeInitialized: () => { },
327
+ });
328
+ const [instance] = await Promise.all([readyPromise, workersLoadingPromise]);
329
+ this.#instance = instance;
330
+ this.#initialized = true;
331
+ };
332
+ isInitialized = () => this.#initialized;
333
+ destroy = () => {
334
+ this.#stopAudioPlaybackLoop();
335
+ if (this.#instance && typeof this.#instance.endCall === "function") {
336
+ try {
337
+ this.#instance.endCall(0, false);
338
+ }
339
+ catch { }
340
+ }
341
+ for (const worker of [...this.#runningWorkers, ...this.#unusedWorkers]) {
342
+ try {
343
+ worker.terminate();
344
+ }
345
+ catch { }
346
+ }
347
+ this.#runningWorkers = [];
348
+ this.#unusedWorkers = [];
349
+ this.#instance = null;
350
+ this.#vmContext = null;
351
+ this.#moduleRegistry.clear();
352
+ this.#wasmModule = null;
353
+ this.#wasmMemory = null;
354
+ this.#initialized = false;
355
+ };
356
+ initVoipStack = (selfJid, meUserJid, selfLid) => {
357
+ this.#ensureInitialized();
358
+ if (this.#voipStackInitialized || this.#voipStackInitPromise)
359
+ return;
360
+ this.#voipStackInitPromise = new Promise((resolveInit) => {
361
+ this.#voipReadyPromise = new Promise((readyResolve) => {
362
+ this.#voipReadyResolver = () => {
363
+ this.#voipStackInitialized = true;
364
+ this.#voipReadyResolver = null;
365
+ this.#voipReadyPromise = null;
366
+ readyResolve();
367
+ };
368
+ });
369
+ try {
370
+ this.#applyDefaultAbProps();
371
+ try {
372
+ this.#instance.initVoipStack(selfJid, meUserJid, selfLid);
373
+ }
374
+ catch (modernErr) {
375
+ if (modernErr?.name === "BindingError" &&
376
+ (String(modernErr?.message ?? "").includes("expected 8 args") ||
377
+ String(modernErr?.message ?? "").includes("takes 8"))) {
378
+ this.#instance.initVoipStack(selfJid, meUserJid, selfLid, true, 5, 0, 8, 16);
379
+ }
380
+ else {
381
+ throw modernErr;
382
+ }
383
+ }
384
+ Promise.race([
385
+ this.#voipReadyPromise,
386
+ new Promise((r) => setTimeout(() => {
387
+ this.#voipStackInitialized = true;
388
+ r();
389
+ }, VOIP_READY_TIMEOUT_MS)),
390
+ ]).finally(() => {
391
+ this.#voipStackInitPromise = null;
392
+ resolveInit();
393
+ });
394
+ }
395
+ catch {
396
+ this.#voipReadyResolver = null;
397
+ this.#voipReadyPromise = null;
398
+ this.#voipStackInitPromise = null;
399
+ resolveInit();
400
+ }
401
+ });
402
+ };
403
+ waitForVoipStackReady = async () => {
404
+ if (this.#voipStackInitialized)
405
+ return;
406
+ if (this.#voipStackInitPromise) {
407
+ await this.#voipStackInitPromise;
408
+ }
409
+ else {
410
+ await new Promise((r) => setTimeout(r, 100));
411
+ }
412
+ };
413
+ isVoipStackReady = () => this.#voipStackInitialized;
414
+ startCall = (options) => {
415
+ this.#ensureInitialized();
416
+ const peers = this.#makeStringList(options.peerList ?? [options.peerJid]);
417
+ const tcToken = this.#createUint8List(options.extraData);
418
+ const isLidCall = options.isLidCall ?? options.peerJid.includes("@lid");
419
+ const isFromDialer = options.isFromDialer ?? false;
420
+ const peerJid = String(options.peerJid);
421
+ try {
422
+ try {
423
+ return this.#instance.startVoipCall(peerJid, peers, options.callId, options.isVideo, options.peerPn, isLidCall, isFromDialer, tcToken);
424
+ }
425
+ catch (error) {
426
+ if (error?.name !== "BindingError")
427
+ throw error;
428
+ return this.#instance.startVoipCall(peerJid, peers, options.callId, options.isVideo, options.peerPn, isFromDialer, tcToken);
429
+ }
430
+ }
431
+ finally {
432
+ peers?.delete?.();
433
+ tcToken?.delete?.();
434
+ }
435
+ };
436
+ endCall = (reason = 0, sendTerminate = true) => {
437
+ this.#ensureInitialized();
438
+ this.#instance.endCall(reason, sendTerminate);
439
+ };
440
+ setMute = (muted) => {
441
+ this.#ensureInitialized();
442
+ return this.#instance.setCallMute(muted);
443
+ };
444
+ updateNetworkMedium = (networkMedium, networkMtu = 0) => {
445
+ this.#ensureInitialized();
446
+ this.#instance.updateNetworkMedium?.(networkMedium, networkMtu);
447
+ };
448
+ handleSignalingOffer = (msg) => {
449
+ this.#ensureInitialized();
450
+ const tcTokenList = this.#createUint8List(msg.tcToken);
451
+ try {
452
+ this.#instance.handleIncomingSignalingOffer(msg.payload, String(msg.peerPlatform ?? 0), String(msg.peerAppVersion ?? "0"), String(msg.epochId ?? "0"), String(msg.timestamp ?? "0"), msg.isOffline ?? false, msg.isOfferNotContact ?? false, String(msg.peerJid), tcTokenList);
453
+ }
454
+ finally {
455
+ tcTokenList?.delete?.();
456
+ }
457
+ };
458
+ handleSignalingMessage = (msg) => {
459
+ this.#ensureInitialized();
460
+ const tcTokenList = this.#createUint8List(msg.tcToken);
461
+ try {
462
+ this.#instance.handleIncomingSignalingMessage(msg.payload, String(msg.peerPlatform ?? "0"), String(msg.peerAppVersion ?? "0"), String(msg.epochId ?? "0"), String(msg.timestamp ?? "0"), msg.isOffline ?? false, String(msg.peerJid), tcTokenList);
463
+ }
464
+ finally {
465
+ tcTokenList?.delete?.();
466
+ }
467
+ };
468
+ handleSignalingAck = (msg) => {
469
+ this.#ensureInitialized();
470
+ const options = this.#createUint8List(msg.extraData);
471
+ try {
472
+ this.#instance.handleIncomingSignalingAck(msg.payload, String(msg.ackError ?? "0"), String(msg.msgType ?? ""), msg.peerJid ?? "", options);
473
+ }
474
+ finally {
475
+ options?.delete?.();
476
+ }
477
+ };
478
+ handleSignalingReceipt = (msg) => {
479
+ this.#ensureInitialized();
480
+ const tcTokenList = this.#createUint8List(msg.tcToken);
481
+ try {
482
+ this.#instance.handleIncomingSignalingReceipt?.(msg.payload, msg.peerJid, tcTokenList);
483
+ }
484
+ finally {
485
+ tcTokenList?.delete?.();
486
+ }
487
+ };
488
+ handleOnTransportMessage = (data, ip, port) => {
489
+ this.#ensureInitialized();
490
+ if (typeof this.#instance.handleOnMessageFromHeap === "function") {
491
+ const ptr = this.malloc(data.byteLength);
492
+ if (!ptr)
493
+ return;
494
+ try {
495
+ const heapU8 = this.#instance.GROWABLE_HEAP_U8?.() ?? this.#instance.HEAPU8;
496
+ if (!heapU8)
497
+ return;
498
+ heapU8.set(data, ptr);
499
+ this.#instance.handleOnMessageFromHeap(ptr, data.byteLength, ip, port);
500
+ }
501
+ finally {
502
+ this.free(ptr);
503
+ }
504
+ return;
505
+ }
506
+ if (typeof this.#instance.handleOnMessage !== "function")
507
+ return;
508
+ const dataList = this.#createUint8List(data);
509
+ try {
510
+ this.#instance.handleOnMessage(dataList, ip, port);
511
+ }
512
+ finally {
513
+ dataList?.delete?.();
514
+ }
515
+ };
516
+ updateIceRtt = (rttMs, relayIp, relayPort) => {
517
+ this.#ensureInitialized();
518
+ this.#instance.updateIceRtt?.(rttMs, relayIp, relayPort);
519
+ };
520
+ sendAudioData = (data, ptr) => {
521
+ this.#ensureInitialized();
522
+ if (!data || data.length === 0 || !ptr)
523
+ return;
524
+ if (typeof this.#instance.onAudioDataFromJs !== "function")
525
+ return;
526
+ try {
527
+ const heapF32 = this.#instance.GROWABLE_HEAP_F32?.();
528
+ if (!heapF32)
529
+ return;
530
+ const index = Math.floor(ptr / 4);
531
+ if (index < 0 || index + data.length > heapF32.length)
532
+ return;
533
+ heapF32.set(data, index);
534
+ this.#instance.onAudioDataFromJs(ptr, data.length);
535
+ }
536
+ catch { }
537
+ };
538
+ malloc = (size) => {
539
+ this.#ensureInitialized();
540
+ return this.#instance._malloc(size);
541
+ };
542
+ free = (ptr) => {
543
+ this.#ensureInitialized();
544
+ this.#instance._free(ptr);
545
+ };
546
+ // ─── private ──────────────────────────────────────────────────────────────
547
+ #ensureInitialized = () => {
548
+ if (!this.#initialized || !this.#instance) {
549
+ throw new Error("WasmEngine not initialized. Call initialize() first.");
550
+ }
551
+ };
552
+ #makeStringList = (arr) => {
553
+ const list = new this.#instance.StringList();
554
+ for (const v of arr)
555
+ list.push_back(v);
556
+ return list;
557
+ };
558
+ #createUint8List = (data) => {
559
+ if (!this.#instance?.Uint8List)
560
+ return null;
561
+ const list = new this.#instance.Uint8List();
562
+ if (data)
563
+ data.forEach((byte) => list.push_back(byte));
564
+ return list;
565
+ };
566
+ #startAudioPlaybackLoop = () => {
567
+ if (this.#audioPlaybackLoopInterval)
568
+ return;
569
+ this.#ensureInitialized();
570
+ this.#isPlaybackActive = true;
571
+ if (typeof this.#instance.requestAudioDataFromWasmVoip !== "function")
572
+ return;
573
+ const framesPerChunk = 320;
574
+ const bufferSize = framesPerChunk * 4;
575
+ try {
576
+ const _malloc = this.#instance._malloc ?? this.#instance.malloc;
577
+ if (!_malloc)
578
+ return;
579
+ this.#audioPlaybackBuffer = _malloc(bufferSize);
580
+ }
581
+ catch {
582
+ return;
583
+ }
584
+ if (!this.#audioPlaybackBuffer || this.#audioPlaybackBuffer <= 0)
585
+ return;
586
+ this.#audioPlaybackLoopInterval = setInterval(() => {
587
+ if (!this.#isPlaybackActive || !this.#instance || !this.#initialized) {
588
+ this.#stopAudioPlaybackLoop();
589
+ return;
590
+ }
591
+ try {
592
+ this.#instance.requestAudioDataFromWasmVoip(this.#audioPlaybackBuffer, bufferSize);
593
+ const heapF32 = this.#instance.GROWABLE_HEAP_F32?.();
594
+ if (!heapF32)
595
+ return;
596
+ const index = Math.floor(this.#audioPlaybackBuffer / 4);
597
+ const numFloats = Math.floor(bufferSize / 4);
598
+ if (index < 0 || index + numFloats > heapF32.length)
599
+ return;
600
+ const audioData = new Float32Array(heapF32.buffer, heapF32.byteOffset + index * 4, numFloats);
601
+ const hasNonZero = audioData.some((s) => Math.abs(s) > 0.0001);
602
+ if (hasNonZero)
603
+ this.#config.callbacks?.onAudioPlaybackData?.(audioData);
604
+ }
605
+ catch { }
606
+ }, 16);
607
+ };
608
+ #stopAudioPlaybackLoop = () => {
609
+ this.#isPlaybackActive = false;
610
+ if (this.#audioPlaybackLoopInterval) {
611
+ clearInterval(this.#audioPlaybackLoopInterval);
612
+ this.#audioPlaybackLoopInterval = null;
613
+ }
614
+ if (this.#audioPlaybackBuffer && this.#audioPlaybackBuffer > 0) {
615
+ try {
616
+ this.#instance?._free?.(this.#audioPlaybackBuffer);
617
+ }
618
+ catch { }
619
+ this.#audioPlaybackBuffer = null;
620
+ }
621
+ };
622
+ #applyDefaultAbProps = () => {
623
+ if (!this.#instance)
624
+ return;
625
+ const setInt = typeof this.#instance.setABPropInt === "function"
626
+ ? (k, v) => { this.#instance.setABPropInt(k, v); }
627
+ : null;
628
+ const setBool = typeof this.#instance.setABPropBool === "function"
629
+ ? (k, v) => { this.#instance.setABPropBool(k, v); }
630
+ : null;
631
+ const setString = typeof this.#instance.setABPropString === "function"
632
+ ? (k, v) => { this.#instance.setABPropString(k, v); }
633
+ : null;
634
+ if (!setInt && !setBool && !setString)
635
+ return;
636
+ const opts = this.#config.options ?? {};
637
+ const intProps = {
638
+ heartbeat_interval_s: opts.heartbeatInterval ?? 30,
639
+ lobby_timeout_min: opts.lobbyTimeout ?? 1,
640
+ max_num_participants_for_ss: opts.maxParticipantsScreenShare ?? 32,
641
+ max_group_size_for_long_ringtone: opts.maxGroupSizeLongRingtone ?? 32,
642
+ app_exit_reason_version: 1,
643
+ log_level: opts.logLevel ?? 3,
644
+ calling_rust_migration_bitmap: 0,
645
+ calling_rust_migration_incoming_stanza_bitmap: 0,
646
+ default_endpoint_thread_poll_timeout: 0,
647
+ aigc_version: 0,
648
+ call_admin_version: 0,
649
+ vid_stream_pause_resume_jb_reset_threshold_ms: 0,
650
+ // Opus: max bandwidth WB (16 kHz). FB (48 kHz) needs native audio device
651
+ // hooks not available in this JS-only WASM context.
652
+ opus_max_bandwidth: 1103, // OPUS_BANDWIDTH_WIDEBAND
653
+ };
654
+ const boolProps = {
655
+ enable_av_downgrade: false,
656
+ enable_new_user_action_stanza_for_raise_hand_sender: false,
657
+ enable_webcodec_video_encode: false,
658
+ enable_init_bwe_for_group_call: false,
659
+ enable_ring_for_gc_on_offer_expire: false,
660
+ allow_reporting_call_replayer_id: false,
661
+ enable_offer_v2_upgrade: false,
662
+ enable_silent_offer: false,
663
+ voice_ai_conversation_starter_latency_tracking: false,
664
+ enable_waiting_room_logging: false,
665
+ attach_transport_rtx: false,
666
+ ignore_joinable_terminate_on_expired_offer: false,
667
+ enable_passthrough_video_decoder: false,
668
+ };
669
+ for (const [key, value] of Object.entries(intProps)) {
670
+ if (setInt && Number.isFinite(value))
671
+ try {
672
+ setInt(key, value);
673
+ }
674
+ catch { }
675
+ }
676
+ for (const [key, value] of Object.entries(boolProps)) {
677
+ if (setBool)
678
+ try {
679
+ setBool(key, value);
680
+ }
681
+ catch { }
682
+ }
683
+ const overrideProps = parseJsonObjectEnv(CALL_WASM_AB_PROPS_JSON);
684
+ for (const [key, value] of Object.entries(overrideProps)) {
685
+ try {
686
+ if (typeof value === "boolean" && setBool)
687
+ setBool(key, value);
688
+ else if (typeof value === "number" && setInt)
689
+ setInt(key, value);
690
+ else if (typeof value === "string" && setString)
691
+ setString(key, value);
692
+ }
693
+ catch { }
694
+ }
695
+ };
696
+ #allocateUnusedWorker = () => {
697
+ const workerScriptPath = resolveWorkerScriptPath();
698
+ if (!fs.existsSync(workerScriptPath))
699
+ return;
700
+ try {
701
+ const worker = new Worker(workerScriptPath, {
702
+ stdout: true, stderr: true,
703
+ workerData: {
704
+ wasmPath: this.#config.wasmPath,
705
+ wasmBinary: this.#config.wasmBinary,
706
+ workerModulesCode: this.#workerModulesCode,
707
+ loaderCode: this.#loaderCode,
708
+ loaderModuleName: this.#config.loaderModuleName,
709
+ resourcesPath: this.#config.resourcesPath,
710
+ enableLogs: this.#config.enableLogs,
711
+ },
712
+ });
713
+ const port = new NodeWorkerMessagePort(worker, "WAWebVoipWebWasmWorker");
714
+ worker.stdout?.on("data", () => { }); // suppress noisy worker stdout
715
+ worker.stderr?.on("data", filterWorkerStderr);
716
+ this.#unusedWorkers.push(port);
717
+ }
718
+ catch { }
719
+ };
720
+ #initPThreadPool = async () => {
721
+ for (let i = 0; i < PTHREAD_POOL_SIZE; i += 1)
722
+ this.#allocateUnusedWorker();
723
+ };
724
+ #loadWasmModuleToWorker = (worker) => new Promise((resolve) => {
725
+ const loadedHandler = (msg) => {
726
+ if (msg && msg.cmd === "loaded") {
727
+ worker.removeMessageListener("cmd", loadedHandler);
728
+ this.#workersLoadedCount += 1;
729
+ if (this.#workersLoadedCount >= PTHREAD_POOL_SIZE && this.#removeRunDependencyCallback) {
730
+ this.#removeRunDependencyCallback("loading-workers");
731
+ }
732
+ resolve();
733
+ }
734
+ };
735
+ worker.addMessageListener("cmd", loadedHandler);
736
+ worker.workerID = this.#nextWorkerID++;
737
+ worker.postMessage({
738
+ cmd: "load", type: "cmd",
739
+ wasmMemory: this.#wasmMemory,
740
+ wasmModule: this.#wasmModule,
741
+ workerID: worker.workerID,
742
+ handlers: [],
743
+ });
744
+ });
745
+ #loadWasmModuleToAllWorkers = async () => {
746
+ this.#workersLoadedCount = 0;
747
+ await Promise.all(this.#unusedWorkers.map((w) => this.#loadWasmModuleToWorker(w)));
748
+ };
749
+ #registerGlobalCallbacks = () => {
750
+ const callbacks = this.#config.callbacks ?? {};
751
+ _a.registerGlobalCallbackListener("loggingCallback", (data) => {
752
+ if (!this.#config.enableLogs)
753
+ return;
754
+ const level = data?.level;
755
+ const msg = data?.message ?? "";
756
+ const mapped = level === 1 ? "error" : level === 2 ? "warn" : level === 3 ? "log" : "debug";
757
+ callbacks.onLog?.(mapped, msg);
758
+ });
759
+ if (callbacks.onAudioCaptureInit) {
760
+ _a.registerGlobalCallbackListener("initCaptureDriverJS", (data) => {
761
+ callbacks.onAudioCaptureInit({
762
+ sampleRate: data?.sample_rate ?? data?.sampleRate,
763
+ channels: data?.channels,
764
+ bitsPerSample: data?.bits_per_sample ?? data?.bitsPerSample,
765
+ framesPerChunk: data?.frames_per_chunk ?? data?.framesPerChunk,
766
+ });
767
+ });
768
+ }
769
+ _a.registerGlobalCallbackListener("startCaptureJS", () => callbacks.onAudioCaptureStart?.());
770
+ _a.registerGlobalCallbackListener("stopCaptureJS", () => callbacks.onAudioCaptureStop?.());
771
+ if (callbacks.onAudioPlaybackInit) {
772
+ _a.registerGlobalCallbackListener("initPlaybackDriverJS", (data) => {
773
+ callbacks.onAudioPlaybackInit({
774
+ sampleRate: data?.sample_rate ?? data?.sampleRate,
775
+ channels: data?.channels,
776
+ bitsPerSample: data?.bits_per_sample ?? data?.bitsPerSample,
777
+ framesPerChunk: data?.frames_per_chunk ?? data?.framesPerChunk,
778
+ });
779
+ });
780
+ }
781
+ _a.registerGlobalCallbackListener("startPlaybackJS", () => {
782
+ callbacks.onAudioPlaybackStart?.();
783
+ this.#startAudioPlaybackLoop();
784
+ });
785
+ _a.registerGlobalCallbackListener("stopPlaybackJS", () => {
786
+ this.#stopAudioPlaybackLoop();
787
+ callbacks.onAudioPlaybackStop?.();
788
+ });
789
+ if (callbacks.onSignalingXmpp) {
790
+ _a.registerGlobalCallbackListener("onSignalingXmpp", (data) => {
791
+ const peerJid = data.peerJid ?? data.args?.peerJid;
792
+ const callId = data.callId ?? data.args?.callId;
793
+ let xmlPayload = data.xmlPayload ?? data.args?.xmlPayload;
794
+ if (Array.isArray(xmlPayload))
795
+ xmlPayload = new Uint8Array(xmlPayload);
796
+ else if (xmlPayload && typeof xmlPayload === "object" &&
797
+ !(xmlPayload instanceof Uint8Array) && !Buffer.isBuffer(xmlPayload)) {
798
+ xmlPayload = new Uint8Array(xmlPayload);
799
+ }
800
+ callbacks.onSignalingXmpp(peerJid, callId, xmlPayload);
801
+ });
802
+ }
803
+ if (callbacks.onCallEvent) {
804
+ _a.registerGlobalCallbackListener("onCallEvent", (data) => {
805
+ callbacks.onCallEvent(data.eventType, data.eventDataJson);
806
+ });
807
+ }
808
+ if (callbacks.sendDataToRelay) {
809
+ _a.registerGlobalCallbackListener("sendDataToRelay", (data) => {
810
+ let relayData = data.data ?? data.args?.data;
811
+ const ip = data.ip ?? data.args?.ip;
812
+ const portNum = data.port ?? data.args?.port;
813
+ if (relayData instanceof Uint8Array) { /* ok */ }
814
+ else if (Array.isArray(relayData))
815
+ relayData = new Uint8Array(relayData);
816
+ else if (Buffer.isBuffer(relayData))
817
+ relayData = new Uint8Array(relayData);
818
+ else if (relayData && typeof relayData === "object" && relayData.buffer) {
819
+ relayData = new Uint8Array(relayData.buffer, relayData.byteOffset ?? 0, relayData.byteLength ?? relayData.length);
820
+ }
821
+ else if (relayData instanceof ArrayBuffer)
822
+ relayData = new Uint8Array(relayData);
823
+ else
824
+ return 0;
825
+ if (!ip || !portNum)
826
+ return 0;
827
+ callbacks.sendDataToRelay(relayData, ip, portNum);
828
+ return relayData.byteLength;
829
+ });
830
+ }
831
+ _a.#globalCallbacksRegistered = true;
832
+ };
833
+ #requireModule = (name) => {
834
+ const preDefinedModules = {
835
+ Promise,
836
+ WAWebVoipWebWasmWorkerResource: {
837
+ resourcePath: resolveWorkerScriptPath(),
838
+ name: "WAWebVoipWebWasmWorker",
839
+ },
840
+ WorkerBundleResource: {
841
+ createDedicatedWebWorker: (resource) => {
842
+ const scriptPath = resource?.resourcePath && fs.existsSync(resource.resourcePath)
843
+ ? resource.resourcePath
844
+ : resolveWorkerScriptPath();
845
+ const worker = new Worker(scriptPath, {
846
+ stdout: true, stderr: true,
847
+ workerData: {
848
+ wasmPath: this.#config.wasmPath,
849
+ wasmBinary: this.#config.wasmBinary,
850
+ workerModulesCode: this.#workerModulesCode,
851
+ loaderCode: this.#loaderCode,
852
+ loaderModuleName: this.#config.loaderModuleName,
853
+ resourcesPath: this.#config.resourcesPath,
854
+ enableLogs: this.#config.enableLogs,
855
+ },
856
+ });
857
+ worker.stdout?.on("data", () => { });
858
+ worker.stderr?.on("data", filterWorkerStderr);
859
+ return worker;
860
+ },
861
+ },
862
+ WorkerClient: { init: () => { } },
863
+ WorkerMessagePort: {
864
+ WorkerMessagePort: NodeWorkerMessagePort,
865
+ CastWorkerMessagePort: (w) => w,
866
+ WorkerSyncedMessagePort: NodeWorkerMessagePort,
867
+ },
868
+ bx: Object.assign((id) => String(id), { getURL: () => "" }),
869
+ HasteSupportData: { handle: () => { } },
870
+ ServiceWorkerDynamicModules: { handle: () => { } },
871
+ WhatsAppWebServiceWorker: { default: true },
872
+ WAWebLogger: { initializeWAWebLogger: () => { } },
873
+ WAWebSw: { initHandlers: () => { } },
874
+ WAWebWamRuntimeProvider: { setWamRuntime: () => { } },
875
+ WAWebWamWorkerInterface: { commit: () => { }, set: () => { } },
876
+ ServerJSDefine: { handleDefine: () => { } },
877
+ ix: { add: () => { } },
878
+ MetaConfigMap: { add: () => { } },
879
+ QPLHasteSupportDataStorage: { default: { add: () => { }, get: () => null } },
880
+ getFalcoLogPolicy_DO_NOT_USE: { add: () => { } },
881
+ gkx: { add: () => { } },
882
+ justknobx: { add: () => { } },
883
+ qex: { add: () => { } },
884
+ };
885
+ if (preDefinedModules[name])
886
+ return preDefinedModules[name];
887
+ const mod = this.#moduleRegistry.get(name);
888
+ if (!mod)
889
+ return {};
890
+ if (mod.exports !== undefined)
891
+ return mod.exports;
892
+ const requireFn = this.#requireModule;
893
+ const normalizeModuleResult = (value) => {
894
+ if (value && typeof value === "object" && "exports" in value && Object.keys(value).length === 1) {
895
+ return value.exports;
896
+ }
897
+ return value;
898
+ };
899
+ const importDefaultFn = (dep) => {
900
+ const v = requireFn(dep);
901
+ return v && v.__esModule ? v.default : v;
902
+ };
903
+ const importAllFn = (dep) => {
904
+ const v = requireFn(dep);
905
+ if (v == null)
906
+ return { default: v };
907
+ if (v.__esModule)
908
+ return v;
909
+ if (typeof v !== "object" && typeof v !== "function")
910
+ return { default: v };
911
+ const ns = {};
912
+ for (const key of Object.keys(v))
913
+ ns[key] = v[key];
914
+ ns.default = v;
915
+ return ns;
916
+ };
917
+ const tryMetro = () => {
918
+ const module = { exports: {} };
919
+ mod.factory(this.#vmContext ?? globalThis, requireFn, importDefaultFn, importAllFn, null, module, module.exports);
920
+ return normalizeModuleResult(module.exports);
921
+ };
922
+ const tryLegacy = () => {
923
+ const exports = {};
924
+ const module = { exports };
925
+ const resolvedDeps = mod.deps.map((dep) => requireFn(dep));
926
+ mod.factory(this.#vmContext ?? globalThis, requireFn, requireFn, requireFn, module, exports, ...resolvedDeps);
927
+ return normalizeModuleResult(module.exports);
928
+ };
929
+ let result = {};
930
+ let metroError = null;
931
+ try {
932
+ result = tryMetro();
933
+ }
934
+ catch (e) {
935
+ metroError = e;
936
+ }
937
+ if (metroError != null || (result && typeof result === "object" && Object.keys(result).length === 0)) {
938
+ try {
939
+ const legacyResult = tryLegacy();
940
+ if (typeof legacyResult === "function" || (legacyResult && Object.keys(legacyResult).length > 0)) {
941
+ result = legacyResult;
942
+ }
943
+ }
944
+ catch { }
945
+ }
946
+ mod.exports = result;
947
+ return result;
948
+ };
949
+ #createVMContext = (memory) => {
950
+ const callbacks = this.#config.callbacks ?? {};
951
+ const wasmCallbacks = {
952
+ onVoipReady: () => {
953
+ this.#voipReadyResolver?.();
954
+ callbacks.onVoipReady?.();
955
+ },
956
+ onSignalingXmpp: (data) => callbacks.onSignalingXmpp?.(data?.peerJid, data?.callId, data?.xmlPayload),
957
+ onCallEvent: (data) => callbacks.onCallEvent?.(data?.eventType, data?.eventDataJson),
958
+ sendDataToRelay: (data) => callbacks.sendDataToRelay?.(data?.data, data?.ip, data?.port),
959
+ loggingCallback: (data) => {
960
+ if (!this.#config.enableLogs)
961
+ return;
962
+ const level = data?.level;
963
+ const msg = data?.message ?? "";
964
+ const mapped = level === 1 ? "error" : level === 2 ? "warn" : level === 3 ? "log" : "debug";
965
+ callbacks.onLog?.(mapped, msg);
966
+ },
967
+ initCaptureDriverJS: (data) => {
968
+ callbacks.onAudioCaptureInit?.({
969
+ sampleRate: data?.sample_rate, channels: data?.channels,
970
+ bitsPerSample: data?.bits_per_sample, framesPerChunk: data?.frames_per_chunk,
971
+ });
972
+ return 0;
973
+ },
974
+ startCaptureJS: () => { callbacks.onAudioCaptureStart?.(); return 0; },
975
+ stopCaptureJS: () => { callbacks.onAudioCaptureStop?.(); return 0; },
976
+ initPlaybackDriverJS: (data) => {
977
+ callbacks.onAudioPlaybackInit?.({
978
+ sampleRate: data?.sample_rate, channels: data?.channels,
979
+ bitsPerSample: data?.bits_per_sample, framesPerChunk: data?.frames_per_chunk,
980
+ });
981
+ return 0;
982
+ },
983
+ startPlaybackJS: () => {
984
+ callbacks.onAudioPlaybackStart?.();
985
+ this.#startAudioPlaybackLoop();
986
+ return 0;
987
+ },
988
+ stopPlaybackJS: () => {
989
+ this.#stopAudioPlaybackLoop();
990
+ callbacks.onAudioPlaybackStop?.();
991
+ return 0;
992
+ },
993
+ startVideoCaptureJS: () => 0,
994
+ stopVideoCaptureJS: () => 0,
995
+ startDesktopCaptureJS: () => 0,
996
+ stopDesktopCaptureJS: () => 0,
997
+ dataChannelStateCallback: () => 0,
998
+ getBrowserAudioProcessingStatus: () => 7,
999
+ getBweModelPath: () => null,
1000
+ videoFrameConsumed: () => 0,
1001
+ cryptoHkdfExtractWithSaltAndExpand: (data) => {
1002
+ const key = toByteArray(data?.key_);
1003
+ const salt = data?.salt_ ? toByteArray(data.salt_) : new Uint8Array(0);
1004
+ const info = toByteArray(data?.info_);
1005
+ const length = data?.length ?? 32;
1006
+ return callbacks.cryptoHkdf?.(key, salt, info, length) ?? new Uint8Array(length);
1007
+ },
1008
+ hmacSha256KeyGenerator: (data) => {
1009
+ const hmacData = new Uint8Array(data?.data_ ?? []);
1010
+ const hmacKey = new Uint8Array(data?.key_ ?? []);
1011
+ return callbacks.hmacSha256?.(hmacData, hmacKey) ?? new Uint8Array(32);
1012
+ },
1013
+ isParticipantKnownContact: () => true,
1014
+ getPersistentDirectoryPath: () => {
1015
+ const dir = "/tmp/voip";
1016
+ try {
1017
+ if (!fs.existsSync(dir))
1018
+ fs.mkdirSync(dir, { recursive: true });
1019
+ }
1020
+ catch { }
1021
+ return dir;
1022
+ },
1023
+ };
1024
+ const __d = (name, deps, factory) => {
1025
+ this.#moduleRegistry.set(name, { deps, factory, exports: undefined });
1026
+ };
1027
+ const babelHelpers = {
1028
+ extends: Object.assign,
1029
+ inheritsLoose: (sub, sup) => {
1030
+ sub.prototype = Object.create(sup.prototype);
1031
+ sub.prototype.constructor = sub;
1032
+ sub.__proto__ = sup;
1033
+ },
1034
+ objectWithoutPropertiesLoose: (source, excluded) => {
1035
+ if (source == null)
1036
+ return {};
1037
+ const target = {};
1038
+ for (const key of Object.keys(source)) {
1039
+ if (excluded.indexOf(key) >= 0)
1040
+ continue;
1041
+ target[key] = source[key];
1042
+ }
1043
+ return target;
1044
+ },
1045
+ taggedTemplateLiteralLoose: (strings, raw) => {
1046
+ if (!raw)
1047
+ raw = strings.slice(0);
1048
+ strings.raw = raw;
1049
+ return strings;
1050
+ },
1051
+ wrapNativeSuper: (Class) => Class,
1052
+ };
1053
+ const addRunDependency = (dep) => {
1054
+ if (dep === "loading-workers" && this.#workersLoadedCount >= PTHREAD_POOL_SIZE) {
1055
+ setImmediate(() => this.#removeRunDependencyCallback?.(dep));
1056
+ }
1057
+ };
1058
+ const removeRunDependency = (_dep) => { };
1059
+ this.#removeRunDependencyCallback = removeRunDependency;
1060
+ const webCrypto = {
1061
+ getRandomValues: (arr) => {
1062
+ if (!arr || !ArrayBuffer.isView(arr)) {
1063
+ throw new TypeError("crypto.getRandomValues expects a TypedArray");
1064
+ }
1065
+ const bytes = Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
1066
+ randomFillSync(bytes);
1067
+ return arr;
1068
+ },
1069
+ };
1070
+ const selfObj = {
1071
+ __swData: { dynamic_data: { hsdp: {}, dynamic_modules: [] } },
1072
+ WhatsAppVoipWasmCallbacks: wasmCallbacks,
1073
+ WhatsAppVoipWasmWorkerCompatibleCallbacks: wasmCallbacks,
1074
+ crypto: webCrypto,
1075
+ };
1076
+ selfObj.self = selfObj;
1077
+ selfObj.window = selfObj;
1078
+ selfObj.globalThis = selfObj;
1079
+ if (typeof global !== "undefined") {
1080
+ global.WhatsAppVoipWasmCallbacks = wasmCallbacks;
1081
+ global.WhatsAppVoipWasmWorkerCompatibleCallbacks = wasmCallbacks;
1082
+ }
1083
+ const context = vm.createContext({
1084
+ self: selfObj, globalThis: selfObj, global: selfObj, window: selfObj,
1085
+ console, setTimeout, setInterval, clearTimeout, clearInterval,
1086
+ queueMicrotask, performance, babelHelpers, __d,
1087
+ require: this.#requireModule,
1088
+ addRunDependency, removeRunDependency,
1089
+ WebAssembly, SharedArrayBuffer,
1090
+ Atomics: this.#createAtomicsWrapper(memory),
1091
+ Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array,
1092
+ Float32Array, Float64Array, BigInt64Array, BigUint64Array,
1093
+ ArrayBuffer, DataView, Error, TypeError, RangeError, Promise,
1094
+ Map, Set, WeakMap, WeakSet, Symbol, Object, Array, String, Number,
1095
+ Boolean, Math, Date, JSON, RegExp, Function, Proxy, Reflect,
1096
+ crypto: webCrypto,
1097
+ WhatsAppVoipWasmCallbacks: wasmCallbacks,
1098
+ WhatsAppVoipWasmWorkerCompatibleCallbacks: wasmCallbacks,
1099
+ navigator: {
1100
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
1101
+ hardwareConcurrency: 4,
1102
+ },
1103
+ process: undefined,
1104
+ document: { currentScript: null },
1105
+ location: { href: "file:///wasm" },
1106
+ Worker: class {
1107
+ constructor() { }
1108
+ postMessage() { }
1109
+ terminate() { }
1110
+ addEventListener() { }
1111
+ },
1112
+ fetch: async () => { throw new Error("fetch not supported"); },
1113
+ XMLHttpRequest: class {
1114
+ open() { }
1115
+ send() { }
1116
+ setRequestHeader() { }
1117
+ },
1118
+ Blob: class {
1119
+ constructor() { }
1120
+ },
1121
+ URL: { createObjectURL: () => "blob:fake", revokeObjectURL: () => { } },
1122
+ Image: class {
1123
+ src = "";
1124
+ onload = null;
1125
+ onerror = null;
1126
+ },
1127
+ Audio: class {
1128
+ src = "";
1129
+ addEventListener() { }
1130
+ },
1131
+ __NODE_PTHREAD: {
1132
+ getUnusedWorker: () => {
1133
+ if (this.#unusedWorkers.length === 0)
1134
+ return null;
1135
+ const worker = this.#unusedWorkers.pop();
1136
+ this.#runningWorkers.push(worker);
1137
+ return worker;
1138
+ },
1139
+ returnWorkerToPool: (worker) => {
1140
+ const idx = this.#runningWorkers.indexOf(worker);
1141
+ if (idx >= 0) {
1142
+ this.#runningWorkers.splice(idx, 1);
1143
+ this.#unusedWorkers.push(worker);
1144
+ }
1145
+ },
1146
+ spawnThread: (params) => {
1147
+ const worker = this.#unusedWorkers.pop();
1148
+ if (!worker)
1149
+ return 6;
1150
+ this.#runningWorkers.push(worker);
1151
+ this.#pthreads[params.pthread_ptr] = worker;
1152
+ worker.pthread_ptr = params.pthread_ptr;
1153
+ const pthreadTable = this.#instance?.PThread?.pthreads;
1154
+ if (pthreadTable)
1155
+ pthreadTable[params.pthread_ptr] = worker;
1156
+ worker.postMessage({
1157
+ cmd: "run",
1158
+ start_routine: params.startRoutine,
1159
+ arg: params.arg,
1160
+ pthread_ptr: params.pthread_ptr,
1161
+ });
1162
+ return 0;
1163
+ },
1164
+ unusedWorkersCount: () => this.#unusedWorkers.length,
1165
+ runningWorkersCount: () => this.#runningWorkers.length,
1166
+ },
1167
+ __IS_NODE_PTHREAD_ENV: true,
1168
+ });
1169
+ context.self = context;
1170
+ context.globalThis = context;
1171
+ context.global = context;
1172
+ context.window = context;
1173
+ return context;
1174
+ };
1175
+ #createAtomicsWrapper = (_memory) => {
1176
+ const atomicsWrapper = {
1177
+ add: Atomics.add.bind(Atomics),
1178
+ and: Atomics.and.bind(Atomics),
1179
+ compareExchange: Atomics.compareExchange.bind(Atomics),
1180
+ exchange: Atomics.exchange.bind(Atomics),
1181
+ isLockFree: Atomics.isLockFree.bind(Atomics),
1182
+ load: Atomics.load.bind(Atomics),
1183
+ or: Atomics.or.bind(Atomics),
1184
+ store: Atomics.store.bind(Atomics),
1185
+ sub: Atomics.sub.bind(Atomics),
1186
+ xor: Atomics.xor.bind(Atomics),
1187
+ notify: (typedArray, index, count) => {
1188
+ try {
1189
+ return Atomics.notify(typedArray, index, count);
1190
+ }
1191
+ catch (e) {
1192
+ if (e?.message?.includes("futex_wake") || e?.message?.includes("main_browser_thread"))
1193
+ return 0;
1194
+ throw e;
1195
+ }
1196
+ },
1197
+ waitAsync: Atomics.waitAsync
1198
+ ? Atomics.waitAsync.bind(Atomics)
1199
+ : () => ({ async: true, value: Promise.resolve("ok") }),
1200
+ wait: (typedArray, index, value, timeout) => {
1201
+ const currentValue = Atomics.load(typedArray, index);
1202
+ if (currentValue !== value)
1203
+ return "not-equal";
1204
+ if (timeout !== undefined && timeout <= 0)
1205
+ return "timed-out";
1206
+ return "timed-out";
1207
+ },
1208
+ [Symbol.toStringTag]: "Atomics",
1209
+ };
1210
+ return atomicsWrapper;
1211
+ };
1212
+ }
1213
+ _a = WasmEngine;
1214
+ export default WasmEngine;