@nerxa/socketon 0.0.0-stage → 1.21.1

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