libzapitu 1.0.0-alpha.25 → 1.0.0-alpha.26

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.
@@ -77,8 +77,8 @@ function proxyCallback(socketId, key, log, ...args) {
77
77
  // ---------------------------------------------------------------------------
78
78
  /**
79
79
  * Recursively clone a value for postMessage, replacing non-cloneable types
80
- * (Error, Function) with plain serializable representations and converting
81
- * protobufjs message instances to JSON.
80
+ * (Error, Function) with plain serializable representations, preserving
81
+ * built-in value objects, and converting protobufjs message instances to JSON.
82
82
  *
83
83
  * Protobuf messages (e.g. proto.Message, proto.WebMessageInfo) carry a
84
84
  * toJSON() method that serializes byte fields as base64 strings and 64-bit
@@ -90,11 +90,42 @@ function proxyCallback(socketId, key, log, ...args) {
90
90
  */
91
91
  function serializeForPostMessage(value, seen = new WeakSet()) {
92
92
  if (value instanceof Error) {
93
+ // Boom carries critical metadata (statusCode, output, data, isServer).
94
+ // Preserve it so the parent can reconstruct a real Boom instance.
95
+ if (value.isBoom) {
96
+ return {
97
+ __error__: true,
98
+ __boom__: true,
99
+ message: value.message,
100
+ name: value.name,
101
+ stack: value.stack,
102
+ data: value.data,
103
+ output: value.output,
104
+ isServer: value.isServer
105
+ };
106
+ }
93
107
  return { __error__: true, message: value.message, name: value.name, stack: value.stack };
94
108
  }
95
109
  if (typeof value === 'function') {
96
110
  return '__fn__';
97
111
  }
112
+ // Preserve built-in value objects that structured clone handles, but tag
113
+ // them so the parent can reconstruct the exact same runtime type.
114
+ if (value instanceof Date) {
115
+ return { __date__: true, value: value.toISOString() };
116
+ }
117
+ if (value instanceof RegExp) {
118
+ return { __regexp__: true, source: value.source, flags: value.flags };
119
+ }
120
+ if (value instanceof URL) {
121
+ return { __url__: true, href: value.href };
122
+ }
123
+ if (value instanceof Map) {
124
+ return { __map__: true, entries: serializeForPostMessage(Array.from(value.entries()), seen) };
125
+ }
126
+ if (value instanceof Set) {
127
+ return { __set__: true, entries: serializeForPostMessage(Array.from(value.values()), seen) };
128
+ }
98
129
  if (value !== null && typeof value === 'object') {
99
130
  if (seen.has(value))
100
131
  return '[Circular]';
@@ -214,6 +245,8 @@ function createSocket(socketId, rawConfig) {
214
245
  log.info('socket created successfully');
215
246
  // Send user and authState to the parent when they become available.
216
247
  // These are needed for wsocket.user and wsocket.authState on the proxy side.
248
+ // authState.keys contains forwarding functions, so we must serialize the
249
+ // info before postMessage or the whole message is dropped.
217
250
  const sendSocketInfo = () => {
218
251
  try {
219
252
  const info = {};
@@ -222,7 +255,11 @@ function createSocket(socketId, rawConfig) {
222
255
  if (sock.authState)
223
256
  info.authState = sock.authState;
224
257
  if (Object.keys(info).length > 0) {
225
- worker_threads_1.parentPort.postMessage({ type: 'socket-info', socketId, info });
258
+ worker_threads_1.parentPort.postMessage({
259
+ type: 'socket-info',
260
+ socketId,
261
+ info: serializeForPostMessage(info)
262
+ });
226
263
  }
227
264
  }
228
265
  catch (_) {
@@ -36,6 +36,7 @@ const stream_1 = require("stream");
36
36
  const util_1 = require("util");
37
37
  const os_2 = require("os");
38
38
  const long_1 = __importDefault(require("long"));
39
+ const boom_1 = require("@hapi/boom");
39
40
  const WAProto_1 = require("../../WAProto");
40
41
  const pipelineAsync = (0, util_1.promisify)(stream_1.pipeline);
41
42
  // ---------------------------------------------------------------------------
@@ -254,6 +255,7 @@ const PROTOBUF_TYPE_REGISTRY = buildProtobufTypeRegistry(WAProto_1.proto);
254
255
  * to direct mode (base64 strings for bytes, strings for 64-bit integers).
255
256
  */
256
257
  function revivePostMessage(value) {
258
+ var _a;
257
259
  // After structured clone, Buffer subclasses become plain Uint8Arrays.
258
260
  // Restore them to Buffer so downstream code gets the same type as in
259
261
  // direct mode for non-protobuf binary fields.
@@ -262,11 +264,42 @@ function revivePostMessage(value) {
262
264
  }
263
265
  if (value !== null && typeof value === 'object') {
264
266
  if (value.__error__) {
267
+ // Boom errors carry status codes, payloads, and extra data. Rebuild
268
+ // a real Boom instance so callers can inspect err.output.statusCode.
269
+ if (value.__boom__) {
270
+ const boom = new boom_1.Boom(value.message, {
271
+ statusCode: (_a = value.output) === null || _a === void 0 ? void 0 : _a.statusCode,
272
+ data: value.data
273
+ });
274
+ // Restore the exact output payload/headers from the worker so the
275
+ // status code and error name match direct mode.
276
+ if (value.output) {
277
+ Object.assign(boom.output, value.output);
278
+ }
279
+ boom.stack = value.stack || boom.stack;
280
+ return boom;
281
+ }
265
282
  const err = new Error(value.message);
266
283
  err.name = value.name;
267
284
  err.stack = value.stack;
268
285
  return err;
269
286
  }
287
+ // Revive built-in value objects tagged by the child.
288
+ if (value.__date__) {
289
+ return new Date(value.value);
290
+ }
291
+ if (value.__regexp__) {
292
+ return new RegExp(value.source, value.flags);
293
+ }
294
+ if (value.__url__) {
295
+ return new URL(value.href);
296
+ }
297
+ if (value.__map__) {
298
+ return new Map(revivePostMessage(value.entries));
299
+ }
300
+ if (value.__set__) {
301
+ return new Set(revivePostMessage(value.entries));
302
+ }
270
303
  // Revive protobuf messages tagged by the child. fromObject() will
271
304
  // recursively recreate nested protobuf instances and convert base64
272
305
  // strings back into Buffer instances.
@@ -279,7 +312,7 @@ function revivePostMessage(value) {
279
312
  try {
280
313
  return type.fromObject(copy);
281
314
  }
282
- catch (_a) {
315
+ catch (_b) {
283
316
  // Fall back to the plain JSON object if fromObject fails;
284
317
  // downstream code will see base64 strings instead of Buffers.
285
318
  }
@@ -292,7 +325,7 @@ function revivePostMessage(value) {
292
325
  return new long_1.default(value.low, value.high, value.unsigned);
293
326
  }
294
327
  if (Array.isArray(value)) {
295
- // Arrays: recurse to revive any Error sentinels / Longs / Uint8Arrays / protobuf messages inside
328
+ // Arrays: recurse to revive any Error sentinels / Longs / Uint8Arrays / protobuf messages / built-ins inside
296
329
  let changed = false;
297
330
  const result = value.map(v => {
298
331
  const revived = revivePostMessage(v);
@@ -303,7 +336,7 @@ function revivePostMessage(value) {
303
336
  return changed ? result : value;
304
337
  }
305
338
  // Plain objects: only recurse if they might contain __error__ sentinels,
306
- // Long-like objects, Uint8Arrays, or protobuf markers.
339
+ // Long-like objects, Uint8Arrays, protobuf markers, or built-in tags.
307
340
  if (value.constructor === Object || value.constructor === undefined) {
308
341
  let changed = false;
309
342
  const result = {};
@@ -515,7 +548,12 @@ async function handleCallbackCall(slot, socketId, msg) {
515
548
  try {
516
549
  log === null || log === void 0 ? void 0 : log.debug({ keystoreMethod: method, argCount: args.length }, 'invoking keystore method');
517
550
  const result = await keystore[method](...args);
518
- slot.worker.postMessage({ type: 'callback-result', socketId, id, result });
551
+ slot.worker.postMessage({
552
+ type: 'callback-result',
553
+ socketId,
554
+ id,
555
+ result: deepStripFunctions(result)
556
+ });
519
557
  }
520
558
  catch (err) {
521
559
  log === null || log === void 0 ? void 0 : log.error({ err, keystoreMethod: method }, 'keystore method threw error');
@@ -543,7 +581,12 @@ async function handleCallbackCall(slot, socketId, msg) {
543
581
  try {
544
582
  log === null || log === void 0 ? void 0 : log.debug({ callbackKey: key, argCount: args.length }, 'invoking proxied callback');
545
583
  const result = await fn(...args);
546
- slot.worker.postMessage({ type: 'callback-result', socketId, id, result });
584
+ slot.worker.postMessage({
585
+ type: 'callback-result',
586
+ socketId,
587
+ id,
588
+ result: deepStripFunctions(result)
589
+ });
547
590
  }
548
591
  catch (err) {
549
592
  log === null || log === void 0 ? void 0 : log.error({ err, callbackKey: key }, 'proxied callback threw error');
@@ -616,8 +659,30 @@ async function drainPool() {
616
659
  * Recursively clone a value, replacing all functions with the sentinel
617
660
  * string '__proxy_fn__'. This ensures the config can be sent via
618
661
  * postMessage (structured clone).
662
+ *
663
+ * Built-in value objects (Date, RegExp, URL, Map, Set) are preserved in
664
+ * their serializable tagged form so they survive the boundary instead of
665
+ * being reduced to empty objects by Object.keys().
619
666
  */
620
667
  function deepStripFunctions(value, seen = new WeakSet()) {
668
+ if (typeof value === 'function') {
669
+ return '__proxy_fn__';
670
+ }
671
+ if (value instanceof Date) {
672
+ return { __date__: true, value: value.toISOString() };
673
+ }
674
+ if (value instanceof RegExp) {
675
+ return { __regexp__: true, source: value.source, flags: value.flags };
676
+ }
677
+ if (value instanceof URL) {
678
+ return { __url__: true, href: value.href };
679
+ }
680
+ if (value instanceof Map) {
681
+ return { __map__: true, entries: deepStripFunctions(Array.from(value.entries()), seen) };
682
+ }
683
+ if (value instanceof Set) {
684
+ return { __set__: true, entries: deepStripFunctions(Array.from(value.values()), seen) };
685
+ }
621
686
  if (typeof value === 'function') {
622
687
  return '__proxy_fn__';
623
688
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libzapitu",
3
- "version": "1.0.0-alpha.25",
3
+ "version": "1.0.0-alpha.26",
4
4
  "description": "A WebSockets library for interacting with WhatsApp Web",
5
5
  "keywords": [
6
6
  "whatsapp",