ruby-baileys 0.0.0-stage → 1.5.17

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 (296) hide show
  1. package/EXPERIMENTAL.md +350 -0
  2. package/LICENSE +23 -0
  3. package/NOTICE.md +14 -0
  4. package/README.md +6265 -2
  5. package/WAProto/GenerateStatics.sh +3 -0
  6. package/WAProto/WAProto.proto +5479 -0
  7. package/WAProto/fix-imports.js +81 -0
  8. package/WAProto/index.d.ts +16877 -0
  9. package/WAProto/index.js +122159 -0
  10. package/assets/ruby_aspirant.jpg +0 -0
  11. package/assets/ruby_aspirant_4k.jpg +88 -0
  12. package/assets/ruby_aspirant_full.jpg +0 -0
  13. package/assets/ruby_aspirant_render.png +1 -0
  14. package/assets/ruby_aspirants_hd.jpg +0 -0
  15. package/assets/thumb.jpg +0 -0
  16. package/engine-requirements.js +14 -0
  17. package/index.cjs +29 -0
  18. package/index.d.ts +2 -0
  19. package/package.json +178 -4
  20. package/src/Defaults/index.d.ts +153 -0
  21. package/src/Defaults/index.js +165 -0
  22. package/src/MessageBuilder/bot-signature.d.ts +22 -0
  23. package/src/MessageBuilder/bot-signature.js +123 -0
  24. package/src/MessageBuilder/extras.d.ts +396 -0
  25. package/src/MessageBuilder/extras.js +1229 -0
  26. package/src/MessageBuilder/index.d.ts +210 -0
  27. package/src/MessageBuilder/index.js +3521 -0
  28. package/src/MessageBuilder/metaai.d.ts +438 -0
  29. package/src/MessageBuilder/metaai.js +891 -0
  30. package/src/Signal/Group/ciphertext-message.d.ts +10 -0
  31. package/src/Signal/Group/ciphertext-message.js +12 -0
  32. package/src/Signal/Group/group-session-builder.d.ts +8 -0
  33. package/src/Signal/Group/group-session-builder.js +28 -0
  34. package/src/Signal/Group/group_cipher.d.ts +11 -0
  35. package/src/Signal/Group/group_cipher.js +79 -0
  36. package/src/Signal/Group/index.d.ts +12 -0
  37. package/src/Signal/Group/index.js +12 -0
  38. package/src/Signal/Group/keyhelper.d.ts +7 -0
  39. package/src/Signal/Group/keyhelper.js +18 -0
  40. package/src/Signal/Group/sender-chain-key.d.ts +14 -0
  41. package/src/Signal/Group/sender-chain-key.js +26 -0
  42. package/src/Signal/Group/sender-key-distribution-message.d.ts +17 -0
  43. package/src/Signal/Group/sender-key-distribution-message.js +63 -0
  44. package/src/Signal/Group/sender-key-message.d.ts +19 -0
  45. package/src/Signal/Group/sender-key-message.js +66 -0
  46. package/src/Signal/Group/sender-key-name.d.ts +12 -0
  47. package/src/Signal/Group/sender-key-name.js +48 -0
  48. package/src/Signal/Group/sender-key-record.d.ts +13 -0
  49. package/src/Signal/Group/sender-key-record.js +41 -0
  50. package/src/Signal/Group/sender-key-state.d.ts +17 -0
  51. package/src/Signal/Group/sender-key-state.js +84 -0
  52. package/src/Signal/Group/sender-message-key.d.ts +12 -0
  53. package/src/Signal/Group/sender-message-key.js +26 -0
  54. package/src/Signal/libsignal.d.ts +55 -0
  55. package/src/Signal/libsignal.js +429 -0
  56. package/src/Signal/lid-mapping.d.ts +21 -0
  57. package/src/Signal/lid-mapping.js +275 -0
  58. package/src/Socket/Client/index.d.ts +3 -0
  59. package/src/Socket/Client/index.js +3 -0
  60. package/src/Socket/Client/types.d.ts +6 -0
  61. package/src/Socket/Client/types.js +10 -0
  62. package/src/Socket/Client/websocket.d.ts +13 -0
  63. package/src/Socket/Client/websocket.js +54 -0
  64. package/src/Socket/business.d.ts +432 -0
  65. package/src/Socket/business.js +380 -0
  66. package/src/Socket/chats.d.ts +248 -0
  67. package/src/Socket/chats.js +1485 -0
  68. package/src/Socket/communities.d.ts +599 -0
  69. package/src/Socket/communities.js +422 -0
  70. package/src/Socket/groups.d.ts +299 -0
  71. package/src/Socket/groups.js +340 -0
  72. package/src/Socket/index.d.ts +582 -0
  73. package/src/Socket/index.js +48 -0
  74. package/src/Socket/messages-recv.d.ts +371 -0
  75. package/src/Socket/messages-recv.js +1803 -0
  76. package/src/Socket/messages-send.d.ts +391 -0
  77. package/src/Socket/messages-send.js +1575 -0
  78. package/src/Socket/mex.d.ts +2 -0
  79. package/src/Socket/mex.js +45 -0
  80. package/src/Socket/newsletter.d.ts +469 -0
  81. package/src/Socket/newsletter.js +643 -0
  82. package/src/Socket/socket.d.ts +78 -0
  83. package/src/Socket/socket.js +1088 -0
  84. package/src/Store/index.d.ts +4 -0
  85. package/src/Store/index.js +4 -0
  86. package/src/Store/make-in-memory-store.d.ts +63 -0
  87. package/src/Store/make-in-memory-store.js +398 -0
  88. package/src/Store/make-ordered-dictionary.d.ts +13 -0
  89. package/src/Store/make-ordered-dictionary.js +79 -0
  90. package/src/Store/object-repository.d.ts +11 -0
  91. package/src/Store/object-repository.js +24 -0
  92. package/src/Types/Auth.d.ts +2 -0
  93. package/src/Types/Auth.js +2 -0
  94. package/src/Types/Bussines.d.ts +2 -0
  95. package/src/Types/Bussines.js +2 -0
  96. package/src/Types/Call.d.ts +2 -0
  97. package/src/Types/Call.js +2 -0
  98. package/src/Types/Chat.d.ts +3 -0
  99. package/src/Types/Chat.js +25 -0
  100. package/src/Types/Contact.d.ts +2 -0
  101. package/src/Types/Contact.js +2 -0
  102. package/src/Types/Events.d.ts +2 -0
  103. package/src/Types/Events.js +1 -0
  104. package/src/Types/GroupMetadata.d.ts +6 -0
  105. package/src/Types/GroupMetadata.js +7 -0
  106. package/src/Types/Label.d.ts +3 -0
  107. package/src/Types/Label.js +25 -0
  108. package/src/Types/LabelAssociation.d.ts +3 -0
  109. package/src/Types/LabelAssociation.js +7 -0
  110. package/src/Types/Message.d.ts +14 -0
  111. package/src/Types/Message.js +24 -0
  112. package/src/Types/Mex.d.ts +3 -0
  113. package/src/Types/Mex.js +96 -0
  114. package/src/Types/Product.d.ts +2 -0
  115. package/src/Types/Product.js +2 -0
  116. package/src/Types/Signal.d.ts +2 -0
  117. package/src/Types/Signal.js +1 -0
  118. package/src/Types/Socket.d.ts +2 -0
  119. package/src/Types/Socket.js +1 -0
  120. package/src/Types/State.d.ts +6 -0
  121. package/src/Types/State.js +55 -0
  122. package/src/Types/USync.d.ts +2 -0
  123. package/src/Types/USync.js +1 -0
  124. package/src/Types/index.d.ts +14 -0
  125. package/src/Types/index.js +26 -0
  126. package/src/Utils/auth-store.d.ts +30 -0
  127. package/src/Utils/auth-store.js +77 -0
  128. package/src/Utils/auth-utils.d.ts +59 -0
  129. package/src/Utils/auth-utils.js +274 -0
  130. package/src/Utils/browser-utils.d.ts +10 -0
  131. package/src/Utils/browser-utils.js +29 -0
  132. package/src/Utils/business.d.ts +50 -0
  133. package/src/Utils/business.js +227 -0
  134. package/src/Utils/chat-utils.d.ts +409 -0
  135. package/src/Utils/chat-utils.js +847 -0
  136. package/src/Utils/companion-reg-client-utils.d.ts +5 -0
  137. package/src/Utils/companion-reg-client-utils.js +40 -0
  138. package/src/Utils/crypto.d.ts +40 -0
  139. package/src/Utils/crypto.js +111 -0
  140. package/src/Utils/decode-wa-message.d.ts +100 -0
  141. package/src/Utils/decode-wa-message.js +374 -0
  142. package/src/Utils/event-buffer.d.ts +23 -0
  143. package/src/Utils/event-buffer.js +625 -0
  144. package/src/Utils/generics.d.ts +64 -0
  145. package/src/Utils/generics.js +376 -0
  146. package/src/Utils/group-metadata-cache.d.ts +5 -0
  147. package/src/Utils/group-metadata-cache.js +26 -0
  148. package/src/Utils/history.d.ts +76 -0
  149. package/src/Utils/history.js +132 -0
  150. package/src/Utils/html-app.d.ts +19 -0
  151. package/src/Utils/html-app.js +97 -0
  152. package/src/Utils/html-multiplayer.d.ts +10 -0
  153. package/src/Utils/html-multiplayer.js +95 -0
  154. package/src/Utils/identity-change-handler.d.ts +14 -0
  155. package/src/Utils/identity-change-handler.js +49 -0
  156. package/src/Utils/index.d.ts +45 -0
  157. package/src/Utils/index.js +45 -0
  158. package/src/Utils/link-preview-metadata.d.ts +47 -0
  159. package/src/Utils/link-preview-metadata.js +89 -0
  160. package/src/Utils/link-preview.d.ts +13 -0
  161. package/src/Utils/link-preview.js +80 -0
  162. package/src/Utils/logger.d.ts +3 -0
  163. package/src/Utils/logger.js +3 -0
  164. package/src/Utils/lt-hash.d.ts +7 -0
  165. package/src/Utils/lt-hash.js +4 -0
  166. package/src/Utils/make-mutex.d.ts +7 -0
  167. package/src/Utils/make-mutex.js +33 -0
  168. package/src/Utils/message-retry-manager.d.ts +80 -0
  169. package/src/Utils/message-retry-manager.js +256 -0
  170. package/src/Utils/messages-media.d.ts +137 -0
  171. package/src/Utils/messages-media.js +815 -0
  172. package/src/Utils/messages.d.ts +63 -0
  173. package/src/Utils/messages.js +2149 -0
  174. package/src/Utils/modern-messages.d.ts +150 -0
  175. package/src/Utils/modern-messages.js +496 -0
  176. package/src/Utils/native-flow.d.ts +11 -0
  177. package/src/Utils/native-flow.js +116 -0
  178. package/src/Utils/newsletter-status.d.ts +158 -0
  179. package/src/Utils/newsletter-status.js +651 -0
  180. package/src/Utils/noise-handler.d.ts +21 -0
  181. package/src/Utils/noise-handler.js +201 -0
  182. package/src/Utils/offline-node-processor.d.ts +10 -0
  183. package/src/Utils/offline-node-processor.js +34 -0
  184. package/src/Utils/optional-media.d.ts +3 -0
  185. package/src/Utils/optional-media.js +46 -0
  186. package/src/Utils/payment-messages.d.ts +66 -0
  187. package/src/Utils/payment-messages.js +161 -0
  188. package/src/Utils/pre-key-manager.d.ts +26 -0
  189. package/src/Utils/pre-key-manager.js +96 -0
  190. package/src/Utils/process-message.d.ts +61 -0
  191. package/src/Utils/process-message.js +689 -0
  192. package/src/Utils/reporting-utils.d.ts +13 -0
  193. package/src/Utils/reporting-utils.js +257 -0
  194. package/src/Utils/scheduled-message.d.ts +51 -0
  195. package/src/Utils/scheduled-message.js +113 -0
  196. package/src/Utils/sender-key-memory.d.ts +20 -0
  197. package/src/Utils/sender-key-memory.js +52 -0
  198. package/src/Utils/signal.d.ts +83 -0
  199. package/src/Utils/signal.js +194 -0
  200. package/src/Utils/stanza-ack.d.ts +17 -0
  201. package/src/Utils/stanza-ack.js +31 -0
  202. package/src/Utils/status-stickers.d.ts +127 -0
  203. package/src/Utils/status-stickers.js +261 -0
  204. package/src/Utils/sync-action-utils.d.ts +3 -0
  205. package/src/Utils/sync-action-utils.js +45 -0
  206. package/src/Utils/tc-token-utils.d.ts +30 -0
  207. package/src/Utils/tc-token-utils.js +156 -0
  208. package/src/Utils/ttl-cache.d.ts +29 -0
  209. package/src/Utils/ttl-cache.js +121 -0
  210. package/src/Utils/use-mongo-auth-state.d.ts +22 -0
  211. package/src/Utils/use-mongo-auth-state.js +68 -0
  212. package/src/Utils/use-multi-file-auth-state.d.ts +12 -0
  213. package/src/Utils/use-multi-file-auth-state.js +107 -0
  214. package/src/Utils/use-mysql-auth-state.d.ts +20 -0
  215. package/src/Utils/use-mysql-auth-state.js +80 -0
  216. package/src/Utils/use-postgres-auth-state.d.ts +20 -0
  217. package/src/Utils/use-postgres-auth-state.js +80 -0
  218. package/src/Utils/use-redis-auth-state.d.ts +20 -0
  219. package/src/Utils/use-redis-auth-state.js +90 -0
  220. package/src/Utils/use-single-file-auth-state.d.ts +11 -0
  221. package/src/Utils/use-single-file-auth-state.js +109 -0
  222. package/src/Utils/use-sqlite-auth-state.d.ts +13 -0
  223. package/src/Utils/use-sqlite-auth-state.js +121 -0
  224. package/src/Utils/useNekoDBAuth.d.ts +19 -0
  225. package/src/Utils/useNekoDBAuth.js +111 -0
  226. package/src/Utils/username.d.ts +12 -0
  227. package/src/Utils/username.js +59 -0
  228. package/src/Utils/validate-connection.d.ts +44 -0
  229. package/src/Utils/validate-connection.js +208 -0
  230. package/src/Utils/voice-recognition.d.ts +53 -0
  231. package/src/Utils/voice-recognition.js +219 -0
  232. package/src/Voip/audio-feeder.d.ts +25 -0
  233. package/src/Voip/audio-feeder.js +269 -0
  234. package/src/Voip/index.d.ts +89 -0
  235. package/src/Voip/index.js +937 -0
  236. package/src/Voip/relay-transport.d.ts +6 -0
  237. package/src/Voip/relay-transport.js +825 -0
  238. package/src/Voip/signaling.d.ts +12 -0
  239. package/src/Voip/signaling.js +1100 -0
  240. package/src/Voip/types.d.ts +3 -0
  241. package/src/Voip/types.js +13 -0
  242. package/src/Voip/video-feeder.d.ts +25 -0
  243. package/src/Voip/video-feeder.js +269 -0
  244. package/src/Voip/wasm-engine.d.ts +27 -0
  245. package/src/Voip/wasm-engine.js +1308 -0
  246. package/src/Voip/worker-bootstrap.js +1024 -0
  247. package/src/WABinary/constants.d.ts +23 -0
  248. package/src/WABinary/constants.js +1301 -0
  249. package/src/WABinary/decode.d.ts +10 -0
  250. package/src/WABinary/decode.js +262 -0
  251. package/src/WABinary/encode.d.ts +3 -0
  252. package/src/WABinary/encode.js +220 -0
  253. package/src/WABinary/generic-utils.d.ts +77 -0
  254. package/src/WABinary/generic-utils.js +214 -0
  255. package/src/WABinary/index.d.ts +6 -0
  256. package/src/WABinary/index.js +6 -0
  257. package/src/WABinary/jid-utils.d.ts +31 -0
  258. package/src/WABinary/jid-utils.js +98 -0
  259. package/src/WABinary/types.d.ts +2 -0
  260. package/src/WABinary/types.js +1 -0
  261. package/src/WAM/BinaryInfo.d.ts +8 -0
  262. package/src/WAM/BinaryInfo.js +10 -0
  263. package/src/WAM/constants.d.ts +34927 -0
  264. package/src/WAM/constants.js +22853 -0
  265. package/src/WAM/encode.d.ts +2 -0
  266. package/src/WAM/encode.js +149 -0
  267. package/src/WAM/index.d.ts +4 -0
  268. package/src/WAM/index.js +4 -0
  269. package/src/WAUSync/Protocols/USyncContactProtocol.d.ts +37 -0
  270. package/src/WAUSync/Protocols/USyncContactProtocol.js +51 -0
  271. package/src/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
  272. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +52 -0
  273. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
  274. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -0
  275. package/src/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
  276. package/src/WAUSync/Protocols/USyncStatusProtocol.js +38 -0
  277. package/src/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
  278. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +24 -0
  279. package/src/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +39 -0
  280. package/src/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -0
  281. package/src/WAUSync/Protocols/UsyncLIDProtocol.d.ts +15 -0
  282. package/src/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
  283. package/src/WAUSync/Protocols/index.d.ts +6 -0
  284. package/src/WAUSync/Protocols/index.js +6 -0
  285. package/src/WAUSync/USyncQuery.d.ts +21 -0
  286. package/src/WAUSync/USyncQuery.js +94 -0
  287. package/src/WAUSync/USyncUser.d.ts +17 -0
  288. package/src/WAUSync/USyncUser.js +31 -0
  289. package/src/WAUSync/index.d.ts +4 -0
  290. package/src/WAUSync/index.js +4 -0
  291. package/src/assets/wasm/README.md +76 -0
  292. package/src/assets/wasm/loader.js +5 -0
  293. package/src/assets/wasm/whatsapp.wasm +0 -0
  294. package/src/assets/wasm/worker-modules.js +273 -0
  295. package/src/index.d.ts +49 -0
  296. package/src/index.js +54 -0
@@ -0,0 +1,1308 @@
1
+ /* Elaina Baileys maintained distribution. Upstream notices and license are preserved in LICENSE and NOTICE.md. */
2
+ import * as vm from 'node:vm';
3
+ import * as fs from 'node:fs';
4
+ import * as path from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { Worker } from 'node:worker_threads';
7
+ import { randomFillSync } from 'node:crypto';
8
+ import { fileURLToPath } from 'node:url';
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ const CALL_WASM_AB_PROPS_JSON = process.env.CALL_WASM_AB_PROPS_JSON ?? "";
11
+ const PTHREAD_POOL_SIZE = 20;
12
+ const VOIP_READY_TIMEOUT_MS = 15_000;
13
+ const parseJsonObjectEnv = (raw) => {
14
+ if (!raw)
15
+ return {};
16
+ try {
17
+ const parsed = JSON.parse(raw);
18
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
19
+ return parsed;
20
+ }
21
+ catch { }
22
+ return {};
23
+ };
24
+ const toByteArray = (input) => {
25
+ if (!input)
26
+ return new Uint8Array(0);
27
+ if (input instanceof Uint8Array)
28
+ return input;
29
+ if (typeof input === "string")
30
+ return new TextEncoder().encode(input);
31
+ if (ArrayBuffer.isView(input))
32
+ return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
33
+ if (input instanceof ArrayBuffer)
34
+ return new Uint8Array(input);
35
+ if (typeof input === "object" && typeof input.length === "number") {
36
+ const arr = new Uint8Array(input.length);
37
+ for (let i = 0; i < input.length; i += 1)
38
+ arr[i] = input[i] ?? 0;
39
+ return arr;
40
+ }
41
+ return new Uint8Array(0);
42
+ };
43
+ const filterWorkerStderr = (chunk) => {
44
+ const line = chunk.toString().trim();
45
+ if (line && !line.startsWith("voip:") && !line.startsWith("still waiting")) {
46
+ process.stderr.write(chunk);
47
+ }
48
+ };
49
+ const normalizeVideoCaptureConfig = (data) => ({
50
+ width: Math.trunc(Number(data?.width ?? data?.frame_width ?? data?.frameWidth ?? 0)) || 640,
51
+ height: Math.trunc(Number(data?.height ?? data?.frame_height ?? data?.frameHeight ?? 0)) || 480,
52
+ fps: Math.trunc(Number(data?.fps ?? data?.frame_rate ?? data?.frameRate ?? data?.max_framerate ?? 0)) || 24,
53
+ raw: data
54
+ });
55
+ const resolveWorkerScriptPath = () => {
56
+ const compiled = path.join(__dirname, "worker-bootstrap.js");
57
+ return fs.existsSync(compiled) ? compiled : path.join(__dirname, "worker-bootstrap.mts");
58
+ };
59
+ class NodeWorkerMessagePort {
60
+ #listeners = new Map();
61
+ #worker;
62
+ fullyConnected;
63
+ name;
64
+ workerID = 0;
65
+ pthread_ptr = 0;
66
+ constructor(worker, name = "WAWebVoipWebWasmWorker") {
67
+ this.#worker = worker;
68
+ this.name = name;
69
+ this.fullyConnected = new Promise((resolve) => {
70
+ const loadedHandler = (msg) => {
71
+ if (msg && msg.cmd === "loaded") {
72
+ this.workerID = msg.workerID ?? 0;
73
+ resolve(this);
74
+ }
75
+ };
76
+ this.addMessageListener("cmd", loadedHandler);
77
+ });
78
+ if (typeof worker.on === "function") {
79
+ worker.on("message", (data) => this.#handleMessage(data));
80
+ worker.on("error", () => { });
81
+ }
82
+ else if (typeof worker.addEventListener === "function") {
83
+ worker.addEventListener("message", (ev) => this.#handleMessage(ev?.data ?? ev));
84
+ }
85
+ }
86
+ postMessage = (msg, transferList) => {
87
+ const out = msg && typeof msg === "object" && msg.cmd && !msg.type ? { ...msg, type: "cmd" } : msg;
88
+ this.#worker.postMessage(out, transferList);
89
+ };
90
+ addMessageListener = (type, handler) => {
91
+ let set = this.#listeners.get(type);
92
+ if (!set) {
93
+ set = new Set();
94
+ this.#listeners.set(type, set);
95
+ }
96
+ set.add(handler);
97
+ return handler;
98
+ };
99
+ removeMessageListener = (type, handler) => this.#listeners.get(type)?.delete(handler) ?? false;
100
+ removeAllMessageListeners = (type) => {
101
+ if (type)
102
+ this.#listeners.get(type)?.clear();
103
+ else
104
+ this.#listeners.clear();
105
+ };
106
+ terminate = () => { this.#worker.terminate(); };
107
+ close = () => { };
108
+ isWrappingVirtualMessagePort = () => false;
109
+ getWorker = () => this.#worker;
110
+ #handleMessage = (data) => {
111
+ if (!data || typeof data !== "object")
112
+ return;
113
+ if (data.type === "callback" || data.type === "waWasmWorkerCompatibleCallback") {
114
+ let callbackName;
115
+ let callbackArgs;
116
+ if (data.__name) {
117
+ callbackName = data.__name;
118
+ callbackArgs = {};
119
+ for (const key in data) {
120
+ if (key !== "type" && key !== "__name" && key !== "prototype" && key !== "args" && !key.startsWith("__")) {
121
+ callbackArgs[key] = data[key];
122
+ }
123
+ }
124
+ }
125
+ else if (data.name) {
126
+ callbackName = data.name;
127
+ callbackArgs = data.args ?? {};
128
+ }
129
+ else if (data.payload?.name) {
130
+ callbackName = data.payload.name;
131
+ callbackArgs = data.payload.args ?? {};
132
+ }
133
+ else {
134
+ return;
135
+ }
136
+ if (callbackName === "onSignalingXmpp" &&
137
+ (!callbackArgs || Object.keys(callbackArgs).length === 0)) {
138
+ callbackArgs = {
139
+ peerJid: data.peerJid, callId: data.callId, xmlPayload: data.xmlPayload,
140
+ };
141
+ }
142
+ let listenerData = callbackArgs;
143
+ if (!callbackArgs || Object.keys(callbackArgs).length === 0 ||
144
+ (Object.keys(callbackArgs).length === 1 && callbackArgs.prototype)) {
145
+ listenerData = {};
146
+ for (const key in data) {
147
+ if (key !== "type" && key !== "__name" && key !== "prototype" && key !== "args" && !key.startsWith("__")) {
148
+ listenerData[key] = data[key];
149
+ }
150
+ }
151
+ }
152
+ else if (callbackName === "sendDataToRelay") {
153
+ listenerData = { ...callbackArgs };
154
+ if (data.data !== undefined)
155
+ listenerData.data = data.data;
156
+ if (data.len !== undefined)
157
+ listenerData.len = data.len;
158
+ if (data.ip !== undefined)
159
+ listenerData.ip = data.ip;
160
+ if (data.port !== undefined)
161
+ listenerData.port = data.port;
162
+ }
163
+ else if (callbackName === "onCallEvent") {
164
+ listenerData = { ...callbackArgs };
165
+ if (data.eventType !== undefined)
166
+ listenerData.eventType = data.eventType;
167
+ if (data.userData !== undefined)
168
+ listenerData.userData = data.userData;
169
+ if (data.eventDataJson !== undefined)
170
+ listenerData.eventDataJson = data.eventDataJson;
171
+ }
172
+ WasmEngine.notifyGlobalCallbackListeners(callbackName, listenerData);
173
+ return;
174
+ }
175
+ const dispatch = (key) => {
176
+ if (!key)
177
+ return;
178
+ for (const handler of this.#listeners.get(key) ?? []) {
179
+ try {
180
+ handler(data);
181
+ }
182
+ catch { }
183
+ }
184
+ };
185
+ dispatch(data.type);
186
+ if (data.cmd !== data.type)
187
+ dispatch(data.cmd);
188
+ };
189
+ }
190
+ export class WasmEngine {
191
+ #jsWorkers = new Set();
192
+ static #globalCallbackListeners = new Map();
193
+ static #globalCallbacksRegistered = false;
194
+ static registerGlobalCallbackListener = (callbackName, handler) => {
195
+ const key = `callback:${callbackName}`;
196
+ let set = WasmEngine.#globalCallbackListeners.get(key);
197
+ if (!set) {
198
+ set = new Set();
199
+ WasmEngine.#globalCallbackListeners.set(key, set);
200
+ }
201
+ set.add(handler);
202
+ };
203
+ static notifyGlobalCallbackListeners = (callbackName, data) => {
204
+ const set = WasmEngine.#globalCallbackListeners.get(`callback:${callbackName}`);
205
+ if (!set)
206
+ return;
207
+ for (const handler of set) {
208
+ try {
209
+ handler(data);
210
+ }
211
+ catch { }
212
+ }
213
+ };
214
+ #config;
215
+ #instance = null;
216
+ #initialized = false;
217
+ #moduleRegistry = new Map();
218
+ #vmContext = null;
219
+ #unusedWorkers = [];
220
+ #runningWorkers = [];
221
+ #pthreads = {};
222
+ #nextWorkerID = 1;
223
+ #wasmModule = null;
224
+ #wasmMemory = null;
225
+ #removeRunDependencyCallback = null;
226
+ #workersLoadedCount = 0;
227
+ #audioPlaybackLoopInterval = null;
228
+ #audioPlaybackBuffer = null;
229
+ #isPlaybackActive = false;
230
+ #voipStackInitialized = false;
231
+ #voipStackInitPromise = null;
232
+ #voipReadyResolver = null;
233
+ #voipReadyPromise = null;
234
+ #workerModulesCode = "";
235
+ #loaderCode = "";
236
+ constructor(config = {}) {
237
+ const basePath = config.resourcesPath
238
+ ? (path.isAbsolute(config.resourcesPath) ? config.resourcesPath : path.resolve(process.cwd(), config.resourcesPath))
239
+ : path.resolve(__dirname, "..");
240
+ const wasmPath = config.wasmPath
241
+ ? (path.isAbsolute(config.wasmPath) ? config.wasmPath : path.resolve(process.cwd(), config.wasmPath))
242
+ : path.join(basePath, "assets", "wasm", "whatsapp.wasm");
243
+ this.#config = {
244
+ ...config,
245
+ storageDir: config.storageDir
246
+ ? (path.isAbsolute(config.storageDir) ? config.storageDir : path.resolve(process.cwd(), config.storageDir))
247
+ : path.join(tmpdir(), "elaina-voip"),
248
+ wasmPath,
249
+ resourcesPath: basePath,
250
+ enableLogs: config.enableLogs ?? true,
251
+ options: {
252
+ heartbeatInterval: 30,
253
+ lobbyTimeout: 1,
254
+ maxParticipantsScreenShare: 32,
255
+ maxGroupSizeLongRingtone: 32,
256
+ ...config.options,
257
+ },
258
+ };
259
+ }
260
+ initialize = async () => {
261
+ if (this.#initialized)
262
+ throw new Error("WasmEngine already initialized");
263
+ const voipStorageDir = this.#config.storageDir;
264
+ try {
265
+ if (!fs.existsSync(voipStorageDir))
266
+ fs.mkdirSync(voipStorageDir, { recursive: true });
267
+ }
268
+ catch { }
269
+ const loaderFile = path.join(this.#config.resourcesPath, "assets", "wasm", "loader.js");
270
+ const workerFile = path.join(this.#config.resourcesPath, "assets", "wasm", "worker-modules.js");
271
+ if (!this.#config.wasmBinary && !fs.existsSync(this.#config.wasmPath)) {
272
+ throw new Error(`WhatsApp VoIP WASM not found at ${this.#config.wasmPath}. Point wasmPath at it, hand the bytes over as wasmBinary, or put whatsapp.wasm, loader.js and worker-modules.js under <resourcesPath>/assets/wasm/.`);
273
+ }
274
+ const wasmBuffer = this.#config.wasmBinary
275
+ ? Buffer.from(this.#config.wasmBinary)
276
+ : fs.readFileSync(this.#config.wasmPath);
277
+ const diskWorkerCode = fs.existsSync(workerFile) ? fs.readFileSync(workerFile, "utf8") : "";
278
+ this.#workerModulesCode = this.#config.workerModulesCode ?? diskWorkerCode;
279
+ const workerBundleHasLoader = typeof this.#workerModulesCode === "string" && /WAWebVoipWebWasmLoader/.test(this.#workerModulesCode);
280
+ this.#loaderCode = this.#config.loaderCode ??
281
+ (workerBundleHasLoader ? "" : fs.existsSync(loaderFile) ? fs.readFileSync(loaderFile, "utf8") : "");
282
+ if (!this.#loaderCode && !this.#workerModulesCode) {
283
+ throw new Error("No loader/worker code available to initialize VoIP");
284
+ }
285
+ const memory = new WebAssembly.Memory({ initial: 256, maximum: 32768, shared: true });
286
+ this.#wasmMemory = memory;
287
+ this.#wasmModule = await WebAssembly.compile(wasmBuffer);
288
+ this.#vmContext = this.#createVMContext(memory);
289
+ const runModuleCode = (code) => {
290
+ if (code)
291
+ vm.runInContext(code, this.#vmContext);
292
+ };
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 (!WasmEngine.#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
+ startGroupCall = (options) => {
437
+ this.#ensureInitialized();
438
+ const pnUserJids = this.#makeStringList(options.pnUserJids ?? []);
439
+ const lidUserJids = this.#makeStringList(options.lidUserJids ?? []);
440
+ const deviceJidsCsv = this.#makeStringList(options.deviceJidsCsv ?? []);
441
+ try {
442
+ return this.#instance.startVoipGroupCall(pnUserJids, lidUserJids, deviceJidsCsv, options.callId, options.isVideo ?? false, options.groupJid, options.isLightWeight ?? false, options.scheduleId ?? "", options.chatName ?? "", options.chatIcon ?? "", options.callFromUI ?? 0, options.lobbyEntryType ?? 0, options.username ?? "");
443
+ }
444
+ finally {
445
+ pnUserJids?.delete?.();
446
+ lidUserJids?.delete?.();
447
+ deviceJidsCsv?.delete?.();
448
+ }
449
+ };
450
+ joinOngoingCall = (options) => {
451
+ this.#ensureInitialized();
452
+ const pnUserJids = this.#makeStringList(options.pnUserJids ?? []);
453
+ const lidUserJids = this.#makeStringList(options.lidUserJids ?? []);
454
+ const deviceJidsCsv = this.#makeStringList(options.deviceJidsCsv ?? []);
455
+ try {
456
+ return this.#instance.joinVoipOngoingCall(options.callId, options.callCreatorJid, options.initialPeerJid ?? options.callCreatorJid, pnUserJids, lidUserJids, deviceJidsCsv, options.isVideo ?? false, options.groupJid ?? "", options.initialGroupTransactionId ?? 0, options.callCreatorIsNotContact ?? false, options.callLinkCode ?? "", options.isLightweight ?? false, options.scheduledId ?? "", options.joinAndAccept ?? true, options.chatName ?? "", options.lobbyEntryType ?? 0, options.isDeviceSwitch ?? false);
457
+ }
458
+ finally {
459
+ pnUserJids?.delete?.();
460
+ lidUserJids?.delete?.();
461
+ deviceJidsCsv?.delete?.();
462
+ }
463
+ };
464
+ acceptCall = (isMicEnabled = true, isCameraEnabled = false) => {
465
+ this.#ensureInitialized();
466
+ return this.#instance.acceptCall(isMicEnabled, isCameraEnabled);
467
+ };
468
+ endCall = (reason = 0, sendTerminate = true) => {
469
+ this.#ensureInitialized();
470
+ this.#instance.endCall(reason, sendTerminate);
471
+ };
472
+ setMute = (muted) => {
473
+ this.#ensureInitialized();
474
+ return this.#instance.setCallMute(muted);
475
+ };
476
+ updateNetworkMedium = (networkMedium, networkMtu = 0) => {
477
+ this.#ensureInitialized();
478
+ this.#instance.updateNetworkMedium?.(networkMedium, networkMtu);
479
+ };
480
+ handleSignalingOffer = (msg) => {
481
+ this.#ensureInitialized();
482
+ const tcTokenList = this.#createUint8List(msg.tcToken);
483
+ try {
484
+ 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);
485
+ }
486
+ finally {
487
+ tcTokenList?.delete?.();
488
+ }
489
+ };
490
+ handleSignalingMessage = (msg) => {
491
+ this.#ensureInitialized();
492
+ const tcTokenList = this.#createUint8List(msg.tcToken);
493
+ try {
494
+ 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);
495
+ }
496
+ finally {
497
+ tcTokenList?.delete?.();
498
+ }
499
+ };
500
+ handleSignalingAck = (msg) => {
501
+ this.#ensureInitialized();
502
+ const options = this.#createUint8List(msg.extraData);
503
+ try {
504
+ this.#instance.handleIncomingSignalingAck(msg.payload, String(msg.ackError ?? "0"), String(msg.msgType ?? ""), msg.peerJid ?? "", options);
505
+ }
506
+ finally {
507
+ options?.delete?.();
508
+ }
509
+ };
510
+ handleSignalingReceipt = (msg) => {
511
+ this.#ensureInitialized();
512
+ const tcTokenList = this.#createUint8List(msg.tcToken);
513
+ try {
514
+ this.#instance.handleIncomingSignalingReceipt?.(msg.payload, msg.peerJid, tcTokenList);
515
+ }
516
+ finally {
517
+ tcTokenList?.delete?.();
518
+ }
519
+ };
520
+ handleOnTransportMessage = (data, ip, port) => {
521
+ this.#ensureInitialized();
522
+ if (typeof this.#instance.handleOnMessageFromHeap === "function") {
523
+ const ptr = this.malloc(data.byteLength);
524
+ if (!ptr)
525
+ return;
526
+ try {
527
+ const heapU8 = this.#instance.GROWABLE_HEAP_U8?.() ?? this.#instance.HEAPU8;
528
+ if (!heapU8)
529
+ return;
530
+ heapU8.set(data, ptr);
531
+ this.#instance.handleOnMessageFromHeap(ptr, data.byteLength, ip, port);
532
+ }
533
+ finally {
534
+ this.free(ptr);
535
+ }
536
+ return;
537
+ }
538
+ if (typeof this.#instance.handleOnMessage !== "function")
539
+ return;
540
+ const dataList = this.#createUint8List(data);
541
+ try {
542
+ this.#instance.handleOnMessage(dataList, ip, port);
543
+ }
544
+ finally {
545
+ dataList?.delete?.();
546
+ }
547
+ };
548
+ updateIceRtt = (rttMs, relayIp, relayPort) => {
549
+ this.#ensureInitialized();
550
+ this.#instance.updateIceRtt?.(rttMs, relayIp, relayPort);
551
+ };
552
+ startScreenShare = () => {
553
+ this.#ensureInitialized();
554
+ return this.#instance.startScreenShare?.();
555
+ };
556
+ stopScreenShare = () => {
557
+ this.#ensureInitialized();
558
+ return this.#instance.stopScreenShare?.();
559
+ };
560
+ sendVideoFrame = (frame, width, height, fps, format = 0, orientation = 0, useDesktopCapture = false) => {
561
+ if (!this.#jsWorkers.size || !frame?.byteLength || !width || !height) {
562
+ return false;
563
+ }
564
+ const timestamp = Date.now();
565
+ for (const worker of this.#jsWorkers) {
566
+ const copy = frame.buffer.slice(frame.byteOffset, frame.byteOffset + frame.byteLength);
567
+ try {
568
+ worker.postMessage({
569
+ type: "jsWorkerCmd",
570
+ jsWorkerCmd: "pushRawVideoFrame",
571
+ useDesktopCapture,
572
+ frameBuffer: copy,
573
+ width,
574
+ height,
575
+ fps,
576
+ format,
577
+ orientation,
578
+ timestamp
579
+ }, [copy]);
580
+ }
581
+ catch { }
582
+ }
583
+ return true;
584
+ };
585
+ releaseVideoFrameBuffer = () => {
586
+ for (const worker of this.#jsWorkers) {
587
+ try {
588
+ worker.postMessage({ type: "jsWorkerCmd", jsWorkerCmd: "releaseRawVideoFrameBuffer" });
589
+ }
590
+ catch { }
591
+ }
592
+ };
593
+ sendAudioData = (data, ptr) => {
594
+ this.#ensureInitialized();
595
+ if (!data || data.length === 0 || !ptr)
596
+ return;
597
+ if (typeof this.#instance.onAudioDataFromJs !== "function")
598
+ return;
599
+ try {
600
+ const heapF32 = this.#instance.GROWABLE_HEAP_F32?.();
601
+ if (!heapF32)
602
+ return;
603
+ const index = Math.floor(ptr / 4);
604
+ if (index < 0 || index + data.length > heapF32.length)
605
+ return;
606
+ heapF32.set(data, index);
607
+ this.#instance.onAudioDataFromJs(ptr, data.length);
608
+ }
609
+ catch { }
610
+ };
611
+ malloc = (size) => {
612
+ this.#ensureInitialized();
613
+ return this.#instance._malloc(size);
614
+ };
615
+ free = (ptr) => {
616
+ this.#ensureInitialized();
617
+ this.#instance._free(ptr);
618
+ };
619
+ #ensureInitialized = () => {
620
+ if (!this.#initialized || !this.#instance) {
621
+ throw new Error("WasmEngine not initialized. Call initialize() first.");
622
+ }
623
+ };
624
+ #makeStringList = (arr) => {
625
+ const list = new this.#instance.StringList();
626
+ for (const v of arr)
627
+ list.push_back(v);
628
+ return list;
629
+ };
630
+ #createUint8List = (data) => {
631
+ if (!this.#instance?.Uint8List)
632
+ return null;
633
+ const list = new this.#instance.Uint8List();
634
+ if (data)
635
+ data.forEach((byte) => list.push_back(byte));
636
+ return list;
637
+ };
638
+ #startAudioPlaybackLoop = () => {
639
+ if (this.#audioPlaybackLoopInterval)
640
+ return;
641
+ this.#ensureInitialized();
642
+ this.#isPlaybackActive = true;
643
+ if (typeof this.#instance.requestAudioDataFromWasmVoip !== "function")
644
+ return;
645
+ const framesPerChunk = 320;
646
+ const bufferSize = framesPerChunk * 4;
647
+ try {
648
+ const _malloc = this.#instance._malloc ?? this.#instance.malloc;
649
+ if (!_malloc)
650
+ return;
651
+ this.#audioPlaybackBuffer = _malloc(bufferSize);
652
+ }
653
+ catch {
654
+ return;
655
+ }
656
+ if (!this.#audioPlaybackBuffer || this.#audioPlaybackBuffer <= 0)
657
+ return;
658
+ this.#audioPlaybackLoopInterval = setInterval(() => {
659
+ if (!this.#isPlaybackActive || !this.#instance || !this.#initialized) {
660
+ this.#stopAudioPlaybackLoop();
661
+ return;
662
+ }
663
+ try {
664
+ this.#instance.requestAudioDataFromWasmVoip(this.#audioPlaybackBuffer, bufferSize);
665
+ const heapF32 = this.#instance.GROWABLE_HEAP_F32?.();
666
+ if (!heapF32)
667
+ return;
668
+ const index = Math.floor(this.#audioPlaybackBuffer / 4);
669
+ const numFloats = Math.floor(bufferSize / 4);
670
+ if (index < 0 || index + numFloats > heapF32.length)
671
+ return;
672
+ const audioData = new Float32Array(heapF32.buffer, heapF32.byteOffset + index * 4, numFloats);
673
+ const hasNonZero = audioData.some((s) => Math.abs(s) > 0.0001);
674
+ if (hasNonZero)
675
+ this.#config.callbacks?.onAudioPlaybackData?.(audioData);
676
+ }
677
+ catch { }
678
+ }, 16);
679
+ };
680
+ #stopAudioPlaybackLoop = () => {
681
+ this.#isPlaybackActive = false;
682
+ if (this.#audioPlaybackLoopInterval) {
683
+ clearInterval(this.#audioPlaybackLoopInterval);
684
+ this.#audioPlaybackLoopInterval = null;
685
+ }
686
+ if (this.#audioPlaybackBuffer && this.#audioPlaybackBuffer > 0) {
687
+ try {
688
+ this.#instance?._free?.(this.#audioPlaybackBuffer);
689
+ }
690
+ catch { }
691
+ this.#audioPlaybackBuffer = null;
692
+ }
693
+ };
694
+ #applyDefaultAbProps = () => {
695
+ if (!this.#instance)
696
+ return;
697
+ const setInt = typeof this.#instance.setABPropInt === "function"
698
+ ? (k, v) => { this.#instance.setABPropInt(k, v); }
699
+ : null;
700
+ const setBool = typeof this.#instance.setABPropBool === "function"
701
+ ? (k, v) => { this.#instance.setABPropBool(k, v); }
702
+ : null;
703
+ const setString = typeof this.#instance.setABPropString === "function"
704
+ ? (k, v) => { this.#instance.setABPropString(k, v); }
705
+ : null;
706
+ if (!setInt && !setBool && !setString)
707
+ return;
708
+ const opts = this.#config.options ?? {};
709
+ const intProps = {
710
+ heartbeat_interval_s: opts.heartbeatInterval ?? 30,
711
+ lobby_timeout_min: opts.lobbyTimeout ?? 1,
712
+ max_num_participants_for_ss: opts.maxParticipantsScreenShare ?? 32,
713
+ max_group_size_for_long_ringtone: opts.maxGroupSizeLongRingtone ?? 32,
714
+ app_exit_reason_version: 1,
715
+ log_level: opts.logLevel ?? 3,
716
+ calling_rust_migration_bitmap: 0,
717
+ calling_rust_migration_incoming_stanza_bitmap: 0,
718
+ default_endpoint_thread_poll_timeout: 0,
719
+ aigc_version: 0,
720
+ call_admin_version: 0,
721
+ vid_stream_pause_resume_jb_reset_threshold_ms: 0,
722
+ opus_max_bandwidth: 1103, // OPUS_BANDWIDTH_WIDEBAND
723
+ };
724
+ const boolProps = {
725
+ enable_av_downgrade: false,
726
+ enable_new_user_action_stanza_for_raise_hand_sender: false,
727
+ enable_webcodec_video_encode: false,
728
+ enable_init_bwe_for_group_call: false,
729
+ enable_ring_for_gc_on_offer_expire: false,
730
+ allow_reporting_call_replayer_id: false,
731
+ enable_offer_v2_upgrade: false,
732
+ enable_silent_offer: false,
733
+ voice_ai_conversation_starter_latency_tracking: false,
734
+ enable_waiting_room_logging: false,
735
+ attach_transport_rtx: false,
736
+ ignore_joinable_terminate_on_expired_offer: false,
737
+ enable_passthrough_video_decoder: false,
738
+ };
739
+ for (const [key, value] of Object.entries(intProps)) {
740
+ if (setInt && Number.isFinite(value))
741
+ try {
742
+ setInt(key, value);
743
+ }
744
+ catch { }
745
+ }
746
+ for (const [key, value] of Object.entries(boolProps)) {
747
+ if (setBool)
748
+ try {
749
+ setBool(key, value);
750
+ }
751
+ catch { }
752
+ }
753
+ const overrideProps = parseJsonObjectEnv(CALL_WASM_AB_PROPS_JSON);
754
+ for (const [key, value] of Object.entries(overrideProps)) {
755
+ try {
756
+ if (typeof value === "boolean" && setBool)
757
+ setBool(key, value);
758
+ else if (typeof value === "number" && setInt)
759
+ setInt(key, value);
760
+ else if (typeof value === "string" && setString)
761
+ setString(key, value);
762
+ }
763
+ catch { }
764
+ }
765
+ };
766
+ #allocateUnusedWorker = () => {
767
+ const workerScriptPath = resolveWorkerScriptPath();
768
+ if (!fs.existsSync(workerScriptPath))
769
+ return;
770
+ try {
771
+ const worker = new Worker(workerScriptPath, {
772
+ stdout: true, stderr: true,
773
+ workerData: {
774
+ wasmPath: this.#config.wasmPath,
775
+ wasmBinary: this.#config.wasmBinary,
776
+ workerModulesCode: this.#workerModulesCode,
777
+ loaderCode: this.#loaderCode,
778
+ loaderModuleName: this.#config.loaderModuleName,
779
+ resourcesPath: this.#config.resourcesPath,
780
+ storageDir: this.#config.storageDir,
781
+ enableLogs: this.#config.enableLogs,
782
+ },
783
+ });
784
+ const port = new NodeWorkerMessagePort(worker, "WAWebVoipWebWasmWorker");
785
+ worker.stdout?.on("data", () => { }); // suppress noisy worker stdout
786
+ worker.stderr?.on("data", filterWorkerStderr);
787
+ this.#unusedWorkers.push(port);
788
+ }
789
+ catch { }
790
+ };
791
+ #initPThreadPool = async () => {
792
+ for (let i = 0; i < PTHREAD_POOL_SIZE; i += 1)
793
+ this.#allocateUnusedWorker();
794
+ };
795
+ #loadWasmModuleToWorker = (worker) => new Promise((resolve) => {
796
+ const loadedHandler = (msg) => {
797
+ if (msg && msg.cmd === "loaded") {
798
+ worker.removeMessageListener("cmd", loadedHandler);
799
+ this.#workersLoadedCount += 1;
800
+ if (this.#workersLoadedCount >= PTHREAD_POOL_SIZE && this.#removeRunDependencyCallback) {
801
+ this.#removeRunDependencyCallback("loading-workers");
802
+ }
803
+ resolve();
804
+ }
805
+ };
806
+ worker.addMessageListener("cmd", loadedHandler);
807
+ worker.workerID = this.#nextWorkerID++;
808
+ worker.postMessage({
809
+ cmd: "load", type: "cmd",
810
+ wasmMemory: this.#wasmMemory,
811
+ wasmModule: this.#wasmModule,
812
+ workerID: worker.workerID,
813
+ handlers: [],
814
+ });
815
+ });
816
+ #loadWasmModuleToAllWorkers = async () => {
817
+ this.#workersLoadedCount = 0;
818
+ await Promise.all(this.#unusedWorkers.map((w) => this.#loadWasmModuleToWorker(w)));
819
+ };
820
+ #registerGlobalCallbacks = () => {
821
+ const callbacks = this.#config.callbacks ?? {};
822
+ WasmEngine.registerGlobalCallbackListener("loggingCallback", (data) => {
823
+ if (!this.#config.enableLogs)
824
+ return;
825
+ const level = data?.level;
826
+ const msg = data?.message ?? "";
827
+ const mapped = level === 1 ? "error" : level === 2 ? "warn" : level === 3 ? "log" : "debug";
828
+ callbacks.onLog?.(mapped, msg);
829
+ });
830
+ if (callbacks.onAudioCaptureInit) {
831
+ WasmEngine.registerGlobalCallbackListener("initCaptureDriverJS", (data) => {
832
+ callbacks.onAudioCaptureInit({
833
+ sampleRate: data?.sample_rate ?? data?.sampleRate,
834
+ channels: data?.channels,
835
+ bitsPerSample: data?.bits_per_sample ?? data?.bitsPerSample,
836
+ framesPerChunk: data?.frames_per_chunk ?? data?.framesPerChunk,
837
+ });
838
+ });
839
+ }
840
+ WasmEngine.registerGlobalCallbackListener("startVideoCaptureJS", (data) => callbacks.onVideoCaptureStart?.(normalizeVideoCaptureConfig(data)));
841
+ WasmEngine.registerGlobalCallbackListener("stopVideoCaptureJS", () => callbacks.onVideoCaptureStop?.());
842
+ WasmEngine.registerGlobalCallbackListener("videoFrameConsumed", () => callbacks.onVideoFrameConsumed?.());
843
+ WasmEngine.registerGlobalCallbackListener("startDesktopCaptureJS", (data) => callbacks.onDesktopCaptureStart?.(normalizeVideoCaptureConfig(data)));
844
+ WasmEngine.registerGlobalCallbackListener("stopDesktopCaptureJS", () => callbacks.onDesktopCaptureStop?.());
845
+ WasmEngine.registerGlobalCallbackListener("startCaptureJS", () => callbacks.onAudioCaptureStart?.());
846
+ WasmEngine.registerGlobalCallbackListener("stopCaptureJS", () => callbacks.onAudioCaptureStop?.());
847
+ if (callbacks.onAudioPlaybackInit) {
848
+ WasmEngine.registerGlobalCallbackListener("initPlaybackDriverJS", (data) => {
849
+ callbacks.onAudioPlaybackInit({
850
+ sampleRate: data?.sample_rate ?? data?.sampleRate,
851
+ channels: data?.channels,
852
+ bitsPerSample: data?.bits_per_sample ?? data?.bitsPerSample,
853
+ framesPerChunk: data?.frames_per_chunk ?? data?.framesPerChunk,
854
+ });
855
+ });
856
+ }
857
+ WasmEngine.registerGlobalCallbackListener("startPlaybackJS", () => {
858
+ callbacks.onAudioPlaybackStart?.();
859
+ this.#startAudioPlaybackLoop();
860
+ });
861
+ WasmEngine.registerGlobalCallbackListener("stopPlaybackJS", () => {
862
+ this.#stopAudioPlaybackLoop();
863
+ callbacks.onAudioPlaybackStop?.();
864
+ });
865
+ if (callbacks.onSignalingXmpp) {
866
+ WasmEngine.registerGlobalCallbackListener("onSignalingXmpp", (data) => {
867
+ const peerJid = data.peerJid ?? data.args?.peerJid;
868
+ const callId = data.callId ?? data.args?.callId;
869
+ let xmlPayload = data.xmlPayload ?? data.args?.xmlPayload;
870
+ if (Array.isArray(xmlPayload))
871
+ xmlPayload = new Uint8Array(xmlPayload);
872
+ else if (xmlPayload && typeof xmlPayload === "object" &&
873
+ !(xmlPayload instanceof Uint8Array) && !Buffer.isBuffer(xmlPayload)) {
874
+ xmlPayload = new Uint8Array(xmlPayload);
875
+ }
876
+ callbacks.onSignalingXmpp(peerJid, callId, xmlPayload);
877
+ });
878
+ }
879
+ if (callbacks.onCallEvent) {
880
+ WasmEngine.registerGlobalCallbackListener("onCallEvent", (data) => {
881
+ callbacks.onCallEvent(data.eventType, data.eventDataJson);
882
+ });
883
+ }
884
+ if (callbacks.sendDataToRelay) {
885
+ WasmEngine.registerGlobalCallbackListener("sendDataToRelay", (data) => {
886
+ let relayData = data.data ?? data.args?.data;
887
+ const ip = data.ip ?? data.args?.ip;
888
+ const portNum = data.port ?? data.args?.port;
889
+ if (relayData instanceof Uint8Array) { /* ok */ }
890
+ else if (Array.isArray(relayData))
891
+ relayData = new Uint8Array(relayData);
892
+ else if (Buffer.isBuffer(relayData))
893
+ relayData = new Uint8Array(relayData);
894
+ else if (relayData && typeof relayData === "object" && relayData.buffer) {
895
+ relayData = new Uint8Array(relayData.buffer, relayData.byteOffset ?? 0, relayData.byteLength ?? relayData.length);
896
+ }
897
+ else if (relayData instanceof ArrayBuffer)
898
+ relayData = new Uint8Array(relayData);
899
+ else
900
+ return 0;
901
+ if (!ip || !portNum)
902
+ return 0;
903
+ callbacks.sendDataToRelay(relayData, ip, portNum);
904
+ return relayData.byteLength;
905
+ });
906
+ }
907
+ WasmEngine.#globalCallbacksRegistered = true;
908
+ };
909
+ #requireModule = (name) => {
910
+ const preDefinedModules = {
911
+ Promise,
912
+ WAWebVoipWebWasmWorkerResource: {
913
+ resourcePath: resolveWorkerScriptPath(),
914
+ name: "WAWebVoipWebWasmWorker",
915
+ },
916
+ WorkerBundleResource: {
917
+ createDedicatedWebWorker: (resource) => {
918
+ const scriptPath = resource?.resourcePath && fs.existsSync(resource.resourcePath)
919
+ ? resource.resourcePath
920
+ : resolveWorkerScriptPath();
921
+ const worker = new Worker(scriptPath, {
922
+ stdout: true, stderr: true,
923
+ workerData: {
924
+ wasmPath: this.#config.wasmPath,
925
+ wasmBinary: this.#config.wasmBinary,
926
+ workerModulesCode: this.#workerModulesCode,
927
+ loaderCode: this.#loaderCode,
928
+ loaderModuleName: this.#config.loaderModuleName,
929
+ resourcesPath: this.#config.resourcesPath,
930
+ storageDir: this.#config.storageDir,
931
+ enableLogs: this.#config.enableLogs,
932
+ },
933
+ });
934
+ worker.stdout?.on("data", () => { });
935
+ worker.stderr?.on("data", filterWorkerStderr);
936
+ this.#jsWorkers.add(worker);
937
+ worker.on("exit", () => this.#jsWorkers.delete(worker));
938
+ return worker;
939
+ },
940
+ },
941
+ WorkerClient: { init: () => { } },
942
+ WorkerMessagePort: {
943
+ WorkerMessagePort: NodeWorkerMessagePort,
944
+ CastWorkerMessagePort: (w) => w,
945
+ WorkerSyncedMessagePort: NodeWorkerMessagePort,
946
+ },
947
+ bx: Object.assign((id) => String(id), { getURL: () => "" }),
948
+ HasteSupportData: { handle: () => { } },
949
+ ServiceWorkerDynamicModules: { handle: () => { } },
950
+ WhatsAppWebServiceWorker: { default: true },
951
+ WAWebLogger: { initializeWAWebLogger: () => { } },
952
+ WAWebSw: { initHandlers: () => { } },
953
+ WAWebWamRuntimeProvider: { setWamRuntime: () => { } },
954
+ WAWebWamWorkerInterface: { commit: () => { }, set: () => { } },
955
+ ServerJSDefine: { handleDefine: () => { } },
956
+ ix: { add: () => { } },
957
+ MetaConfigMap: { add: () => { } },
958
+ QPLHasteSupportDataStorage: { default: { add: () => { }, get: () => null } },
959
+ getFalcoLogPolicy_DO_NOT_USE: { add: () => { } },
960
+ gkx: { add: () => { } },
961
+ justknobx: { add: () => { } },
962
+ qex: { add: () => { } },
963
+ };
964
+ if (preDefinedModules[name])
965
+ return preDefinedModules[name];
966
+ const mod = this.#moduleRegistry.get(name);
967
+ if (!mod)
968
+ return {};
969
+ if (mod.exports !== undefined)
970
+ return mod.exports;
971
+ const requireFn = this.#requireModule;
972
+ const normalizeModuleResult = (value) => {
973
+ if (value && typeof value === "object" && "exports" in value && Object.keys(value).length === 1) {
974
+ return value.exports;
975
+ }
976
+ return value;
977
+ };
978
+ const importDefaultFn = (dep) => {
979
+ const v = requireFn(dep);
980
+ return v && v.__esModule ? v.default : v;
981
+ };
982
+ const importAllFn = (dep) => {
983
+ const v = requireFn(dep);
984
+ if (v == null)
985
+ return { default: v };
986
+ if (v.__esModule)
987
+ return v;
988
+ if (typeof v !== "object" && typeof v !== "function")
989
+ return { default: v };
990
+ const ns = {};
991
+ for (const key of Object.keys(v))
992
+ ns[key] = v[key];
993
+ ns.default = v;
994
+ return ns;
995
+ };
996
+ const tryMetro = () => {
997
+ const module = { exports: {} };
998
+ mod.factory(this.#vmContext ?? globalThis, requireFn, importDefaultFn, importAllFn, null, module, module.exports);
999
+ return normalizeModuleResult(module.exports);
1000
+ };
1001
+ const tryLegacy = () => {
1002
+ const exports = {};
1003
+ const module = { exports };
1004
+ const resolvedDeps = mod.deps.map((dep) => requireFn(dep));
1005
+ mod.factory(this.#vmContext ?? globalThis, requireFn, requireFn, requireFn, module, exports, ...resolvedDeps);
1006
+ return normalizeModuleResult(module.exports);
1007
+ };
1008
+ let result = {};
1009
+ let metroError = null;
1010
+ try {
1011
+ result = tryMetro();
1012
+ }
1013
+ catch (e) {
1014
+ metroError = e;
1015
+ }
1016
+ if (metroError != null || (result && typeof result === "object" && Object.keys(result).length === 0)) {
1017
+ try {
1018
+ const legacyResult = tryLegacy();
1019
+ if (typeof legacyResult === "function" || (legacyResult && Object.keys(legacyResult).length > 0)) {
1020
+ result = legacyResult;
1021
+ }
1022
+ }
1023
+ catch { }
1024
+ }
1025
+ mod.exports = result;
1026
+ return result;
1027
+ };
1028
+ #createVMContext = (memory) => {
1029
+ const callbacks = this.#config.callbacks ?? {};
1030
+ const wasmCallbacks = {
1031
+ onVoipReady: () => {
1032
+ this.#voipReadyResolver?.();
1033
+ callbacks.onVoipReady?.();
1034
+ },
1035
+ onSignalingXmpp: (data) => callbacks.onSignalingXmpp?.(data?.peerJid, data?.callId, data?.xmlPayload),
1036
+ onCallEvent: (data) => callbacks.onCallEvent?.(data?.eventType, data?.eventDataJson),
1037
+ sendDataToRelay: (data) => callbacks.sendDataToRelay?.(data?.data, data?.ip, data?.port),
1038
+ loggingCallback: (data) => {
1039
+ if (!this.#config.enableLogs)
1040
+ return;
1041
+ const level = data?.level;
1042
+ const msg = data?.message ?? "";
1043
+ const mapped = level === 1 ? "error" : level === 2 ? "warn" : level === 3 ? "log" : "debug";
1044
+ callbacks.onLog?.(mapped, msg);
1045
+ },
1046
+ initCaptureDriverJS: (data) => {
1047
+ callbacks.onAudioCaptureInit?.({
1048
+ sampleRate: data?.sample_rate, channels: data?.channels,
1049
+ bitsPerSample: data?.bits_per_sample, framesPerChunk: data?.frames_per_chunk,
1050
+ });
1051
+ return 0;
1052
+ },
1053
+ startCaptureJS: () => { callbacks.onAudioCaptureStart?.(); return 0; },
1054
+ stopCaptureJS: () => { callbacks.onAudioCaptureStop?.(); return 0; },
1055
+ initPlaybackDriverJS: (data) => {
1056
+ callbacks.onAudioPlaybackInit?.({
1057
+ sampleRate: data?.sample_rate, channels: data?.channels,
1058
+ bitsPerSample: data?.bits_per_sample, framesPerChunk: data?.frames_per_chunk,
1059
+ });
1060
+ return 0;
1061
+ },
1062
+ startPlaybackJS: () => {
1063
+ callbacks.onAudioPlaybackStart?.();
1064
+ this.#startAudioPlaybackLoop();
1065
+ return 0;
1066
+ },
1067
+ stopPlaybackJS: () => {
1068
+ this.#stopAudioPlaybackLoop();
1069
+ callbacks.onAudioPlaybackStop?.();
1070
+ return 0;
1071
+ },
1072
+ startVideoCaptureJS: (data) => {
1073
+ callbacks.onVideoCaptureStart?.(normalizeVideoCaptureConfig(data));
1074
+ return 0;
1075
+ },
1076
+ stopVideoCaptureJS: () => {
1077
+ callbacks.onVideoCaptureStop?.();
1078
+ return 0;
1079
+ },
1080
+ startDesktopCaptureJS: (data) => {
1081
+ callbacks.onDesktopCaptureStart?.(normalizeVideoCaptureConfig(data));
1082
+ return 0;
1083
+ },
1084
+ stopDesktopCaptureJS: () => {
1085
+ callbacks.onDesktopCaptureStop?.();
1086
+ return 0;
1087
+ },
1088
+ dataChannelStateCallback: () => 0,
1089
+ getBrowserAudioProcessingStatus: () => 7,
1090
+ getBweModelPath: () => null,
1091
+ videoFrameConsumed: () => {
1092
+ callbacks.onVideoFrameConsumed?.();
1093
+ return 0;
1094
+ },
1095
+ cryptoHkdfExtractWithSaltAndExpand: (data) => {
1096
+ const key = toByteArray(data?.key_);
1097
+ const salt = data?.salt_ ? toByteArray(data.salt_) : new Uint8Array(0);
1098
+ const info = toByteArray(data?.info_);
1099
+ const length = data?.length ?? 32;
1100
+ return callbacks.cryptoHkdf?.(key, salt, info, length) ?? new Uint8Array(length);
1101
+ },
1102
+ hmacSha256KeyGenerator: (data) => {
1103
+ const hmacData = new Uint8Array(data?.data_ ?? []);
1104
+ const hmacKey = new Uint8Array(data?.key_ ?? []);
1105
+ return callbacks.hmacSha256?.(hmacData, hmacKey) ?? new Uint8Array(32);
1106
+ },
1107
+ isParticipantKnownContact: () => true,
1108
+ getPersistentDirectoryPath: () => {
1109
+ const dir = this.#config.storageDir;
1110
+ try {
1111
+ if (!fs.existsSync(dir))
1112
+ fs.mkdirSync(dir, { recursive: true });
1113
+ }
1114
+ catch { }
1115
+ return dir;
1116
+ },
1117
+ };
1118
+ const __d = (name, deps, factory) => {
1119
+ this.#moduleRegistry.set(name, { deps, factory, exports: undefined });
1120
+ };
1121
+ const babelHelpers = {
1122
+ extends: Object.assign,
1123
+ inheritsLoose: (sub, sup) => {
1124
+ sub.prototype = Object.create(sup.prototype);
1125
+ sub.prototype.constructor = sub;
1126
+ sub.__proto__ = sup;
1127
+ },
1128
+ objectWithoutPropertiesLoose: (source, excluded) => {
1129
+ if (source == null)
1130
+ return {};
1131
+ const target = {};
1132
+ for (const key of Object.keys(source)) {
1133
+ if (excluded.indexOf(key) >= 0)
1134
+ continue;
1135
+ target[key] = source[key];
1136
+ }
1137
+ return target;
1138
+ },
1139
+ taggedTemplateLiteralLoose: (strings, raw) => {
1140
+ if (!raw)
1141
+ raw = strings.slice(0);
1142
+ strings.raw = raw;
1143
+ return strings;
1144
+ },
1145
+ wrapNativeSuper: (Class) => Class,
1146
+ };
1147
+ const addRunDependency = (dep) => {
1148
+ if (dep === "loading-workers" && this.#workersLoadedCount >= PTHREAD_POOL_SIZE) {
1149
+ setImmediate(() => this.#removeRunDependencyCallback?.(dep));
1150
+ }
1151
+ };
1152
+ const removeRunDependency = (_dep) => { };
1153
+ this.#removeRunDependencyCallback = removeRunDependency;
1154
+ const webCrypto = {
1155
+ getRandomValues: (arr) => {
1156
+ if (!arr || !ArrayBuffer.isView(arr)) {
1157
+ throw new TypeError("crypto.getRandomValues expects a TypedArray");
1158
+ }
1159
+ const bytes = Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
1160
+ randomFillSync(bytes);
1161
+ return arr;
1162
+ },
1163
+ };
1164
+ const selfObj = {
1165
+ __swData: { dynamic_data: { hsdp: {}, dynamic_modules: [] } },
1166
+ WhatsAppVoipWasmCallbacks: wasmCallbacks,
1167
+ WhatsAppVoipWasmWorkerCompatibleCallbacks: wasmCallbacks,
1168
+ crypto: webCrypto,
1169
+ };
1170
+ selfObj.self = selfObj;
1171
+ selfObj.window = selfObj;
1172
+ selfObj.globalThis = selfObj;
1173
+ if (typeof global !== "undefined") {
1174
+ global.WhatsAppVoipWasmCallbacks = wasmCallbacks;
1175
+ global.WhatsAppVoipWasmWorkerCompatibleCallbacks = wasmCallbacks;
1176
+ }
1177
+ const context = vm.createContext({
1178
+ self: selfObj, globalThis: selfObj, global: selfObj, window: selfObj,
1179
+ console, setTimeout, setInterval, clearTimeout, clearInterval,
1180
+ queueMicrotask, performance, babelHelpers, __d,
1181
+ require: this.#requireModule,
1182
+ addRunDependency, removeRunDependency,
1183
+ WebAssembly, SharedArrayBuffer,
1184
+ Atomics: this.#createAtomicsWrapper(memory),
1185
+ Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array,
1186
+ Float32Array, Float64Array, BigInt64Array, BigUint64Array,
1187
+ ArrayBuffer, DataView, Error, TypeError, RangeError, Promise,
1188
+ Map, Set, WeakMap, WeakSet, Symbol, Object, Array, String, Number,
1189
+ Boolean, Math, Date, JSON, RegExp, Function, Proxy, Reflect,
1190
+ crypto: webCrypto,
1191
+ WhatsAppVoipWasmCallbacks: wasmCallbacks,
1192
+ WhatsAppVoipWasmWorkerCompatibleCallbacks: wasmCallbacks,
1193
+ navigator: {
1194
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
1195
+ hardwareConcurrency: 4,
1196
+ },
1197
+ process: undefined,
1198
+ document: { currentScript: null },
1199
+ location: { href: "file:///wasm" },
1200
+ Worker: class {
1201
+ constructor() { }
1202
+ postMessage() { }
1203
+ terminate() { }
1204
+ addEventListener() { }
1205
+ },
1206
+ fetch: async () => { throw new Error("fetch not supported"); },
1207
+ XMLHttpRequest: class {
1208
+ open() { }
1209
+ send() { }
1210
+ setRequestHeader() { }
1211
+ },
1212
+ Blob: class {
1213
+ constructor() { }
1214
+ },
1215
+ URL: { createObjectURL: () => "blob:fake", revokeObjectURL: () => { } },
1216
+ Image: class {
1217
+ src = "";
1218
+ onload = null;
1219
+ onerror = null;
1220
+ },
1221
+ Audio: class {
1222
+ src = "";
1223
+ addEventListener() { }
1224
+ },
1225
+ __NODE_PTHREAD: {
1226
+ getUnusedWorker: () => {
1227
+ if (this.#unusedWorkers.length === 0)
1228
+ return null;
1229
+ const worker = this.#unusedWorkers.pop();
1230
+ this.#runningWorkers.push(worker);
1231
+ return worker;
1232
+ },
1233
+ returnWorkerToPool: (worker) => {
1234
+ const idx = this.#runningWorkers.indexOf(worker);
1235
+ if (idx >= 0) {
1236
+ this.#runningWorkers.splice(idx, 1);
1237
+ this.#unusedWorkers.push(worker);
1238
+ }
1239
+ },
1240
+ spawnThread: (params) => {
1241
+ const worker = this.#unusedWorkers.pop();
1242
+ if (!worker)
1243
+ return 6;
1244
+ this.#runningWorkers.push(worker);
1245
+ this.#pthreads[params.pthread_ptr] = worker;
1246
+ worker.pthread_ptr = params.pthread_ptr;
1247
+ const pthreadTable = this.#instance?.PThread?.pthreads;
1248
+ if (pthreadTable)
1249
+ pthreadTable[params.pthread_ptr] = worker;
1250
+ worker.postMessage({
1251
+ cmd: "run",
1252
+ start_routine: params.startRoutine,
1253
+ arg: params.arg,
1254
+ pthread_ptr: params.pthread_ptr,
1255
+ });
1256
+ return 0;
1257
+ },
1258
+ unusedWorkersCount: () => this.#unusedWorkers.length,
1259
+ runningWorkersCount: () => this.#runningWorkers.length,
1260
+ },
1261
+ __IS_NODE_PTHREAD_ENV: true,
1262
+ });
1263
+ context.self = context;
1264
+ context.globalThis = context;
1265
+ context.global = context;
1266
+ context.window = context;
1267
+ return context;
1268
+ };
1269
+ #createAtomicsWrapper = (_memory) => {
1270
+ const atomicsWrapper = {
1271
+ add: Atomics.add.bind(Atomics),
1272
+ and: Atomics.and.bind(Atomics),
1273
+ compareExchange: Atomics.compareExchange.bind(Atomics),
1274
+ exchange: Atomics.exchange.bind(Atomics),
1275
+ isLockFree: Atomics.isLockFree.bind(Atomics),
1276
+ load: Atomics.load.bind(Atomics),
1277
+ or: Atomics.or.bind(Atomics),
1278
+ store: Atomics.store.bind(Atomics),
1279
+ sub: Atomics.sub.bind(Atomics),
1280
+ xor: Atomics.xor.bind(Atomics),
1281
+ notify: (typedArray, index, count) => {
1282
+ try {
1283
+ return Atomics.notify(typedArray, index, count);
1284
+ }
1285
+ catch (e) {
1286
+ if (e?.message?.includes("futex_wake") || e?.message?.includes("main_browser_thread"))
1287
+ return 0;
1288
+ throw e;
1289
+ }
1290
+ },
1291
+ waitAsync: Atomics.waitAsync
1292
+ ? Atomics.waitAsync.bind(Atomics)
1293
+ : () => ({ async: true, value: Promise.resolve("ok") }),
1294
+ wait: (typedArray, index, value, timeout) => {
1295
+ const currentValue = Atomics.load(typedArray, index);
1296
+ if (currentValue !== value)
1297
+ return "not-equal";
1298
+ if (timeout !== undefined && timeout <= 0)
1299
+ return "timed-out";
1300
+ return "timed-out";
1301
+ },
1302
+ [Symbol.toStringTag]: "Atomics",
1303
+ };
1304
+ return atomicsWrapper;
1305
+ };
1306
+ }
1307
+
1308
+ export default WasmEngine;