@oxidezap/baileyrs 0.0.35 → 0.1.0

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.
@@ -10,8 +10,11 @@ import type { SocketContext } from './types.js';
10
10
  * it across the delete and restore it on a fresh contextInfo.
11
11
  *
12
12
  * Mutates `msg` in place.
13
+ *
14
+ * `contentType` is a parameter so the send path can hand over the type it has
15
+ * already resolved rather than have it scanned out of `msg` a second time.
13
16
  */
14
- export declare function stripContextInfoForBridge(msg: WAMessageContent): void;
17
+ export declare function stripContextInfoForBridge(msg: WAMessageContent, contentType?: keyof WAProto.IMessage | undefined): void;
15
18
  export declare const makeMessageMethods: (ctx: SocketContext) => {
16
19
  sendMessage: (jid: string, content: AnyMessageContent, options?: Omit<MessageGenerationOptions, 'waClient' | 'logger' | 'userJid' | 'mediaInNote'>) => Promise<WAMessage>;
17
20
  updateMediaMessage: (message: WAMessage) => Promise<WAMessage>;
@@ -22,9 +22,11 @@ function getMediaContent(content) {
22
22
  * it across the delete and restore it on a fresh contextInfo.
23
23
  *
24
24
  * Mutates `msg` in place.
25
+ *
26
+ * `contentType` is a parameter so the send path can hand over the type it has
27
+ * already resolved rather than have it scanned out of `msg` a second time.
25
28
  */
26
- export function stripContextInfoForBridge(msg) {
27
- const contentType = getContentType(msg);
29
+ export function stripContextInfoForBridge(msg, contentType = getContentType(msg)) {
28
30
  const pinAddOnDuration = contentType === 'pinInChatMessage' ? msg.messageContextInfo?.messageAddOnDurationInSecs : undefined;
29
31
  delete msg.messageContextInfo;
30
32
  if (pinAddOnDuration !== undefined && pinAddOnDuration !== null) {
@@ -85,7 +87,7 @@ export const makeMessageMethods = (ctx) => ({
85
87
  return fullMsg;
86
88
  }
87
89
  }
88
- stripContextInfoForBridge(msg);
90
+ stripContextInfoForBridge(msg, contentType);
89
91
  let msgId;
90
92
  const msgBytes = encodeProto('Message', msg);
91
93
  if (jid === 'status@broadcast' && options?.statusJidList?.length) {
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Reports the terminal `connection.update { close }` — exactly once, after
3
+ * teardown, and never silently not at all.
4
+ *
5
+ * That sentence is the whole contract this branch sells, and getting it wrong
6
+ * has two opposite failure modes, both bad:
7
+ *
8
+ * - **Not reported.** The consumer's handler never runs, so it never builds a
9
+ * replacement socket. A bot offline with nothing in its logs — the original
10
+ * bug this branch exists to fix.
11
+ * - **Reported early, or twice.** The replacement socket overlaps the old
12
+ * one's auth-store flush and `free()`, or every listener sees two terminal
13
+ * notifications for one socket and a handler that cleans up on close loops.
14
+ *
15
+ * Keeping both away used to be inline logic split across the dispatcher hook
16
+ * and `logout()`, sharing a counter and a promise. Nine separate bugs came out
17
+ * of that in review — a publish that could never run, a throwing listener
18
+ * taking the process down, `logout()` resolving before the close it caused,
19
+ * the watchdog not releasing its waiters, a suppression check that also
20
+ * matched non-terminal teardown, a fallback that did not count itself. Every
21
+ * one was a different way of answering the same question, so it is one object
22
+ * now, with the answer in one place.
23
+ */
24
+ import type { ILogger } from '../Utils/logger.js';
25
+ /**
26
+ * How long teardown may run before the close is reported anyway.
27
+ *
28
+ * A deliberate trade of one guarantee for the other: past this point the close
29
+ * goes out with teardown still running, because losing the event entirely is
30
+ * the worse of the two failures. Teardown takes milliseconds in practice, so
31
+ * reaching this means a consumer end handler or a store flush never settled —
32
+ * and the error logged alongside says exactly that. Generous rather than
33
+ * tight, since firing early is the harmful direction.
34
+ */
35
+ export declare const TERMINAL_CLOSE_PUBLISH_TIMEOUT_MS = 60000;
36
+ export interface TerminalCloseReporter {
37
+ /**
38
+ * Run `teardown`, then publish. Used by the dispatcher, which learns about
39
+ * the close first and hands over the publishing so the socket can finish
40
+ * releasing its resources before a consumer can react.
41
+ *
42
+ * Never rejects and never leaves `publish` uncalled: teardown failures are
43
+ * logged, a throwing listener is contained, and a teardown that hangs is
44
+ * cut short by the watchdog.
45
+ */
46
+ reportAfter: (teardown: () => Promise<void>, publish: () => void) => void;
47
+ /**
48
+ * Publish immediately, for a close nothing else will announce — a `logout()`
49
+ * with no live client, or one whose `logout()` threw before the bridge
50
+ * dispatched anything.
51
+ */
52
+ reportNow: (publish: () => void) => void;
53
+ /**
54
+ * Whether a terminal close has been *claimed* — reported, or reported-and-
55
+ * still-tearing-down. Not "published": `reportAfter` publishes only once
56
+ * teardown finishes, so a check keyed on delivery would see `false` right
57
+ * after the bridge announced the logout and let `logout()` add a second
58
+ * close of its own.
59
+ *
60
+ * `logout()` uses this rather than "is the socket closing", which is also
61
+ * true for a plain `end()` — and those report nothing, so keying off them
62
+ * would let a logout racing one finish with no close at all.
63
+ */
64
+ hasReported: () => boolean;
65
+ /**
66
+ * Settles once the most recent report has been published — the moment the
67
+ * consumer sees it, not the moment teardown finishes, so a waiter is not
68
+ * left hanging when the watchdog is what released the event.
69
+ *
70
+ * Resolves immediately when nothing has been reported.
71
+ */
72
+ published: () => Promise<void>;
73
+ }
74
+ export declare const makeTerminalCloseReporter: (opts: {
75
+ logger: ILogger;
76
+ /** Overridable for tests; production uses the constant above. */
77
+ publishTimeoutMs?: number;
78
+ }) => TerminalCloseReporter;
79
+ //# sourceMappingURL=terminal-close-reporter.d.ts.map
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Reports the terminal `connection.update { close }` — exactly once, after
3
+ * teardown, and never silently not at all.
4
+ *
5
+ * That sentence is the whole contract this branch sells, and getting it wrong
6
+ * has two opposite failure modes, both bad:
7
+ *
8
+ * - **Not reported.** The consumer's handler never runs, so it never builds a
9
+ * replacement socket. A bot offline with nothing in its logs — the original
10
+ * bug this branch exists to fix.
11
+ * - **Reported early, or twice.** The replacement socket overlaps the old
12
+ * one's auth-store flush and `free()`, or every listener sees two terminal
13
+ * notifications for one socket and a handler that cleans up on close loops.
14
+ *
15
+ * Keeping both away used to be inline logic split across the dispatcher hook
16
+ * and `logout()`, sharing a counter and a promise. Nine separate bugs came out
17
+ * of that in review — a publish that could never run, a throwing listener
18
+ * taking the process down, `logout()` resolving before the close it caused,
19
+ * the watchdog not releasing its waiters, a suppression check that also
20
+ * matched non-terminal teardown, a fallback that did not count itself. Every
21
+ * one was a different way of answering the same question, so it is one object
22
+ * now, with the answer in one place.
23
+ */
24
+ /**
25
+ * How long teardown may run before the close is reported anyway.
26
+ *
27
+ * A deliberate trade of one guarantee for the other: past this point the close
28
+ * goes out with teardown still running, because losing the event entirely is
29
+ * the worse of the two failures. Teardown takes milliseconds in practice, so
30
+ * reaching this means a consumer end handler or a store flush never settled —
31
+ * and the error logged alongside says exactly that. Generous rather than
32
+ * tight, since firing early is the harmful direction.
33
+ */
34
+ export const TERMINAL_CLOSE_PUBLISH_TIMEOUT_MS = 60000;
35
+ export const makeTerminalCloseReporter = (opts) => {
36
+ const { logger } = opts;
37
+ const publishTimeoutMs = opts.publishTimeoutMs ?? TERMINAL_CLOSE_PUBLISH_TIMEOUT_MS;
38
+ /** Claims, not deliveries — see `hasReported`. */
39
+ let claimed = 0;
40
+ let publishedPromise;
41
+ /** One publish per claim, whatever gets there first, and never throwing. */
42
+ const makeOnce = (publish, settle) => {
43
+ let done = false;
44
+ return () => {
45
+ if (done)
46
+ return;
47
+ done = true;
48
+ try {
49
+ publish();
50
+ }
51
+ catch (err) {
52
+ // `publish` emits on the consumer's bus. Letting this escape
53
+ // would surface as an unhandled rejection on a detached chain —
54
+ // process exit under Node's default handler.
55
+ logger.error({ err }, 'connection.update listener threw on the terminal close');
56
+ }
57
+ settle();
58
+ };
59
+ };
60
+ return {
61
+ reportAfter: (teardown, publish) => {
62
+ claimed++;
63
+ let settle;
64
+ publishedPromise = new Promise(resolve => {
65
+ settle = resolve;
66
+ });
67
+ const publishOnce = makeOnce(publish, settle);
68
+ // Deliberately referenced: a pending promise does not keep Node's
69
+ // event loop alive, so an unref'd timer lets a minimal bot exit
70
+ // before it can publish — and the close handler that would have
71
+ // built the replacement never runs, which is what this guards.
72
+ // Cleared the moment teardown settles, so it holds the loop only
73
+ // while one is in flight.
74
+ const watchdog = setTimeout(() => {
75
+ logger.error({ afterMs: publishTimeoutMs }, 'socket teardown is still running; reporting the close anyway');
76
+ publishOnce();
77
+ }, publishTimeoutMs);
78
+ const finish = (err) => {
79
+ clearTimeout(watchdog);
80
+ if (err)
81
+ logger.error({ err }, 'socket teardown failed after a terminal disconnect');
82
+ publishOnce();
83
+ };
84
+ // `teardown()` is called inside the try because it can throw
85
+ // *synchronously*, before returning a promise — `.then` would never
86
+ // run and the close would stay unpublished until the watchdog, or
87
+ // forever if the timer were ever removed. The no-silent-failure
88
+ // promise has to hold for that path too.
89
+ try {
90
+ void teardown().then(() => finish(), finish);
91
+ }
92
+ catch (err) {
93
+ finish(err);
94
+ }
95
+ },
96
+ reportNow: publish => {
97
+ claimed++;
98
+ let settle;
99
+ publishedPromise = new Promise(resolve => {
100
+ settle = resolve;
101
+ });
102
+ makeOnce(publish, settle)();
103
+ },
104
+ hasReported: () => claimed > 0,
105
+ published: () => publishedPromise ?? Promise.resolve()
106
+ };
107
+ };
108
+ //# sourceMappingURL=terminal-close-reporter.js.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Which bridge disconnects end the socket for good.
3
+ *
4
+ * This mirrors one decision that lives in the Rust engine, so keep it honest:
5
+ * `whatsapp-rust` clears `enable_auto_reconnect` and breaks out of its run loop
6
+ * on exactly these, and retries everything else on the WA Web Fibonacci backoff
7
+ * (`client/lifecycle.rs`).
8
+ *
9
+ * The socket layer needs the answer because `WasmWhatsAppClient.run()` returns
10
+ * `void` — it spawns the loop as a background task, so the loop's exit is not
11
+ * observable from JS (`whatsapp_rust_bridge.d.ts`, `run(): void`). Until the
12
+ * bridge exposes loop completion, this table is how the socket knows a client
13
+ * has become dead weight that only `free()` can reclaim.
14
+ *
15
+ * The upstream Baileys contract this buys us: `connection.update { close }`
16
+ * means "this socket is finished, build a new one" — which is what every
17
+ * consumer written against upstream already assumes, because upstream has no
18
+ * auto-reconnect at all. Transient drops therefore never surface as `close`;
19
+ * they surface as `connecting`.
20
+ *
21
+ * Events deliberately absent from the terminal set, and why:
22
+ * - `disconnected` — the engine only dispatches `Event::Disconnected` for an
23
+ * *unexpected* loop exit, and every terminal path sets `expected_disconnect`
24
+ * first, which suppresses it (`client/lifecycle.rs`). So this one is the
25
+ * "engine is retrying" signal — with one exception the dispatcher handles:
26
+ * under `setAutoReconnect(false)` the run loop dispatches `Disconnected`
27
+ * and only *then* tests the flag and breaks out, which makes the very same
28
+ * event terminal. Absence from this list means "not terminal on its own",
29
+ * not "never terminal".
30
+ * - `streamError` — reaches JS only from the engine's catch-all `<stream:error>`
31
+ * branch (unknown code, `<ack/>`, `<xml-not-well-formed>`); the coded ones
32
+ * (401/409/515/516/429/503) dispatch their own events instead. Every case
33
+ * that gets here keeps the connection or recycles it deliberately.
34
+ * - `pairError` — pairing failed, but the engine keeps its loop and re-emits a
35
+ * QR; nothing about the client is dead.
36
+ */
37
+ /** True when the engine will keep retrying after this `<failure>`. */
38
+ export declare const isReconnectableConnectFailure: (reason: number | undefined) => boolean;
39
+ //# sourceMappingURL=terminal-close.d.ts.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Which bridge disconnects end the socket for good.
3
+ *
4
+ * This mirrors one decision that lives in the Rust engine, so keep it honest:
5
+ * `whatsapp-rust` clears `enable_auto_reconnect` and breaks out of its run loop
6
+ * on exactly these, and retries everything else on the WA Web Fibonacci backoff
7
+ * (`client/lifecycle.rs`).
8
+ *
9
+ * The socket layer needs the answer because `WasmWhatsAppClient.run()` returns
10
+ * `void` — it spawns the loop as a background task, so the loop's exit is not
11
+ * observable from JS (`whatsapp_rust_bridge.d.ts`, `run(): void`). Until the
12
+ * bridge exposes loop completion, this table is how the socket knows a client
13
+ * has become dead weight that only `free()` can reclaim.
14
+ *
15
+ * The upstream Baileys contract this buys us: `connection.update { close }`
16
+ * means "this socket is finished, build a new one" — which is what every
17
+ * consumer written against upstream already assumes, because upstream has no
18
+ * auto-reconnect at all. Transient drops therefore never surface as `close`;
19
+ * they surface as `connecting`.
20
+ *
21
+ * Events deliberately absent from the terminal set, and why:
22
+ * - `disconnected` — the engine only dispatches `Event::Disconnected` for an
23
+ * *unexpected* loop exit, and every terminal path sets `expected_disconnect`
24
+ * first, which suppresses it (`client/lifecycle.rs`). So this one is the
25
+ * "engine is retrying" signal — with one exception the dispatcher handles:
26
+ * under `setAutoReconnect(false)` the run loop dispatches `Disconnected`
27
+ * and only *then* tests the flag and breaks out, which makes the very same
28
+ * event terminal. Absence from this list means "not terminal on its own",
29
+ * not "never terminal".
30
+ * - `streamError` — reaches JS only from the engine's catch-all `<stream:error>`
31
+ * branch (unknown code, `<ack/>`, `<xml-not-well-formed>`); the coded ones
32
+ * (401/409/515/516/429/503) dispatch their own events instead. Every case
33
+ * that gets here keeps the connection or recycles it deliberately.
34
+ * - `pairError` — pairing failed, but the engine keeps its loop and re-emits a
35
+ * QR; nothing about the client is dead.
36
+ */
37
+ /**
38
+ * `ConnectFailureReason` wire codes the engine retries — the JS mirror of
39
+ * `ConnectFailureReason::should_reconnect()`, which matches only
40
+ * `InternalServerError | ServiceUnavailable`.
41
+ *
42
+ * A `<failure>` with no reason at all is NOT retried: the engine parses it as
43
+ * `Unknown(0)`, which fails `should_reconnect()`.
44
+ */
45
+ const RECONNECTABLE_CONNECT_FAILURE_REASONS = new Set([
46
+ 500, // InternalServerError
47
+ 503 // ServiceUnavailable
48
+ ]);
49
+ /** True when the engine will keep retrying after this `<failure>`. */
50
+ export const isReconnectableConnectFailure = (reason) => reason !== undefined && RECONNECTABLE_CONNECT_FAILURE_REASONS.has(reason);
51
+ //# sourceMappingURL=terminal-close.js.map
@@ -362,6 +362,37 @@ export const makeEventBuffer = (logger) => {
362
362
  let flushPendingTimeout;
363
363
  ev.on('event', (events) => {
364
364
  for (const event of Object.keys(events)) {
365
+ if (event === 'connection.update') {
366
+ // Delivered listener by listener, unlike every other event.
367
+ // `EventEmitter.emit()` stops at the first listener that throws,
368
+ // so one bad handler would keep the rest — including the app's
369
+ // reconnect handler — from ever seeing a terminal `close`, and
370
+ // the bot would stay offline. This is the lifecycle channel;
371
+ // losing delivery here is the failure mode the socket's whole
372
+ // close contract exists to prevent.
373
+ // `rawListeners`, not `listeners`: the latter unwraps `once()`
374
+ // handlers to the function underneath, so calling that would
375
+ // never run the wrapper that unregisters them and the listener
376
+ // would stay subscribed for every later update. `once` is not on
377
+ // `BaileysEventEmitter` today, so this is unreachable rather than
378
+ // broken — but the two differ only in this respect and the raw
379
+ // one is the correct primitive for calling listeners by hand.
380
+ for (const listener of ev.rawListeners(event)) {
381
+ try {
382
+ // `.call(ev, …)` so `this` is still the emitter, as it
383
+ // would be under `emit()`. A listener declared as a
384
+ // normal function that does `this.off('connection.update', …)`
385
+ // — a common self-removing pattern — would otherwise
386
+ // throw on `undefined` and be swallowed by the catch.
387
+ ;
388
+ listener.call(ev, events[event]);
389
+ }
390
+ catch (err) {
391
+ logger.error({ err, event }, 'connection.update listener threw; continuing with the rest');
392
+ }
393
+ }
394
+ continue;
395
+ }
365
396
  ev.emit(event, events[event]);
366
397
  }
367
398
  });
@@ -57,6 +57,17 @@ export type DownloadMediaMessageContext = {
57
57
  */
58
58
  export declare const downloadMediaMessage: <Type extends 'buffer' | 'stream'>(message: WAMessage, type: Type, options: MediaDownloadOptions, ctx: DownloadMediaMessageContext) => Promise<Type extends "buffer" ? Buffer<ArrayBufferLike> : Readable>;
59
59
  export declare const _registerActiveBridgeClient: (client: WasmWhatsAppClient, logger?: ILogger) => void;
60
+ /**
61
+ * Drop the module-level pointer when `sock.end()` frees the client it points
62
+ * at. Without this the global keeps a strong reference to a freed
63
+ * `WasmWhatsAppClient`, so the next standalone `downloadContentFromMessage()`
64
+ * call reaches into a null wasm pointer and fails with an opaque
65
+ * wasm-bindgen error instead of the actionable "no bridge client" Boom.
66
+ *
67
+ * Identity-checked on purpose: a multi-account host that ends socket A after
68
+ * creating socket B must not clear B's registration.
69
+ */
70
+ export declare const _unregisterActiveBridgeClient: (client: WasmWhatsAppClient) => void;
60
71
  /**
61
72
  * Upstream-Baileys-compatible standalone media download. Builds a synthetic
62
73
  * `WAMessage` from the supplied media subcontent (image/video/audio/etc fields)
@@ -505,10 +505,14 @@ export const generateWAMessageContent = async (message, options) => {
505
505
  };
506
506
  export const generateWAMessageFromContent = (jid, message, options) => {
507
507
  const innerMessage = normalizeMessageContent(message);
508
- const key = getContentType(innerMessage);
509
508
  const timestamp = unixTimestampSeconds(options.timestamp);
510
509
  const { quoted, userJid } = options;
510
+ // Only the quote and ephemeral branches read the content key, and a plain
511
+ // send takes neither, so resolve it on demand instead of on every send.
512
+ let key;
511
513
  if (quoted && !isJidNewsletter(jid)) {
514
+ const contentKey = getContentType(innerMessage);
515
+ key = contentKey;
512
516
  const participant = quoted.key.fromMe
513
517
  ? userJid // TODO: Add support for LIDs
514
518
  : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
@@ -520,7 +524,7 @@ export const generateWAMessageFromContent = (jid, message, options) => {
520
524
  if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
521
525
  delete quotedContent.contextInfo;
522
526
  }
523
- const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
527
+ const contextInfo = ('contextInfo' in innerMessage[contentKey] && innerMessage[contentKey]?.contextInfo) || {};
524
528
  contextInfo.participant = jidNormalizedUser(participant);
525
529
  contextInfo.stanzaId = quoted.key.id;
526
530
  contextInfo.quotedMessage = quotedMsg;
@@ -529,26 +533,27 @@ export const generateWAMessageFromContent = (jid, message, options) => {
529
533
  if (jid !== quoted.key.remoteJid) {
530
534
  contextInfo.remoteJid = quoted.key.remoteJid;
531
535
  }
532
- if (contextInfo && innerMessage[key]) {
536
+ if (contextInfo && innerMessage[contentKey]) {
533
537
  /* @ts-ignore */
534
- innerMessage[key].contextInfo = contextInfo;
538
+ innerMessage[contentKey].contextInfo = contextInfo;
535
539
  }
536
540
  }
537
541
  if (
538
542
  // if we want to send a disappearing message
539
543
  !!options?.ephemeralExpiration &&
540
- // and it's not a protocol message -- delete, toggle disappear message
541
- key !== 'protocolMessage' &&
542
- // already not converted to disappearing message
543
- key !== 'ephemeralMessage' &&
544
544
  // newsletters don't support ephemeral messages
545
545
  !isJidNewsletter(jid)) {
546
- /* @ts-ignore */
547
- innerMessage[key].contextInfo = {
548
- ...innerMessage[key].contextInfo,
549
- expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
550
- //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
551
- };
546
+ const contentKey = key ?? getContentType(innerMessage);
547
+ // skip protocol messages -- delete, toggle disappear message -- and
548
+ // content already converted to a disappearing message
549
+ if (contentKey !== 'protocolMessage' && contentKey !== 'ephemeralMessage') {
550
+ /* @ts-ignore */
551
+ innerMessage[contentKey].contextInfo = {
552
+ ...innerMessage[contentKey].contextInfo,
553
+ expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL
554
+ //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
555
+ };
556
+ }
552
557
  }
553
558
  // `create` copies into a fresh instance; content built by
554
559
  // `generateWAMessageContent` already is one, and the branches above mutate
@@ -720,6 +725,22 @@ export const _registerActiveBridgeClient = (client, logger) => {
720
725
  activeBridgeClient = client;
721
726
  activeBridgeLogger = logger;
722
727
  };
728
+ /**
729
+ * Drop the module-level pointer when `sock.end()` frees the client it points
730
+ * at. Without this the global keeps a strong reference to a freed
731
+ * `WasmWhatsAppClient`, so the next standalone `downloadContentFromMessage()`
732
+ * call reaches into a null wasm pointer and fails with an opaque
733
+ * wasm-bindgen error instead of the actionable "no bridge client" Boom.
734
+ *
735
+ * Identity-checked on purpose: a multi-account host that ends socket A after
736
+ * creating socket B must not clear B's registration.
737
+ */
738
+ export const _unregisterActiveBridgeClient = (client) => {
739
+ if (activeBridgeClient !== client)
740
+ return;
741
+ activeBridgeClient = undefined;
742
+ activeBridgeLogger = undefined;
743
+ };
723
744
  const noopLogger = {
724
745
  level: 'silent',
725
746
  child: () => noopLogger,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oxidezap/baileyrs",
3
3
  "type": "module",
4
- "version": "0.0.35",
4
+ "version": "0.1.0",
5
5
  "description": "A Rust-powered WhatsApp Web library for JavaScript, with a Baileys-compatible API",
6
6
  "keywords": [
7
7
  "whatsapp",
@@ -75,7 +75,7 @@
75
75
  },
76
76
  "dependencies": {
77
77
  "@hapi/boom": "^9.1.4",
78
- "@oxidezap/whatsapp-rust-bridge": "0.6.4",
78
+ "@oxidezap/whatsapp-rust-bridge": "0.6.5",
79
79
  "long": "^5.3.2",
80
80
  "pino": "^10.3.1",
81
81
  "protobufjs": "^7.6.5"