@oxidezap/whatsapp-rust-bridge 0.13.0 → 0.14.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.
@@ -253,7 +253,7 @@ export interface CallLinkJoin {
253
253
  group?: GroupCallUpdate | null;
254
254
  }
255
255
 
256
- /** Audio/video mode of a reusable call link. */
256
+ /** Audio/video mode of a reusable call link. Hand-written rather than generated. The enum catalog holds exactly one `audio`/`video` pair, `MediaType` in the status composer's module, and two two-valued media enums agreeing on their values is not evidence that one owns the other's wire format. Binding it would let a kind added for status composition arrive here, in the type that builds and parses `<call_link>`. */
257
257
  export type CallLinkMedia = "audio" | "video";
258
258
 
259
259
  /** Metadata returned without joining a reusable call link. */
@@ -321,6 +321,16 @@ export interface ClearChatUpdate {
321
321
  from_full_sync: boolean;
322
322
  }
323
323
 
324
+ /** The server pushed a retirement deadline for the running client build, via `<ib><client_expiration>`. Dispatched only when the deadline actually changed, so a repeated stanza is silent. `expires_at` is the deadline as recorded, which is never sooner than three days out even when the server's own answer is; `withdrawn` marks the stanza that carries no deadline at all, retracting whatever was held. Consumers own the response. This client keeps connecting until the server refuses it -- the deadline is notice, not an instruction to stop -- so a consumer that cares about uptime should treat this as the cue to move to a newer build before the date arrives. */
325
+ export interface ClientExpirationChanged {
326
+ /** Unix seconds after which the server expects to stop accepting this build. `None` when the deadline was withdrawn. */
327
+ expires_at?: number | string | null;
328
+ /** The build the deadline was issued against. */
329
+ version: [number, number, number];
330
+ /** `true` when the server retracted a deadline it had previously set. */
331
+ withdrawn: boolean;
332
+ }
333
+
324
334
  export interface ClientOutdated {
325
335
  /** The whole `<failure>` stanza, so no attribute is lost to a log line. */
326
336
  raw?: any | null;
@@ -380,7 +390,8 @@ export interface ContactUpdated {
380
390
 
381
391
  export type DayOfWeek = "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | string;
382
392
 
383
- export type DecryptFailMode = "show" | "hide";
393
+ /** The `decrypt-fail` attribute of an `<enc>` node. `Hide` is the server asking that a failure to decrypt this stanza not be surfaced to the user. Generated from `DecryptFailType` in `WAWebBackendJobs.flow`. */
394
+ export type DecryptFailMode = "hide" | "show";
384
395
 
385
396
  /** Payload of [`Event::DecryptedPayload`]: what Signal produced for one `<enc>`, before this build tried to make sense of it. The client decodes a plaintext into [`wa::Message`] and dispatches that. A payload it cannot decode — a field this build predates, a message type it does not model — is logged and dropped, and with it goes something that cost a real decryption and advanced the ratchet. Nothing can ask for it back: the ratchet has moved on, so the same ciphertext will never decrypt again. This event is that payload, handed over before decoding is attempted. It arrives whether or not the decode goes on to succeed. Reasons to want it: recording traffic for faithful replay (re-encoding a decoded `Message` does not reproduce the original bytes), decoding with a newer protobuf than this build carries, and looking at a payload that failed to decode instead of only reading that it did. Gated by `Client::acquire_decrypted_payload_forwarding()`: nothing is emitted, and nothing is cloned, while no consumer holds a lease. */
386
397
  export interface DecryptedPayload {
@@ -390,6 +401,10 @@ export interface DecryptedPayload {
390
401
  enc_index: number;
391
402
  /** The `type` attribute the `<enc>` carried: `msg`, `pkmsg`, `skmsg`, … */
392
403
  enc_type: string;
404
+ /** The `state` attribute the `<enc>` carried, verbatim, or `None` when it carried none. The server's own annotation of the session this copy was encrypted under. This build does not model the values and does not act on them; they are handed over as text so a consumer can. */
405
+ state?: string | null;
406
+ /** The `session_type` attribute the `<enc>` carried, verbatim, or `None` when it carried none. Unmodelled and unacted-on, like [`state`](Self::state). */
407
+ session_type?: string | null;
393
408
  }
394
409
 
395
410
  export interface DeleteChatUpdate {
@@ -449,6 +464,8 @@ export interface Device {
449
464
  lid_migrated: boolean;
450
465
  /** Wall-clock ms of the last signed-pre-key rotation, driving WA Web's `RotateKeyJob` cadence. Fresh devices baseline off creation; devices persisted before this field existed deserialize to `0`, which the rotation path treats as "seed the baseline, don't rotate yet". */
451
466
  last_signed_pre_key_rotation_ms: number | string;
467
+ /** Deadline the server pushed for this build, via `<ib><client_expiration>`. `None` until the server says otherwise, which is the common case: the stanza is sent when a build is being retired, not on every connect. */
468
+ server_client_expiration?: ServerClientExpiration | null;
452
469
  /** true means the account's `readreceipts` privacy is `none`, so DM read/played receipts go out as `*-self` (which don't notify the sender). Persisted so the value is known on reconnect before the privacy fetch completes; `false` (WA default `all`) sends plain `read`/`played`. */
453
470
  read_receipts_disabled: boolean;
454
471
  }
@@ -565,6 +582,7 @@ export interface DisableLinkPreviewsUpdate {
565
582
  from_full_sync: boolean;
566
583
  }
567
584
 
585
+ /** Whether a privacy disallowed-list entry is being added or removed. Generated from `PrivacyUserAction` in `WAWebSetPrivacyJob`. */
568
586
  export type DisallowedListAction = "add" | "remove";
569
587
 
570
588
  /** A contact's default disappearing messages setting changed. Sent by the server as `<notification type="disappearing_mode">`. WA Web: `WAWebHandleDisappearingModeNotification` → `WAWebUpdateDisappearingModeForContact`. */
@@ -609,6 +627,9 @@ export interface EncDecryptFailed {
609
627
  /** Why one `<enc>` produced no plaintext. Every variant names a branch the receive path actually takes; there is no catch-all "other" standing in for code nobody wrote. New branches append new variants, so this is `#[non_exhaustive]` and a match on it needs a `_` arm. This is the client's own classification of where *it* stopped, not something the server sends and not a statement about the sender's copy. Two builds can classify the same ciphertext differently as branches are refined; the pairing of a reason with a specific `<enc>` is the stable part, the exact variant is not. */
610
628
  export type EncDecryptFailureReason = "MalformedNode" | "UnsupportedEncType" | "MalformedCiphertext" | "NoSession" | "NoSenderKey" | "UnknownPreKey" | "UntrustedIdentity" | "BadMac" | "InvalidMessage" | "NoMessageSecret" | "LocalCryptoFailure" | "SignalError" | "StorageFailure" | "PlaintextUnusable" | "NotAttempted";
611
629
 
630
+ /** The `mediatype` attribute of an `<enc>` node. A hint about the payload the ciphertext carries, available before the decryption that would reveal it. It is the sender's claim and nothing checks it against the decrypted message. Generated from `EncMediaType` in `WAWebBackendJobs.flow`. */
631
+ export type EncMediaType = "image" | "video" | "ptv" | "audio" | "ptt" | "location" | "vcard" | "document" | "url" | "call" | "gif" | "future" | "contact_array" | "livelocation" | "profile_pic" | "sticker" | "sticker_pack" | "hsm" | "product_image" | "template" | "md_app_state" | "md_history_sync" | "list" | "list_response" | "button" | "button_response" | "order" | "product" | "native_flow_response" | "group_history" | string;
632
+
612
633
  /** Review state for an appeal on a suspended group. */
613
634
  export type GroupAppealStatus = "approved" | "in_review" | "none" | "rejected";
614
635
 
@@ -754,8 +775,8 @@ export interface GroupParticipantInfo {
754
775
  group_history_sent_state?: GroupHistorySentState | null;
755
776
  }
756
777
 
757
- /** Admin tier from `<participant type="...">`. Mirrors `GROUP_PARTICIPANT_TYPES` in `WAWebGroupApiConst`. */
758
- export type GroupParticipantType = "participant" | "admin" | "superadmin";
778
+ /** A participant's role in a group. Generated from `GROUP_PARTICIPANT_TYPES` in `WAWebGroupApiConst`. */
779
+ export type GroupParticipantType = "superadmin" | "admin" | "participant";
759
780
 
760
781
  /** Query request type. */
761
782
  export type GroupQueryRequestType = "interactive";
@@ -826,6 +847,9 @@ export interface IncomingCall {
826
847
  group?: GroupCallUpdate | null;
827
848
  }
828
849
 
850
+ /** A child of `<ib>`, which is what says what the bulletin is about. Open: the server adds bulletin kinds without warning, and one this client does not know is logged and skipped rather than treated as a parse failure. */
851
+ export type InfoBulletinType = "dirty" | "edge_routing" | "offline" | "offline_preview" | "tos" | "thread_metadata" | "client_expiration" | "priority_offline_complete" | "recovery_nonce" | "unknown";
852
+
829
853
  /** IQ request type for WhatsApp protocol queries. */
830
854
  export type InfoQueryType = "set" | "get";
831
855
 
@@ -914,7 +938,7 @@ export interface MarkChatAsReadUpdate {
914
938
  /** Member link mode for group invite links. */
915
939
  export type MemberLinkMode = "admin_link" | "all_member_link";
916
940
 
917
- /** Who can share message history with new members. */
941
+ /** Who may share a group's history with a new participant. Generated from `MemberShareGroupHistoryMode` in `WAWebGroupHistoryShareMode`. */
918
942
  export type MemberShareHistoryMode = "admin_share" | "all_member_share";
919
943
 
920
944
  /** How a membership request was initiated. Maps to `WAWebRequestMethodType` in WhatsApp Web JS. */
@@ -934,12 +958,14 @@ export interface MessageInfo {
934
958
  source: MessageSource;
935
959
  id: string;
936
960
  server_id: number;
937
- type: string;
961
+ /** The envelope's `type` attribute. `None` when the stanza carried none. */
962
+ type?: StanzaMessageType | null;
938
963
  push_name: string;
939
964
  timestamp: number;
940
965
  category: MessageCategory;
941
966
  multicast: boolean;
942
- media_type: string;
967
+ /** The `mediatype` the stanza's `<enc>` nodes declared, aggregated to one value per message. A fan-out stanza carries one `<enc>` per device and the attribute is a property of the message, not of a device copy, so the first `<enc>` that carries one wins in the order the client enumerates them: the direct `<enc>` children first, then this device's under `<participants><to>`. Divergent values across a fan-out are not reconciled and the later ones are dropped; a consumer that needs per-node values reads them from [`DecryptedPayload`](crate::types::events::DecryptedPayload). Those fan-out nodes are a wider source than WA Web's parser, which maps only the direct `<enc>` children. The two agree on every stanza seen so far, since the attribute describes the message and every device copy repeats it, so the wider read only fills the field on a stanza whose direct children carry nothing. `None` when no `<enc>` carried the attribute. */
968
+ media_type?: EncMediaType | null;
943
969
  edit: EditAttribute;
944
970
  bot_info?: MsgBotInfo | null;
945
971
  meta_info: MsgMetaInfo;
@@ -1043,9 +1069,12 @@ export interface MsgMetaInfo {
1043
1069
  target_sender?: Jid | null;
1044
1070
  /** `<meta target_chat_jid="…">` — present when the bot reply addresses a chat distinct from the stanza-level `from` (used for msmsg secret lookup; see WA Web `decryptMsmsgBotMessage`). */
1045
1071
  target_chat?: Jid | null;
1046
- deprecated_lid_session?: boolean | null;
1072
+ /** `<meta thread_msg_id="…">`: the message this one threads under, for a stanza the server routes into an existing thread. */
1047
1073
  thread_message_id?: string | null;
1074
+ /** `<meta thread_msg_sender_jid="…">`: who authored [`thread_message_id`](Self::thread_message_id). Absent whenever that is. */
1048
1075
  thread_message_sender_jid?: Jid | null;
1076
+ /** `<meta polltype="…">`: which stage of a poll's lifecycle the envelope carries. Read only when the envelope declares [`StanzaMessageType::Poll`], so a `<meta polltype>` on any other type is ignored rather than recorded. An unrecognized value is `None`, indistinguishable from the attribute being absent. */
1077
+ poll_type?: PollType | null;
1049
1078
  /** `<meta content_type=...>` attr. Server marks reactions/edits as `"add_on"`; mirrors `WAWebHandleMsgParser` b()'s metadata read. */
1050
1079
  content_type?: string | null;
1051
1080
  /** `<meta appdata=...>` attr. `"default"` is the only observed value. */
@@ -1105,6 +1134,9 @@ export interface NewsletterLiveUpdateReaction {
1105
1134
 
1106
1135
  export type NewsletterMessageType = "text" | "media" | "reaction" | "revoke" | "poll_creation" | "poll_vote" | "edit" | string;
1107
1136
 
1137
+ /** The `type` attribute of an incoming `<notification>`. Every value WA Web routes. This client handles a subset and forwards the rest as a raw event, so a variant here is a value the protocol carries, not a promise that anything acts on it. */
1138
+ export type NotificationType = "account_sync" | "business" | "companion_reg_refresh" | "contacts" | "crsc_continuation" | "devices" | "digital_commerce_subscription" | "disappearing_mode" | "encrypt" | "fb:update" | "hosted" | "link_code_companion_reg" | "mediaretry" | "mex" | "newsletter" | "passkey_prologue_request" | "pay" | "picture" | "privacy_token" | "psa" | "registration" | "server" | "server_sync" | "status" | "w:gp2" | "w:growth" | "waffle";
1139
+
1108
1140
  export interface OfflineSyncCompleted {
1109
1141
  count: number;
1110
1142
  }
@@ -1217,6 +1249,9 @@ export interface PinUpdate {
1217
1249
  from_full_sync: boolean;
1218
1250
  }
1219
1251
 
1252
+ /** The `polltype` attribute of an incoming `<message><meta>` node. Closed on purpose: the attribute is `attrEnumOrNullIfUnknown` upstream (`unknownValue: "null"`), so a value outside this set is dropped rather than preserved. Generated from `POLL_TYPES` in `WAWebHandleMsgCommon`. */
1253
+ export type PollType = "creation" | "quiz_creation" | "vote" | "result_snapshot" | "edit";
1254
+
1220
1255
  export type PreKeyFetchReason = "identity" | "retry" | string;
1221
1256
 
1222
1257
  export type Presence = "available" | "unavailable";
@@ -1240,14 +1275,6 @@ export type ProductAvailability = "IN_STOCK" | "OUT_OF_STOCK" | "AVAILABLE_FOR_A
1240
1275
  /** Profile picture type (preview thumbnail or full-size). */
1241
1276
  export type ProfilePictureType = "preview" | "image";
1242
1277
 
1243
- export interface PushNameUpdate {
1244
- /** The contact who changed their push name. */
1245
- jid: Jid;
1246
- message: MessageInfo;
1247
- old_push_name: string;
1248
- new_push_name: string;
1249
- }
1250
-
1251
1278
  export type PushPriority = "high" | "high_force";
1252
1279
 
1253
1280
  /** A quick reply was created, edited, or deleted on a linked device. Deletion is the same mutation with `action.deleted == Some(true)`, not a syncd `Remove`, so a consumer must check that flag rather than assume the event always describes a live quick reply. */
@@ -1303,6 +1330,13 @@ export interface SelfPushNameUpdated {
1303
1330
  new_name: string;
1304
1331
  }
1305
1332
 
1333
+ /** Identifies a message *and who sent it*. Message ids come from the sending client and are not unique across senders, so `(chat, id)` names a message only when the sender is already known from context. WA Web says the same in `MsgKey`, which serializes as `[fromMe, remote, id, participant]`: two participants of one group using the same id are two messages, and folding them into one drops the second. */
1334
+ export interface SenderMessageId {
1335
+ chat: Jid;
1336
+ id: string;
1337
+ sender: Jid;
1338
+ }
1339
+
1306
1340
  /** Payload of [`Event::ServerAck`]: the server acknowledged (or nacked) an outgoing stanza. Server acks cover every outgoing stanza class — message, receipt, notification, call — so consumers should filter on [`class`](Self::class) before correlating ids. */
1307
1341
  export interface ServerAck {
1308
1342
  /** Id of the acked stanza (for a sent message, its message id). */
@@ -1317,9 +1351,23 @@ export interface ServerAck {
1317
1351
  error?: string | null;
1318
1352
  }
1319
1353
 
1354
+ /** The server's answer to "when does this client build stop being accepted". Scoped to the build it was issued against, exactly like WA Web's `setServerClientExpirationOverride(value, VERSION_BASE)`. A deadline learned for one build says nothing about the next one, so a version change retires the record rather than carrying it forward. */
1355
+ export interface ServerClientExpiration {
1356
+ /** Unix seconds after which the server expects to stop accepting this build. */
1357
+ expires_at: number | string;
1358
+ /** The `(primary, secondary, tertiary)` build the deadline was issued for. */
1359
+ version: [number, number, number];
1360
+ }
1361
+
1320
1362
  /** The type of spam flow indicating the source of the report. */
1321
1363
  export type SpamFlow = "GroupSpamBannerReport" | "GroupInfoReport" | "MessageMenu" | "ContactInfo" | "StatusReport";
1322
1364
 
1365
+ /** The `type` attribute of an incoming `<message>` envelope. The official parser rejects a stanza whose `type` is absent or outside this set (`unknownValue: "reject"`). This client keeps the stanza instead, so the fallback arm holds the exact wire bytes of a value it does not model. Generated from `STANZA_MSG_TYPES` in `WAWebHandleMsgCommon`. */
1366
+ export type StanzaMessageType = "text" | "media" | "medianotify" | "pay" | "poll" | "reaction" | "event" | string;
1367
+
1368
+ /** The tag a stanza arrives under. The union of WA Web's stanza dispatcher, the requests the server sends us, and the types this client sends: no one document lists them all. */
1369
+ export type StanzaTag = "ack" | "call" | "chatstate" | "error" | "failure" | "ib" | "iq" | "message" | "notification" | "presence" | "receipt" | "status" | "stream:error" | "success" | "xmlstreamend";
1370
+
1323
1371
  export interface StarUpdate {
1324
1372
  /** The chat containing the starred or unstarred message. */
1325
1373
  chat_jid: Jid;
@@ -2607,7 +2655,7 @@ export type PresenceStatus = "available" | "unavailable";
2607
2655
  * `From` impls below by walking the source chain. This keeps the JS object
2608
2656
  * shape predictable and the codegen / `Tsify` output simple.
2609
2657
  */
2610
- export type BridgeError = { kind: "server"; serverCode: number; serverText: string } | { kind: "timeout" } | { kind: "not-connected" } | { kind: "disconnected"; reason: string } | { kind: "invalid-argument"; field: string; reason: string } | { kind: "protocol-violation"; reason: string } | { kind: "crypto"; operation: string } | { kind: "storage"; operation: string } | { kind: "no-recipient-device"; attempted: number } | { kind: "internal"; message: string };
2658
+ export type BridgeError = { kind: "server"; serverCode: number; serverText: string; errorType?: string; backoffSeconds?: number } | { kind: "timeout" } | { kind: "not-connected" } | { kind: "disconnected"; reason: string } | { kind: "invalid-argument"; field: string; reason: string } | { kind: "protocol-violation"; reason: string } | { kind: "crypto"; operation: string } | { kind: "storage"; operation: string } | { kind: "no-recipient-device"; attempted: number } | { kind: "internal"; message: string };
2611
2659
 
2612
2660
  /**
2613
2661
  * Public portion of one pre-key in a supplied pairwise session bundle.
@@ -3319,7 +3367,6 @@ export type WhatsAppEvent =
3319
3367
  | { type: 'contact_number_changed'; data: ContactNumberChanged }
3320
3368
  | { type: 'contact_sync_requested'; data: ContactSyncRequested }
3321
3369
  | { type: 'group_update'; data: GroupUpdate }
3322
- | { type: 'push_name_update'; data: PushNameUpdate }
3323
3370
  | { type: 'self_push_name_updated'; data: SelfPushNameUpdated }
3324
3371
  | { type: 'offline_sync_preview'; data: OfflineSyncPreview }
3325
3372
  | { type: 'offline_sync_completed'; data: OfflineSyncCompleted }
@@ -3343,6 +3390,7 @@ export type WhatsAppEvent =
3343
3390
  | { type: 'app_state_sync_failed'; data: AppStateSyncFailed }
3344
3391
  | { type: 'contact_removed'; data: ContactRemoved }
3345
3392
  | { type: 'pairing_qr_codes_exhausted'; data: PairingQrCodesExhausted }
3393
+ | { type: 'client_expiration_changed'; data: ClientExpirationChanged }
3346
3394
  | { type: 'contact_update'; data: ContactUpdate }
3347
3395
  | { type: 'pin_update'; data: PinUpdate }
3348
3396
  | { type: 'mute_update'; data: MuteUpdate }
@@ -4654,12 +4702,12 @@ export interface InitOutput {
4654
4702
  readonly intounderlyingsink_write: (a: number, b: number) => number;
4655
4703
  readonly intounderlyingsource_cancel: (a: number) => void;
4656
4704
  readonly intounderlyingsource_pull: (a: number, b: number) => number;
4657
- readonly __wasm_bindgen_func_elem_4333: (a: number, b: number, c: number) => void;
4658
- readonly __wasm_bindgen_func_elem_26304: (a: number, b: number, c: number, d: number) => void;
4659
- readonly __wasm_bindgen_func_elem_26306: (a: number, b: number, c: number, d: number) => void;
4660
- readonly __wasm_bindgen_func_elem_9238: (a: number, b: number, c: number) => void;
4661
- readonly __wasm_bindgen_func_elem_4332: (a: number, b: number, c: number) => void;
4662
- readonly __wasm_bindgen_func_elem_4331: (a: number, b: number) => void;
4705
+ readonly __wasm_bindgen_func_elem_4361: (a: number, b: number, c: number) => void;
4706
+ readonly __wasm_bindgen_func_elem_26597: (a: number, b: number, c: number, d: number) => void;
4707
+ readonly __wasm_bindgen_func_elem_26599: (a: number, b: number, c: number, d: number) => void;
4708
+ readonly __wasm_bindgen_func_elem_9307: (a: number, b: number, c: number) => void;
4709
+ readonly __wasm_bindgen_func_elem_4360: (a: number, b: number, c: number) => void;
4710
+ readonly __wasm_bindgen_func_elem_4359: (a: number, b: number) => void;
4663
4711
  readonly __wbindgen_export: (a: number, b: number) => number;
4664
4712
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
4665
4713
  readonly __wbindgen_export3: (a: number) => void;
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxidezap/whatsapp-rust-bridge",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "A high-performance utilities for WhatsApp, powered by Rust and WebAssembly.",
5
5
  "author": "João Lucas <jlucaso@hotmail.com>",
6
6
  "license": "MIT",