@oxidezap/whatsapp-rust-bridge 0.19.0 → 0.21.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.
@@ -116,11 +116,24 @@ export interface AppStateSyncKey {
116
116
  timestamp: number | string;
117
117
  }
118
118
 
119
+ /** Why, and with what, a session connected without a freshly resolved version. Only the browser version source falls back this way; see the source constants in the client crate's `version` module for the reason. */
120
+ export interface AppVersionFallback {
121
+ /** The version the session actually connected with. */
122
+ version: [number, number, number];
123
+ /** True when that version is the one compiled into this library, so its staleness is the release's age. False when the device already carried a different one, whose provenance this does not claim to know: it may have been resolved earlier or supplied by the caller. */
124
+ compiled_default: boolean;
125
+ /** What stopped the resolution. Worth distinguishing, because one is routine and the other is news. */
126
+ reason: AppVersionFallbackReason;
127
+ }
128
+
129
+ /** Why a version could not be resolved. */
130
+ export type AppVersionFallbackReason = "SourceUnreachable" | "SourceUnparsable";
131
+
119
132
  export interface ArchiveUpdate {
120
133
  /** The chat being archived or unarchived. */
121
134
  jid: Jid;
122
135
  timestamp: string;
123
- action: import('./proto-types').proto.SyncActionValue.IArchiveChatAction;
136
+ action: import('./proto-types.js').proto.SyncActionValue.IArchiveChatAction;
124
137
  from_full_sync: boolean;
125
138
  }
126
139
 
@@ -197,10 +210,11 @@ export interface CachedNoiseCert {
197
210
  not_after: number | string;
198
211
  }
199
212
 
200
- /** Cached form of the server's two-cert chain. `leaf.key` is the server static public key consumed by Noise IK; the intermediate is kept solely to mirror WA Web's expiry checks. */
213
+ /** Cached form of the server's two-cert chain. `leaf.key` is the server static public key consumed by Noise IK; the intermediate is kept solely to mirror WA Web's expiry checks. `signature_verified` records that both XEdDSA signatures were actually checked when this chain was cached. Only such chains may authorize IK. Records written before this field existed deserialize it as `false` and fall back to one XX, which then stores a verified chain. This is upgrade hygiene, not tamper-proofing: the storage backend remains the trust boundary, and a backend that rewrites this flag can already rewrite the keys it guards. */
201
214
  export interface CachedServerCertChain {
202
215
  intermediate: CachedNoiseCert;
203
216
  leaf: CachedNoiseCert;
217
+ signature_verified: boolean;
204
218
  }
205
219
 
206
220
  /** Fields kept per-variant (not a shared `BasicCallMeta`) so the `serde` shape mirrors the stanza 1:1 for downstream JS consumers. */
@@ -276,7 +290,7 @@ export interface CallLogSync {
276
290
  from_me: boolean;
277
291
  /** When the mutation was written, not when the call happened — the call's own time is `record.start_time`. This is the field WA Web measures against the pairing timestamp to decide whether a record predates the device, so it is worth having; it is not a time to file the call under. A mutation that arrives without one falls back to the moment it was received, as every other app-state event does. */
278
292
  timestamp: string;
279
- record: import('./proto-types').proto.ICallLogRecord;
293
+ record: import('./proto-types.js').proto.ICallLogRecord;
280
294
  from_full_sync: boolean;
281
295
  }
282
296
 
@@ -317,7 +331,7 @@ export interface ClearChatUpdate {
317
331
  /** From the index, not the proto. */
318
332
  delete_media: boolean;
319
333
  timestamp: string;
320
- action: import('./proto-types').proto.SyncActionValue.IClearChatAction;
334
+ action: import('./proto-types.js').proto.SyncActionValue.IClearChatAction;
321
335
  from_full_sync: boolean;
322
336
  }
323
337
 
@@ -346,6 +360,12 @@ export interface ConnectFailure {
346
360
  /** Wire codes: 400=Generic, 401=LoggedOut, 402=TempBanned, 403=AccountLocked, 406=UnknownLogout, 405=ClientOutdated, 409=BadUserAgent, 413=CatExpired, 414=CatInvalid, 415=NotFound, 418=ClientUnknown, 500=InternalServerError, 501=Experimental, 503=ServiceUnavailable */
347
361
  export type ConnectFailureReason = number;
348
362
 
363
+ /** The session is authenticated and has asked the server to leave passive mode. That request is best effort: a failure to go active is logged and the connection is announced anyway, on the same reasoning as below, so treat this as "the client believes stanzas should be flowing" rather than a guarantee that the server agrees. After a fresh pairing the client waits for the critical app-state collections before publishing this, so the push name and blocklist are normally in place by now. It waits, but it does not withhold: a critical collection the server refused or could not deliver is reported as [`AppStateSyncFailed`] and the connection is announced regardless, because a session already delivering messages is not one a consumer should be left believing never opened. */
364
+ export interface Connected {
365
+ /** Present when version resolution could not reach its source and the session connected on the version the device already held. Absent on every normal connect, so `Some` is the whole signal: a consumer that cares can warn, refuse, or pin a version of its own. */
366
+ app_version_fallback?: AppVersionFallback | null;
367
+ }
368
+
349
369
  /** A contact changed their phone number. Emitted from `<notification type="contacts"><modify old="..." new="..." old_lid="..." new_lid="..."/>`. The library updates the global LID-PN cache when both `old_lid` and `new_lid` are present, mirroring `WAWebDBCreateLidPnMappings`. No Signal session is wiped (WA Web `WAWebHandleContactNotification` also leaves sessions intact). Group participant updates arrive via separate `w:gp2` notifications, so per-group caches are not touched here. Consumers can subscribe and refresh their own caches if needed. */
350
370
  export interface ContactNumberChanged {
351
371
  /** Old phone number JID. */
@@ -377,7 +397,7 @@ export interface ContactUpdate {
377
397
  /** The chat/contact this sync action applies to. */
378
398
  jid: Jid;
379
399
  timestamp: string;
380
- action: import('./proto-types').proto.SyncActionValue.IContactAction;
400
+ action: import('./proto-types.js').proto.SyncActionValue.IContactAction;
381
401
  from_full_sync: boolean;
382
402
  }
383
403
 
@@ -413,7 +433,7 @@ export interface DeleteChatUpdate {
413
433
  /** From the index, not the proto — DeleteChatAction only has messageRange. */
414
434
  delete_media: boolean;
415
435
  timestamp: string;
416
- action: import('./proto-types').proto.SyncActionValue.IDeleteChatAction;
436
+ action: import('./proto-types.js').proto.SyncActionValue.IDeleteChatAction;
417
437
  from_full_sync: boolean;
418
438
  }
419
439
 
@@ -424,7 +444,7 @@ export interface DeleteMessageForMeUpdate {
424
444
  message_id: string;
425
445
  from_me: boolean;
426
446
  timestamp: string;
427
- action: import('./proto-types').proto.SyncActionValue.IDeleteMessageForMeAction;
447
+ action: import('./proto-types.js').proto.SyncActionValue.IDeleteMessageForMeAction;
428
448
  from_full_sync: boolean;
429
449
  }
430
450
 
@@ -438,7 +458,7 @@ export interface Device {
438
458
  signed_pre_key_id: number;
439
459
  signed_pre_key_signature: Uint8Array;
440
460
  adv_secret_key: Uint8Array;
441
- account?: import('./proto-types').proto.IADVSignedDeviceIdentity | null;
461
+ account?: import('./proto-types.js').proto.IADVSignedDeviceIdentity | null;
442
462
  push_name: string;
443
463
  app_version_primary: number;
444
464
  app_version_secondary: number;
@@ -456,7 +476,7 @@ export interface Device {
456
476
  server_has_prekeys: boolean;
457
477
  /** NCT salt provisioned by the server via app state sync or history sync. */
458
478
  nct_salt?: Uint8Array | null;
459
- /** Server cert chain cached from the last successful XX (or XX-fallback) handshake. Enables Noise IK on the next connect by exposing `leaf.key` as the server's static public key, and lets us reject stale entries via `not_after` before even attempting IK. `None` forces XX on the next connect. */
479
+ /** Server cert chain cached from the last successful XX (or XX-fallback) handshake. Enables Noise IK on the next connect by exposing `leaf.key` as the server's static public key, and lets us reject stale entries via `not_after` before even attempting IK. Only chains whose signatures were checked (`signature_verified`) authorize IK; `None` — or an unmarked legacy record — forces XX on the next connect. */
460
480
  server_cert_chain?: CachedServerCertChain | null;
461
481
  /** Login counter sent as `ClientPayload.lc` on every login. WA Web's `WAWebUserPrefsGeneral.getLoginCounter()` reads (and bumps) this from localStorage on each connect; the server uses it as an anti-abuse signal. Persisted so it survives restarts. */
462
482
  login_counter: number;
@@ -480,21 +500,19 @@ export interface DeviceElement {
480
500
  lid?: Jid | null;
481
501
  }
482
502
 
483
- /** Device information for registry tracking. */
503
+ /** Device information for registry tracking. Packed into 8 bytes rather than the 16 the obvious three fields occupy: a `u32` device id, an `Option<u32>` key index and a `bool` carry 5 bytes of information and 11 bytes of alignment padding, and a device registry holds one of these per device per known contact. The device id is a `u16` because that is what it is on the wire — [`Jid::device`] has always been one — and the hosted flag and the key index's presence share one byte. Serialized as the `{device_id, key_index, is_hosted}` object the previous layout wrote, so stored device-list blobs are unchanged in both directions. */
484
504
  export interface DeviceInfo {
485
- /** The device ID (0 = primary device, 1+ = companion devices) */
486
505
  device_id: number;
487
- /** The key index, if known */
506
+ /** Meaningful only when [`Self::HAS_KEY_INDEX`] is set. */
488
507
  key_index?: number | null;
489
- /** Whether the device uses the hosted PN/LID address space. */
490
508
  is_hosted: boolean;
491
509
  }
492
510
 
493
- /** Device list record matching WhatsApp Web's DeviceListRecord structure. */
511
+ /** Device list record matching WhatsApp Web's DeviceListRecord structure. Serialized through a private shadow struct whose fields are the `String`, `Vec` and `Option<String>` the previous layout used. Deriving serde on the compact fields directly would stamp a second set of `Box<[T]>` and `Option<Box<str>>` codecs into every crate that persists a record, for a blob that is byte-for-byte the same either way. */
494
512
  export interface DeviceListRecord {
495
- /** The user part of the JID (phone number or LID) */
513
+ /** The user part of the JID (phone number or LID) `Arc<str>`, so the registry cache can key the record by exactly this string instead of allocating a second copy of it: every write stores the record under its own `user`, and the two used to be separate `String` allocations of identical content. */
496
514
  user: string;
497
- /** List of known devices for this user */
515
+ /** List of known devices for this user. Boxed rather than a `Vec`: the list is built once and then read for the life of the cache entry, so the capacity field is dead weight — and worse, `retain_devices_by_key_index` shortens it without releasing the capacity, leaving the dropped devices' slots resident. Mutations go through [`DeviceListRecord::edit_devices`]. */
498
516
  devices: DeviceInfo[];
499
517
  /** Timestamp when this record was last updated */
500
518
  timestamp: number | string;
@@ -578,7 +596,7 @@ export interface DisableLinkPreviewsUpdate {
578
596
  /** `true` when link previews are now disabled. Only emitted when the wire carried the flag; WA Web treats an absent one as a malformed mutation. */
579
597
  previews_disabled: boolean;
580
598
  timestamp: string;
581
- action: import('./proto-types').proto.SyncActionValue.IPrivacySettingDisableLinkPreviewsAction;
599
+ action: import('./proto-types.js').proto.SyncActionValue.IPrivacySettingDisableLinkPreviewsAction;
582
600
  from_full_sync: boolean;
583
601
  }
584
602
 
@@ -706,7 +724,7 @@ export interface GroupInfo {
706
724
  addressing_mode: AddressingMode;
707
725
  /** Whether this group is a Community Announcement Group (WA Web `isCag`, derived from `default_sub_group`). `None` means the persisted blob predates the field, so the answer is unknown and callers must re-query. */
708
726
  is_community_announce?: boolean | null;
709
- /** Maps a LID user identifier (the `user` part of the LID JID) to the corresponding phone-number JID. This is used for device queries since LID usync requests may not work reliably. */
727
+ /** LID→PN mappings, sorted by the LID user part, looked up by binary search. Used for device queries, since LID usync requests may not work reliably. A sorted slice rather than a `HashMap`: a 1024-member group needs 2048 hashbrown buckets, so roughly half the map's bytes were empty slots, and the entries are read far more often than they are written (member changes arrive on notifications; lookups run once per participant per send). Serialized as the `lid_to_pn_map` object the previous layout wrote, so the persisted `group_metadata` blob is unchanged. */
710
728
  lid_to_pn_map: Record<string, Jid>;
711
729
  }
712
730
 
@@ -717,7 +735,7 @@ export type GroupNotificationAction =
717
735
  | { type: "promote"; participants: GroupParticipantInfo[] }
718
736
  | { type: "demote"; participants: GroupParticipantInfo[] }
719
737
  | { type: "modify"; participants: GroupParticipantInfo[] }
720
- | { type: "subject"; subject: string; subject_owner?: Jid | null; subject_time?: number | string | null }
738
+ | { type: "subject"; subject: string; subject_owner?: Jid | null; subject_owner_pn?: Jid | null; subject_owner_username?: string | null; subject_time?: number | string | null }
721
739
  | { type: "description"; id: string; description?: string | null }
722
740
  | { type: "locked"; threshold?: string | null }
723
741
  | { type: "unlocked" }
@@ -807,7 +825,7 @@ export interface GroupUpdate {
807
825
  is_lid_addressing_mode: boolean;
808
826
  /** Whether participant identity information was incomplete in the source stanza. */
809
827
  has_incomplete_participant_information: boolean;
810
- /** The specific action */
828
+ /** The specific action. Boxed, like the `action` of every sync-action payload in this file (`ContactUpdate`, `PinUpdate`, `MuteUpdate`, …): at 288 bytes it made `GroupUpdate` the largest variant of `Event`, and `Event` is what sizes the single `Arc` allocation every dispatch makes, group update or not. */
811
829
  action: GroupNotificationAction;
812
830
  }
813
831
 
@@ -825,8 +843,12 @@ export interface IdentityChange {
825
843
 
826
844
  /** One decrypted inbound message. The same items (and order) back both consumer surfaces: the durability hook's batch and [`Event::Messages`]. */
827
845
  export interface InboundMessage {
828
- message: import('./proto-types').proto.IMessage;
846
+ message: import('./proto-types.js').proto.IMessage;
829
847
  info: MessageInfo;
848
+ /** Ephemeral duration in seconds, from the decrypted message's `contextInfo.expiration`. Lives here rather than on `info` because it is only known after decryption, and `info` is shared with every `<enc>` of the stanza by then: writing it there cost a deep copy of the whole `MessageInfo` on every disappearing-chat message. */
849
+ ephemeral_expiration?: number | null;
850
+ /** Parent post key when `message` is a decrypted CAG channel comment (`enc_comment_message`). The inner `Message` proto has no slot for the threading link, so it surfaces here. Boxed: rare. */
851
+ comment_target?: import('./proto-types.js').proto.IMessageKey | null;
830
852
  }
831
853
 
832
854
  export interface IncomingCall {
@@ -843,6 +865,8 @@ export interface IncomingCall {
843
865
  timestamp: number;
844
866
  offline: boolean;
845
867
  action: CallAction;
868
+ /** The rotation the sending device announced on this stanza's `<video>` child, in `0..=3`. Only an `<offer>` and an `<accept>` carry one; `None` everywhere else, and for a stanza whose value was out of range. A video-from-start peer announces its camera rotation exactly once, in that stanza, and sends no `<video>` of its own until the camera actually turns -- so dropping this leaves every frame of a call from a sideways camera stamped upright. On the payload rather than inside [`CallAction::Offer`] / [`Accept`]: those variants are plain struct variants, so a new field there breaks every consumer that destructures them without a `..` rest. This struct is `#[non_exhaustive]` with a `bon` builder, which is exactly the shape the `Event` stability policy reserves for a payload that has to grow. [`Accept`]: CallAction::Accept */
869
+ video_orientation?: number | null;
846
870
  /** Group snapshot embedded in an initial offer or active-call invitation. */
847
871
  group?: GroupCallUpdate | null;
848
872
  }
@@ -868,7 +892,7 @@ export interface LabelAssociationUpdate {
868
892
  /** The chat the label was associated with or removed from. */
869
893
  chat_jid: Jid;
870
894
  timestamp: string;
871
- action: import('./proto-types').proto.SyncActionValue.ILabelAssociationAction;
895
+ action: import('./proto-types.js').proto.SyncActionValue.ILabelAssociationAction;
872
896
  from_full_sync: boolean;
873
897
  }
874
898
 
@@ -877,7 +901,7 @@ export interface LabelEditUpdate {
877
901
  /** The label identifier (the index key, not a JID). */
878
902
  label_id: string;
879
903
  timestamp: string;
880
- action: import('./proto-types').proto.SyncActionValue.ILabelEditAction;
904
+ action: import('./proto-types.js').proto.SyncActionValue.ILabelEditAction;
881
905
  from_full_sync: boolean;
882
906
  }
883
907
 
@@ -931,7 +955,7 @@ export interface MarkChatAsReadUpdate {
931
955
  /** The chat being marked as read or unread. */
932
956
  jid: Jid;
933
957
  timestamp: string;
934
- action: import('./proto-types').proto.SyncActionValue.IMarkChatAsReadAction;
958
+ action: import('./proto-types.js').proto.SyncActionValue.IMarkChatAsReadAction;
935
959
  from_full_sync: boolean;
936
960
  }
937
961
 
@@ -960,6 +984,7 @@ export interface MessageInfo {
960
984
  server_id: number;
961
985
  /** The envelope's `type` attribute. `None` when the stanza carried none. */
962
986
  type?: StanzaMessageType | null;
987
+ /** The sender's `notify` display name. Inline up to 24 bytes, which covers most names, so a message does not allocate for it. */
963
988
  push_name: string;
964
989
  timestamp: number;
965
990
  category: MessageCategory;
@@ -967,13 +992,14 @@ export interface MessageInfo {
967
992
  /** 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
993
  media_type?: EncMediaType | null;
969
994
  edit: EditAttribute;
995
+ /** The `<bot>` child. Boxed: most messages carry none. */
970
996
  bot_info?: MsgBotInfo | null;
971
- meta_info: MsgMetaInfo;
997
+ /** The `<meta>` and `<reporting>` children, `None` when the stanza carries neither. Boxed: it is 280 bytes of mostly-absent fields, and every `MessageInfo` is retained per message through the commit batch and every consumer that keeps a message. */
998
+ meta_info?: MsgMetaInfo | null;
972
999
  /** Decoded `<verified_name>` child cert of business senders; the display name is in `.name`. Boxed: most messages carry none. */
973
1000
  verified_name?: VerifiedName | null;
1001
+ /** Set on a self-fanout of an own outgoing message. Boxed: rare. */
974
1002
  device_sent_meta?: DeviceSentMeta | null;
975
- /** Ephemeral duration in seconds, extracted from `contextInfo.expiration`. */
976
- ephemeral_expiration?: number | null;
977
1003
  /** Whether this message was delivered during offline sync. */
978
1004
  is_offline: boolean;
979
1005
  /** Set when this message was recovered via PDO rather than normal decryption. Contains the PDO request message ID. */
@@ -986,8 +1012,6 @@ export interface MessageInfo {
986
1012
  verified_name_serial?: number | string | null;
987
1013
  /** Envelope `peer_recipient_pn` attr. Present on companion-device self-synced DM stanzas to identify the peer's PN (so the receipt goes to the right routing target). */
988
1014
  peer_recipient_pn?: Jid | null;
989
- /** Parent post key when the dispatched message is a decrypted CAG channel comment (`enc_comment_message`). The inner `Message` proto has no slot for the threading link, so it surfaces here. */
990
- comment_target?: import('./proto-types').proto.IMessageKey | null;
991
1015
  /** Broadcast-contact-list recipients from `<participants><to jid>` on an incoming broadcast/status stanza. Populated only for broadcasts; used to validate a `deviceSentMessage.phash` (WA Web `validateBclHash`). Empty otherwise. */
992
1016
  bcl_participants: Jid[];
993
1017
  }
@@ -1001,7 +1025,7 @@ export interface MessageLabelAssociationUpdate {
1001
1025
  /** The labelled message's id. */
1002
1026
  message_id: string;
1003
1027
  timestamp: string;
1004
- action: import('./proto-types').proto.SyncActionValue.ILabelAssociationAction;
1028
+ action: import('./proto-types.js').proto.SyncActionValue.ILabelAssociationAction;
1005
1029
  from_full_sync: boolean;
1006
1030
  }
1007
1031
 
@@ -1107,11 +1131,11 @@ export interface MuteUpdate {
1107
1131
  /** The chat being muted or unmuted. */
1108
1132
  jid: Jid;
1109
1133
  timestamp: string;
1110
- action: import('./proto-types').proto.SyncActionValue.IMuteAction;
1134
+ action: import('./proto-types.js').proto.SyncActionValue.IMuteAction;
1111
1135
  from_full_sync: boolean;
1112
1136
  }
1113
1137
 
1114
- /** Wire codes: 421=StaleGroupAddressingMode, 475=NewChatMessagesCapped, 487=ParsingError, 488=UnrecognizedStanza, 489=UnrecognizedStanzaClass, 490=UnrecognizedStanzaType, 491=InvalidProtobuf, 493=InvalidHostedCompanionStanza, 495=MissingMessageSecret, 496=SignalErrorOldCounter, 499=MessageDeletedOnPeer, 500=UnhandledError, 550=UnsupportedAdminRevoke, 551=UnsupportedLIDGroup, 552=DBOperationFailed */
1138
+ /** Wire codes: 415=UnsupportedMessage, 421=StaleGroupAddressingMode, 475=NewChatMessagesCapped, 487=ParsingError, 488=UnrecognizedStanza, 489=UnrecognizedStanzaClass, 490=UnrecognizedStanzaType, 491=InvalidProtobuf, 493=InvalidHostedCompanionStanza, 495=MissingMessageSecret, 496=SignalErrorOldCounter, 499=MessageDeletedOnPeer, 500=UnhandledError, 550=UnsupportedAdminRevoke, 551=UnsupportedLIDGroup, 552=DBOperationFailed */
1115
1139
  export type NackReason = number;
1116
1140
 
1117
1141
  /** A newsletter live update notification, typically containing updated reaction counts for one or more messages. */
@@ -1142,6 +1166,14 @@ export interface OfflineSyncCompleted {
1142
1166
  count: number;
1143
1167
  }
1144
1168
 
1169
+ /** An offline backlog drain ended without its `<ib><offline>` end marker, because the connection went away first. This is the counterpart of [`OfflineSyncCompleted`], not a variant of it: the drain did not finish, the client is not caught up, and the remainder of the backlog is still queued server-side. Nothing was lost — an offline message is only acked through the aggregate receipt flush that a *completed* drain performs, so everything undelivered (and the last open batch) is redelivered on the next connection, where a fresh [`OfflineSyncPreview`] announces it. A consumer that gates "caught up" UI or startup work on [`OfflineSyncCompleted`] should treat this as "not caught up, wait for the next preview" rather than as completion. */
1170
+ export interface OfflineSyncInterrupted {
1171
+ /** What the preview announced for this drain. */
1172
+ total: number;
1173
+ /** Offline stanzas processed before the connection ended. Never larger than `total` in practice, but the server owns both numbers, so treat the pair as a progress report rather than an invariant. */
1174
+ delivered: number;
1175
+ }
1176
+
1145
1177
  /** `total` is authoritative; the per-kind counts need not sum to it. */
1146
1178
  export interface OfflineSyncPreview {
1147
1179
  total: number;
@@ -1157,8 +1189,8 @@ export interface OfflineSyncPreview {
1157
1189
  export type PairCodeRejection = number;
1158
1190
 
1159
1191
  export interface PairError {
1160
- id: Jid;
1161
- lid: Jid;
1192
+ id: string;
1193
+ lid: string;
1162
1194
  business_name: string;
1163
1195
  platform: string;
1164
1196
  error: string;
@@ -1183,8 +1215,8 @@ export interface PairPasskeyRequest {
1183
1215
  }
1184
1216
 
1185
1217
  export interface PairSuccess {
1186
- id: Jid;
1187
- lid: Jid;
1218
+ id: string;
1219
+ lid: string;
1188
1220
  business_name: string;
1189
1221
  platform: string;
1190
1222
  }
@@ -1246,7 +1278,7 @@ export interface PinUpdate {
1246
1278
  /** The chat being pinned or unpinned. */
1247
1279
  jid: Jid;
1248
1280
  timestamp: string;
1249
- action: import('./proto-types').proto.SyncActionValue.IPinAction;
1281
+ action: import('./proto-types.js').proto.SyncActionValue.IPinAction;
1250
1282
  from_full_sync: boolean;
1251
1283
  }
1252
1284
 
@@ -1283,7 +1315,7 @@ export interface QuickReplyUpdate {
1283
1315
  /** The quick reply's identifier (the index key, not a JID). */
1284
1316
  id: string;
1285
1317
  timestamp: string;
1286
- action: import('./proto-types').proto.SyncActionValue.IQuickReplyAction;
1318
+ action: import('./proto-types.js').proto.SyncActionValue.IQuickReplyAction;
1287
1319
  from_full_sync: boolean;
1288
1320
  }
1289
1321
 
@@ -1377,7 +1409,7 @@ export interface StarUpdate {
1377
1409
  message_id: string;
1378
1410
  from_me: boolean;
1379
1411
  timestamp: string;
1380
- action: import('./proto-types').proto.SyncActionValue.IStarAction;
1412
+ action: import('./proto-types.js').proto.SyncActionValue.IStarAction;
1381
1413
  from_full_sync: boolean;
1382
1414
  }
1383
1415
 
@@ -1437,7 +1469,7 @@ export interface UserStatusMuteUpdate {
1437
1469
  /** `true` = status muted, `false` = unmuted. */
1438
1470
  muted: boolean;
1439
1471
  timestamp: string;
1440
- action: import('./proto-types').proto.SyncActionValue.IUserStatusMuteAction;
1472
+ action: import('./proto-types.js').proto.SyncActionValue.IUserStatusMuteAction;
1441
1473
  from_full_sync: boolean;
1442
1474
  }
1443
1475
 
@@ -1474,6 +1506,8 @@ export interface UsyncBotPrompt {
1474
1506
 
1475
1507
  export interface UsyncBusinessResult {
1476
1508
  verified_name?: VerifiedName | null;
1509
+ /** Phone-number JID the server attaches to `<business>` when the queried user was addressed by LID. It is the only place a username lookup can learn the PN, since such a query never carries one. */
1510
+ pn_jid?: Jid | null;
1477
1511
  }
1478
1512
 
1479
1513
  export interface UsyncContactResult {
@@ -1928,6 +1962,11 @@ export function initWasmEngine(logger?: any, crypto?: JsCryptoCallbacks): void;
1928
1962
  * @param wanted_pre_key_count Optional pre-key upload batch size (default 812);
1929
1963
  * clamped to the protocol-safe range at upload time. Smaller batches reduce
1930
1964
  * memory pressure on embedded/WASM hosts.
1965
+ * @param danger_skip_cert_chain_verify Optional testing-only bypass for the
1966
+ * Noise server-cert XEdDSA check, for mock servers that cannot sign a chain
1967
+ * rooted in WhatsApp's issuer. Absent, null or false keeps strict
1968
+ * verification; only an explicit `true` opts in. Anything else rejects the
1969
+ * construction as invalid-argument.
1931
1970
  */
1932
1971
  export function createWhatsAppClient(
1933
1972
  transport_config: JsTransportCallbacks,
@@ -1937,6 +1976,7 @@ store?: JsStoreCallbacks | null,
1937
1976
  cache_config?: CacheConfig | null,
1938
1977
  version?: readonly [number, number, number] | null,
1939
1978
  wanted_pre_key_count?: number | null,
1979
+ danger_skip_cert_chain_verify?: boolean | null,
1940
1980
  ): Promise<WasmWhatsAppClient>;
1941
1981
 
1942
1982
  /** Cache entry configuration. */
@@ -1980,7 +2020,7 @@ interface WasmWhatsAppClient {
1980
2020
 
1981
2021
  /**
1982
2022
  * A catalog product. Only `id` is guaranteed; the server omits rather than
1983
- * blanks, so an absent name is absent, not `\"\"`.
2023
+ * blanks, so an absent name is absent, not `""`.
1984
2024
  */
1985
2025
  export interface ProductResult {
1986
2026
  id: string;
@@ -1990,7 +2030,7 @@ export interface ProductResult {
1990
2030
  url?: string;
1991
2031
  /**
1992
2032
  * The link-shimmed form of `url`, carried alongside it rather than
1993
- * instead. Which to open is a consumer\'s call.
2033
+ * instead. Which to open is a consumer's call.
1994
2034
  */
1995
2035
  shimmedUrl?: string;
1996
2036
  price?: PriceResult;
@@ -2011,9 +2051,9 @@ export interface ProductResult {
2011
2051
  }
2012
2052
 
2013
2053
  /**
2014
- * A delta on the account\'s own business profile.
2054
+ * A delta on the account's own business profile.
2015
2055
  *
2016
- * Absent means \"leave alone\"; an empty value means \"clear\" (`\"\"` for text,
2056
+ * Absent means "leave alone"; an empty value means "clear" (`""` for text,
2017
2057
  * `[]` for `websites`). The core rejects a delta with nothing set.
2018
2058
  */
2019
2059
  export interface BusinessProfileUpdateInput {
@@ -2045,7 +2085,7 @@ export interface OrderProductResult {
2045
2085
  images: ProductImageResult[];
2046
2086
  /**
2047
2087
  * Empty for a product with no variants. Without it a variant order cannot
2048
- * be fulfilled: id, name and price are shared across one listing\'s
2088
+ * be fulfilled: id, name and price are shared across one listing's
2049
2089
  * variants.
2050
2090
  */
2051
2091
  variantProperties: VariantPropertyResult[];
@@ -2091,7 +2131,7 @@ export interface ParticipantChangeResult {
2091
2131
  }
2092
2132
 
2093
2133
  /**
2094
- * A postal address, as sent for a product\'s importer of record.
2134
+ * A postal address, as sent for a product's importer of record.
2095
2135
  */
2096
2136
  export interface ImporterAddressResult {
2097
2137
  street1?: string;
@@ -2103,16 +2143,16 @@ export interface ImporterAddressResult {
2103
2143
  }
2104
2144
 
2105
2145
  /**
2106
- * A price, in thousandths of the currency\'s main unit.
2146
+ * A price, in thousandths of the currency's main unit.
2107
2147
  *
2108
2148
  * WhatsApp scales money by 1000, not 100, and the protobuf field is an
2109
2149
  * `int64`. `amount1000` therefore crosses as a **string**: a `number` is exact
2110
2150
  * only below 2^53, and a large order would be silently wrong rather than
2111
- * rejected. Dividing by 1000 for display is the consumer\'s decision.
2151
+ * rejected. Dividing by 1000 for display is the consumer's decision.
2112
2152
  */
2113
2153
  export interface PriceResult {
2114
2154
  /**
2115
- * Thousandths of one currency unit: `\"1990\"` is 1.99 in `currency`.
2155
+ * Thousandths of one currency unit: `"1990"` is 1.99 in `currency`.
2116
2156
  */
2117
2157
  amount1000: string;
2118
2158
  /**
@@ -2164,6 +2204,11 @@ export interface UserInfoResult {
2164
2204
  * the server returned no device list.
2165
2205
  */
2166
2206
  devices: number[];
2207
+ /**
2208
+ * Meta username, without the display-only `@` prefix. Absent when the
2209
+ * server reported none, which is also how it reports a deleted one.
2210
+ */
2211
+ username?: string;
2167
2212
  }
2168
2213
 
2169
2214
  /**
@@ -2187,7 +2232,7 @@ export interface CommunitySubgroupResult {
2187
2232
  }
2188
2233
 
2189
2234
  /**
2190
- * Allocation churn attributed by whatsapp-rust\'s own `AllocMeter` to tasks
2235
+ * Allocation churn attributed by whatsapp-rust's own `AllocMeter` to tasks
2191
2236
  * spawned for this client. Available in diagnostics builds only.
2192
2237
  */
2193
2238
  export interface CoreAllocationSnapshotResult {
@@ -2222,7 +2267,7 @@ export interface CoreSpanAllocationSnapshot {
2222
2267
  }
2223
2268
 
2224
2269
  /**
2225
- * An admin\'s published profile on a newsletter.
2270
+ * An admin's published profile on a newsletter.
2226
2271
  */
2227
2272
  export interface NewsletterAdminProfileResult {
2228
2273
  id?: string;
@@ -2372,7 +2417,7 @@ export interface ParticipantAddRequestResult {
2372
2417
 
2373
2418
  /**
2374
2419
  * Key of an existing message targeted by `sendReaction` / `sendCommentBytes`.
2375
- * The chat JID comes from the method\'s `jid` argument; `participant` is the
2420
+ * The chat JID comes from the method's `jid` argument; `participant` is the
2376
2421
  * original sender (required for group/status targets).
2377
2422
  */
2378
2423
  export interface TargetMessageKey {
@@ -2389,7 +2434,7 @@ export type MediaType = "image" | "video" | "audio" | "document" | "sticker" | "
2389
2434
  /**
2390
2435
  * Mirrors `device_props.HistorySyncConfig`. Only fields a consumer would
2391
2436
  * realistically tune are exposed individually; partial overrides merge into
2392
- * `wacore::store::default_history_sync_config()` so callers don\'t accidentally
2437
+ * `wacore::store::default_history_sync_config()` so callers don't accidentally
2393
2438
  * drop the WA-Web-aligned support_* claims by setting just one field.
2394
2439
  */
2395
2440
  export interface DeviceHistorySyncConfig {
@@ -2406,7 +2451,7 @@ export interface DeviceHistorySyncConfig {
2406
2451
 
2407
2452
  /**
2408
2453
  * Mirrors `device_props.PlatformType`. The display value the phone shows in
2409
- * \"Linked Devices\" — and the type WhatsApp\'s server uses to decide whether
2454
+ * "Linked Devices" — and the type WhatsApp's server uses to decide whether
2410
2455
  * features like view-once are deliverable as payload or as `absent` stub.
2411
2456
  * Variant names render as `SCREAMING_SNAKE_CASE` in TS to match the proto
2412
2457
  * enum identifiers callers see in WhatsApp documentation / wire dumps.
@@ -2478,7 +2523,7 @@ export interface CommunityLinkFailureResult {
2478
2523
  export interface NewsletterFollowerResult {
2479
2524
  jid: string;
2480
2525
  /**
2481
- * Withheld by the server when the follower\'s privacy settings hide it.
2526
+ * Withheld by the server when the follower's privacy settings hide it.
2482
2527
  */
2483
2528
  phoneJid?: string;
2484
2529
  displayName?: string;
@@ -2552,10 +2597,10 @@ export interface CatalogResult {
2552
2597
  }
2553
2598
 
2554
2599
  /**
2555
- * One page of a business\'s collections.
2600
+ * One page of a business's collections.
2556
2601
  *
2557
2602
  * Forward cursor only — the collections paging object has no `before`, and
2558
- * the asymmetry with the catalog is the wire\'s, not an oversight.
2603
+ * the asymmetry with the catalog is the wire's, not an oversight.
2559
2604
  */
2560
2605
  export interface CollectionsResult {
2561
2606
  collections: CollectionResult[];
@@ -2586,7 +2631,7 @@ export interface BusinessHoursUpdateInput {
2586
2631
 
2587
2632
  /**
2588
2633
  * Optional Noise-payload overrides applied on top of every preset.
2589
- * Leaving any field `None` preserves wacore\'s default, which matches
2634
+ * Leaving any field `None` preserves wacore's default, which matches
2590
2635
  * WA Web (notably `phoneId` stays unset on the wire).
2591
2636
  */
2592
2637
  export interface ClientProfileOverrides {
@@ -2597,13 +2642,13 @@ export interface ClientProfileOverrides {
2597
2642
  }
2598
2643
 
2599
2644
  /**
2600
- * Options for `getCatalog`. Omitted fields take the core\'s own defaults; no
2645
+ * Options for `getCatalog`. Omitted fields take the core's own defaults; no
2601
2646
  * second default is applied here.
2602
2647
  */
2603
2648
  export interface CatalogOptionsInput {
2604
2649
  limit?: number | undefined;
2605
2650
  /**
2606
- * Cursor from a previous page\'s `afterCursor`.
2651
+ * Cursor from a previous page's `afterCursor`.
2607
2652
  */
2608
2653
  after?: string | undefined;
2609
2654
  imageWidth?: number | undefined;
@@ -2629,7 +2674,7 @@ export interface CollectionOptionsInput {
2629
2674
  }
2630
2675
 
2631
2676
  /**
2632
- * Per-mode colours for a bot\'s card.
2677
+ * Per-mode colours for a bot's card.
2633
2678
  */
2634
2679
  export interface BotThemeResult {
2635
2680
  mode: string;
@@ -2652,7 +2697,7 @@ export type PresenceStatus = "available" | "unavailable";
2652
2697
  * Public error shape that crosses the WASM→JS boundary.
2653
2698
  *
2654
2699
  * Variants are intentionally flat — no `#[from]` on enum variants, no
2655
- * `#[serde(flatten)]`. Translation from the core\'s typed errors happens in
2700
+ * `#[serde(flatten)]`. Translation from the core's typed errors happens in
2656
2701
  * `From` impls below by walking the source chain. This keeps the JS object
2657
2702
  * shape predictable and the codegen / `Tsify` output simple.
2658
2703
  */
@@ -2696,7 +2741,7 @@ export interface EncryptMediaResult {
2696
2741
  * Result from `fetchNewChatMessageCappingInfo`.
2697
2742
  *
2698
2743
  * Every field is optional because the server omits the ones that do not apply
2699
- * to an account\'s tier. `remainingQuota` is the core\'s own derivation, present
2744
+ * to an account's tier. `remainingQuota` is the core's own derivation, present
2700
2745
  * only when both quota fields are.
2701
2746
  */
2702
2747
  export interface NewChatMessageCappingResult {
@@ -2724,7 +2769,7 @@ export interface FetchStatusResult {
2724
2769
  *
2725
2770
  * Sections arrive as the server grouped them. The core keeps every section
2726
2771
  * because a bot can be carried by a `category` or `featured` section and by no
2727
- * other, so flattening is a consumer\'s decision, not the bridge\'s.
2772
+ * other, so flattening is a consumer's decision, not the bridge's.
2728
2773
  */
2729
2774
  export interface BotListResult {
2730
2775
  version: string;
@@ -2874,6 +2919,28 @@ export interface OrderResult {
2874
2919
  creationTimestamp?: number;
2875
2920
  }
2876
2921
 
2922
+ /**
2923
+ * Result from `getUsername`: this account's own Meta username.
2924
+ *
2925
+ * Every field is optional because the server omits the ones that do not
2926
+ * apply. An account with no username at all comes back as `null` from the
2927
+ * method rather than as an all-absent object.
2928
+ */
2929
+ export interface OwnUsernameResult {
2930
+ /**
2931
+ * The handle, without the display-only `@` prefix.
2932
+ */
2933
+ username?: string;
2934
+ /**
2935
+ * `ACTIVE` or `RESERVED`.
2936
+ */
2937
+ state?: string;
2938
+ /**
2939
+ * The numeric username key that guards lookups of this account by handle.
2940
+ */
2941
+ key?: string;
2942
+ }
2943
+
2877
2944
  /**
2878
2945
  * Result from `groupRequestParticipantsList`.
2879
2946
  */
@@ -2887,7 +2954,7 @@ export interface MembershipRequestResult {
2887
2954
  *
2888
2955
  * Mirrors the core `IsOnWhatsAppResult` so callers get the LID/PN counterpart
2889
2956
  * and business flag from the same usync round trip — no follow-up
2890
- * `fetchUserInfo` IQ needed for the common \"check + enrich\" flow.
2957
+ * `fetchUserInfo` IQ needed for the common "check + enrich" flow.
2891
2958
  */
2892
2959
  export interface IsOnWhatsAppResult {
2893
2960
  jid: string;
@@ -2906,6 +2973,11 @@ export interface IsOnWhatsAppResult {
2906
2973
  * Verified business name from the usync `<business><verified_name>` cert, if any.
2907
2974
  */
2908
2975
  verifiedName?: string;
2976
+ /**
2977
+ * Meta username, without the display-only `@` prefix. Absent when the
2978
+ * server reported none, which is also how it reports a deleted one.
2979
+ */
2980
+ username?: string;
2909
2981
  }
2910
2982
 
2911
2983
  /**
@@ -2978,14 +3050,14 @@ export interface CommunityLinkResult {
2978
3050
  /**
2979
3051
  * Selects which `ClientProfile` preset to use for the noise-handshake
2980
3052
  * `ClientPayload.UserAgent`. Independent of `DeviceProps`: `setDeviceProps`
2981
- * controls the \"Linked Devices\" display on the phone, this controls what
3053
+ * controls the "Linked Devices" display on the phone, this controls what
2982
3054
  * the server sees in the noise layer.
2983
3055
  *
2984
- * Use `{ preset: \'android\', osVersion: \'13\' }` to advertise
3056
+ * Use `{ preset: 'android', osVersion: '13' }` to advertise
2985
3057
  * `UserAgent.platform = ANDROID` with `web_info` omitted.
2986
3058
  *
2987
3059
  * Every variant flattens the [`ClientProfileOverrides`] fields, so the
2988
- * JS literal is flat (e.g. `{ preset: \'web\', phoneId: \'fixed-id\' }`).
3060
+ * JS literal is flat (e.g. `{ preset: 'web', phoneId: 'fixed-id' }`).
2989
3061
  */
2990
3062
  export type ClientProfileInput = ({ preset: "web" } & {} & ClientProfileOverrides) | ({ preset: "android" } & { osVersion: string } & ClientProfileOverrides) | ({ preset: "smbAndroid" } & { osVersion: string } & ClientProfileOverrides) | ({ preset: "ios" } & { osVersion: string } & ClientProfileOverrides) | ({ preset: "macos" } & { osVersion: string } & ClientProfileOverrides) | ({ preset: "windows" } & { osVersion: string } & ClientProfileOverrides);
2991
3063
 
@@ -3006,6 +3078,12 @@ export interface SignalSignedPreKeyInput {
3006
3078
  signature: Uint8Array;
3007
3079
  }
3008
3080
 
3081
+ /**
3082
+ * Terminal protocol cause the reader captured before its expected-disconnect
3083
+ * flag suppressed the transport outcome.
3084
+ */
3085
+ export type ProtocolTerminalReasonResult = { kind: "stream-error"; code: number } | { kind: "connect-failure"; reason: string } | { kind: "conflict" } | { kind: "unknown"; detail: string };
3086
+
3009
3087
  /**
3010
3088
  * The bot the server marks as the one to offer by default.
3011
3089
  */
@@ -3033,20 +3111,67 @@ export interface CoverPhotoUploadInput {
3033
3111
  }
3034
3112
 
3035
3113
  /**
3036
- * What the client\'s connection state means for work handed to it now.
3114
+ * What `findByUsername` learned about a Meta username.
3115
+ *
3116
+ * Mirrors the core `UsernameLookup`, which is a three-way answer rather than
3117
+ * an optional user: a username the server confirms but will not resolve
3118
+ * without the account's username key is neither a hit nor a miss.
3119
+ */
3120
+ export type UsernameLookupResult = { status: "notFound" } | { status: "keyRequired"; username?: string } | { status: "found"; jid: string; pnJid?: string; username?: string; isBusiness: boolean; verifiedName?: string };
3121
+
3122
+ /**
3123
+ * What the client's connection state means for work handed to it now.
3037
3124
  *
3038
- * The core\'s `Reachability`, carried across unflattened. A refused call says
3125
+ * The core's `Reachability`, carried across unflattened. A refused call says
3039
3126
  * what happened to that attempt; this says what the client is, which is the
3040
3127
  * only thing that answers whether asking again is worth it — so it is read
3041
3128
  * when the question comes up rather than stamped onto an error that is a fact
3042
3129
  * about one instant.
3043
3130
  *
3044
- * `unknown` is not one of the core\'s: the enum is `#[non_exhaustive]`, and a
3131
+ * `unknown` is not one of the core's: the enum is `#[non_exhaustive]`, and a
3045
3132
  * state added upstream has no name here yet. Naming the gap beats reporting it
3046
3133
  * as one of its neighbours.
3047
3134
  */
3048
3135
  export type Reachability = "reachable" | "reconnecting" | "paused" | "unsupervised" | "finished" | "unknown";
3049
3136
 
3137
+ /**
3138
+ * Which core Noise handshake step failed, for a `core` handshake failure.
3139
+ */
3140
+ export type NoiseHandshakeFailureResult = { kind: "proto-decode"; message: string } | { kind: "incomplete-response" } | { kind: "crypto"; detail: string } | { kind: "cert-verification"; detail: string } | { kind: "invalid-length"; name: string; expected: number; got: number } | { kind: "invalid-key-length" } | { kind: "noise"; message: string };
3141
+
3142
+ /**
3143
+ * Which handshake step failed, for a `handshake` connect error.
3144
+ */
3145
+ export type HandshakeFailureResult = { kind: "transport"; message: string } | { kind: "core"; reason: NoiseHandshakeFailureResult } | { kind: "timeout" } | { kind: "stream-closed" } | { kind: "disconnected" } | { kind: "unexpected-event"; detail: string } | { kind: "unknown"; detail: string };
3146
+
3147
+ /**
3148
+ * Why a connection attempt failed, as the final attempt reported it.
3149
+ *
3150
+ * `anyhow` causes cross as their rendered message: the detail is diagnostic
3151
+ * text, not a boundary contract.
3152
+ */
3153
+ export type ConnectErrorResult = { kind: "already-connected" } | { kind: "not-activated" } | { kind: "shutdown" } | { kind: "paused" } | { kind: "timeout"; stage: string; timeoutMs: number } | { kind: "version"; message: string } | { kind: "transport"; message: string } | { kind: "handshake"; reason: HandshakeFailureResult } | { kind: "unknown"; detail: string };
3154
+
3155
+ /**
3156
+ * Why the supervised run loop started by `run()` ended.
3157
+ *
3158
+ * The core's `RunCompletionReason`, carried across unflattened: the
3159
+ * discriminant says which branch ended the run, and only the
3160
+ * `auto-reconnect-disabled` branch carries causes. Every cause is typed at
3161
+ * the boundary (no `Debug` rendering), and every absence is an absent key.
3162
+ * `generation` keys the result to the `run()` call that produced it; a stale
3163
+ * task can never overwrite a newer run's result.
3164
+ *
3165
+ * `unknown` is not one of the core's: the enum is `#[non_exhaustive]`, and a
3166
+ * reason added upstream has no shape here yet.
3167
+ */
3168
+ export type RunCompletionResult = { reason: "shutdown-requested"; generation: number } | { reason: "auto-reconnect-disabled"; generation: number; connection?: DisconnectReasonResult; connectError?: ConnectErrorResult; protocolError?: ProtocolTerminalReasonResult } | { reason: "stopped"; generation: number } | { reason: "already-running"; generation: number } | { reason: "unknown"; generation: number; detail: string };
3169
+
3170
+ /**
3171
+ * Why the transport connection ended, as the final reader observed it.
3172
+ */
3173
+ export type DisconnectReasonResult = { kind: "server-close"; code?: number; reason: string } | { kind: "stream-ended" } | { kind: "read-error"; message: string } | { kind: "unknown" };
3174
+
3050
3175
  export interface AllocationBucketSnapshot {
3051
3176
  allocatedBytes: number;
3052
3177
  allocations: number;
@@ -3082,7 +3207,7 @@ export interface HistorySyncAllocationSnapshot {
3082
3207
  largestCompressedBytes: number;
3083
3208
  largestDecompressedBytes: number;
3084
3209
  /**
3085
- * Compressed history events waiting in the bridge\'s ordered event queue.
3210
+ * Compressed history events waiting in the bridge's ordered event queue.
3086
3211
  */
3087
3212
  queuedEvents: number;
3088
3213
  queuedCompressedBytes: number;
@@ -3330,7 +3455,7 @@ export interface WasmAllocationSnapshot {
3330
3455
  largestAllocationBytes: number;
3331
3456
  /**
3332
3457
  * Mutually exclusive allocation-site buckets. Core task allocation is a
3333
- * second measurement through the core\'s `AllocMeter`, exposed on the
3458
+ * second measurement through the core's `AllocMeter`, exposed on the
3334
3459
  * client for cross-checking this host-side scope.
3335
3460
  */
3336
3461
  other: AllocationBucketSnapshot;
@@ -3386,6 +3511,7 @@ export type WhatsAppEvent =
3386
3511
  | { type: 'self_push_name_updated'; data: SelfPushNameUpdated }
3387
3512
  | { type: 'offline_sync_preview'; data: OfflineSyncPreview }
3388
3513
  | { type: 'offline_sync_completed'; data: OfflineSyncCompleted }
3514
+ | { type: 'offline_sync_interrupted'; data: OfflineSyncInterrupted }
3389
3515
  | { type: 'dirty_state'; data: { dirty_type: DirtyType; timestamp?: number | null } }
3390
3516
  | { type: 'device_list_update'; data: DeviceListUpdate }
3391
3517
  | { type: 'identity_change'; data: IdentityChange }
@@ -3436,7 +3562,7 @@ export type WhatsAppEvent =
3436
3562
  | { type: 'qr_scanned_without_multidevice'; data: Record<string, never> }
3437
3563
  | { type: 'client_outdated'; data: Record<string, never> }
3438
3564
  | { type: 'raw_node'; data: { tag: string; attrs: Record<string, string>; content?: unknown } }
3439
- | { type: 'history_sync'; data: import('./proto-types').proto.IHistorySync & { syncType: number; chunkOrder?: number; progress?: number; peerDataRequestSessionId?: string } }
3565
+ | { type: 'history_sync'; data: import('./proto-types.js').proto.IHistorySync & { syncType: number; chunkOrder?: number; progress?: number; peerDataRequestSessionId?: string } }
3440
3566
  | { type: 'pairing_code_error'; data: PairingCodeError }
3441
3567
  ;
3442
3568
 
@@ -3678,6 +3804,19 @@ export class WasmWhatsAppClient {
3678
3804
  * Fetch user status/about text for one or more JIDs.
3679
3805
  */
3680
3806
  fetchStatus(jids: string[]): Promise<FetchStatusResult[]>;
3807
+ /**
3808
+ * Resolve a Meta username to the account behind it.
3809
+ *
3810
+ * **Experimental.** The core builds the request exactly as WhatsApp Web
3811
+ * does, but no capture of a server answering it backs the implementation,
3812
+ * so a rejection here is not necessarily a bug.
3813
+ *
3814
+ * `username` is the bare handle; a leading `@` is display-only and the
3815
+ * core strips it. `usernameKey` is the account's numeric username key,
3816
+ * which some accounts require before the server discloses an identity at
3817
+ * all — without it the answer is `{ status: "keyRequired" }`.
3818
+ */
3819
+ findByUsername(username: string, username_key?: string | null): Promise<UsernameLookupResult>;
3681
3820
  /**
3682
3821
  * Get the ADV signed device identity (account), if available.
3683
3822
  * Exposes the persisted account identity to credential consumers.
@@ -3763,6 +3902,15 @@ export class WasmWhatsAppClient {
3763
3902
  * query takes neither.
3764
3903
  */
3765
3904
  getUSyncDevices(jids: string[], _use_cache: boolean, _ignore_zero_devices: boolean): Promise<any>;
3905
+ /**
3906
+ * Read this account's own Meta username, its state and its username key.
3907
+ *
3908
+ * `null` means no username is set: the server answers 404 and the core
3909
+ * reads it that way. Only the read is exposed — setting a username or its
3910
+ * key changes the account's identity in a way the server does not undo,
3911
+ * so the core leaves those two MEX operations unwrapped.
3912
+ */
3913
+ getUsername(): Promise<OwnUsernameResult | undefined>;
3766
3914
  /**
3767
3915
  * Join a group using an invite code.
3768
3916
  */
@@ -4437,6 +4585,31 @@ export class WasmWhatsAppClient {
4437
4585
  * connection is fully ready. Rejects with `kind === 'timeout'` on expiry.
4438
4586
  */
4439
4587
  waitForConnected(timeout_ms: number): Promise<void>;
4588
+ /**
4589
+ * Wait for the supervised run loop started by `run()` to end, and report
4590
+ * why it ended.
4591
+ *
4592
+ * Resolves with the core's own completion reason, typed per branch: only
4593
+ * `auto-reconnect-disabled` carries causes, and every absence is an
4594
+ * absent key. The result is stored at termination, so a waiter that
4595
+ * arrives after the run already ended reads the same completion, and any
4596
+ * number of simultaneous waiters each receive it.
4597
+ *
4598
+ * A plain function returning a `Promise`, so the pending wait holds no
4599
+ * borrow on the client: `disconnect()`, `free()` and a second `run()`
4600
+ * all reach the client while it is outstanding.
4601
+ *
4602
+ * Three endings are told apart. A resolved promise is always the
4603
+ * supervision's own completion. The bridge cancelling its waiter is a
4604
+ * rejection on exactly one path: the host freed the client while the
4605
+ * wait was pending, reported as `not-connected`. The host tearing down
4606
+ * after the call returned is not awaited here and is not claimed. A
4607
+ * manual `connect()` drives one connection outside supervision and never
4608
+ * touches this observation.
4609
+ *
4610
+ * Rejects with `invalid-argument` when `run()` was never called.
4611
+ */
4612
+ waitForRunCompletion(): Promise<RunCompletionResult>;
4440
4613
  /**
4441
4614
  * Wait until the socket is connected, or the timeout elapses.
4442
4615
  *
@@ -4571,7 +4744,7 @@ export interface InitOutput {
4571
4744
  readonly beginWasmAllocationProfile: () => void;
4572
4745
  readonly calculateAgreement: (a: number, b: number, c: number, d: number, e: number) => void;
4573
4746
  readonly calculateSignature: (a: number, b: number, c: number, d: number, e: number) => void;
4574
- readonly createWhatsAppClient: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number;
4747
+ readonly createWhatsAppClient: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
4575
4748
  readonly decodeSenderKeyRecordComponents: (a: number, b: number, c: number) => void;
4576
4749
  readonly decodeSessionRecordComponents: (a: number, b: number, c: number) => void;
4577
4750
  readonly decryptEventResponsePayload: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => void;
@@ -4579,8 +4752,8 @@ export interface InitOutput {
4579
4752
  readonly decryptPollVotePayload: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number) => void;
4580
4753
  readonly encodeSenderKeyRecordComponents: (a: number, b: number) => void;
4581
4754
  readonly encodeSessionRecordComponents: (a: number, b: number) => void;
4582
- readonly generateKeyPair: () => number;
4583
- readonly getEnabledFeatures: () => number;
4755
+ readonly generateKeyPair: (a: number) => void;
4756
+ readonly getEnabledFeatures: (a: number) => void;
4584
4757
  readonly getPublicFromPrivateKey: (a: number, b: number, c: number) => void;
4585
4758
  readonly getWasmAllocationSnapshot: (a: number) => void;
4586
4759
  readonly hasLogger: () => number;
@@ -4629,13 +4802,14 @@ export interface InitOutput {
4629
4802
  readonly wasmwhatsappclient_fetchReachoutTimelock: (a: number) => number;
4630
4803
  readonly wasmwhatsappclient_fetchStatus: (a: number, b: number, c: number) => number;
4631
4804
  readonly wasmwhatsappclient_fetchUserInfo: (a: number, b: number, c: number) => number;
4805
+ readonly wasmwhatsappclient_findByUsername: (a: number, b: number, c: number, d: number, e: number) => number;
4632
4806
  readonly wasmwhatsappclient_getAccount: (a: number) => number;
4633
4807
  readonly wasmwhatsappclient_getBotList: (a: number) => number;
4634
4808
  readonly wasmwhatsappclient_getBusinessProfile: (a: number, b: number, c: number) => number;
4635
4809
  readonly wasmwhatsappclient_getCatalog: (a: number, b: number, c: number, d: number) => number;
4636
4810
  readonly wasmwhatsappclient_getCollections: (a: number, b: number, c: number, d: number) => number;
4637
4811
  readonly wasmwhatsappclient_getCommunitySubgroups: (a: number, b: number, c: number) => number;
4638
- readonly wasmwhatsappclient_getCoreAllocationSnapshot: (a: number) => number;
4812
+ readonly wasmwhatsappclient_getCoreAllocationSnapshot: (a: number, b: number) => void;
4639
4813
  readonly wasmwhatsappclient_getGroupMetadata: (a: number, b: number, c: number) => number;
4640
4814
  readonly wasmwhatsappclient_getJid: (a: number) => number;
4641
4815
  readonly wasmwhatsappclient_getLid: (a: number) => number;
@@ -4644,6 +4818,7 @@ export interface InitOutput {
4644
4818
  readonly wasmwhatsappclient_getOrder: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => number;
4645
4819
  readonly wasmwhatsappclient_getPushName: (a: number) => number;
4646
4820
  readonly wasmwhatsappclient_getUSyncDevices: (a: number, b: number, c: number, d: number, e: number) => number;
4821
+ readonly wasmwhatsappclient_getUsername: (a: number) => number;
4647
4822
  readonly wasmwhatsappclient_groupAcceptInvite: (a: number, b: number, c: number) => number;
4648
4823
  readonly wasmwhatsappclient_groupAcceptInviteV4: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => number;
4649
4824
  readonly wasmwhatsappclient_groupFetchAllParticipating: (a: number) => number;
@@ -4698,7 +4873,7 @@ export interface InitOutput {
4698
4873
  readonly wasmwhatsappclient_profilePictureUrl: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
4699
4874
  readonly wasmwhatsappclient_queryNode: (a: number, b: number, c: number, d: number) => number;
4700
4875
  readonly wasmwhatsappclient_queryUsync: (a: number, b: number) => number;
4701
- readonly wasmwhatsappclient_reachability: (a: number) => number;
4876
+ readonly wasmwhatsappclient_reachability: (a: number, b: number) => void;
4702
4877
  readonly wasmwhatsappclient_readMessages: (a: number, b: number) => number;
4703
4878
  readonly wasmwhatsappclient_reconnect: (a: number) => number;
4704
4879
  readonly wasmwhatsappclient_refreshPreKeys: (a: number, b: number) => number;
@@ -4767,6 +4942,7 @@ export interface InitOutput {
4767
4942
  readonly wasmwhatsappclient_validateKeyBundle: (a: number) => number;
4768
4943
  readonly wasmwhatsappclient_votePoll: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => number;
4769
4944
  readonly wasmwhatsappclient_waitForConnected: (a: number, b: number) => number;
4945
+ readonly wasmwhatsappclient_waitForRunCompletion: (a: number) => number;
4770
4946
  readonly wasmwhatsappclient_waitForSocket: (a: number, b: number) => number;
4771
4947
  readonly wasmwhatsappclient_waitUntilReachable: (a: number) => number;
4772
4948
  readonly wasmwhatsappclient_withdrawParkedCalls: (a: number) => number;
@@ -4784,12 +4960,12 @@ export interface InitOutput {
4784
4960
  readonly intounderlyingsink_write: (a: number, b: number) => number;
4785
4961
  readonly intounderlyingsource_cancel: (a: number) => void;
4786
4962
  readonly intounderlyingsource_pull: (a: number, b: number) => number;
4787
- readonly __wasm_bindgen_func_elem_4420: (a: number, b: number, c: number) => void;
4788
- readonly __wasm_bindgen_func_elem_26654: (a: number, b: number, c: number, d: number) => void;
4789
- readonly __wasm_bindgen_func_elem_26656: (a: number, b: number, c: number, d: number) => void;
4790
- readonly __wasm_bindgen_func_elem_9413: (a: number, b: number, c: number) => void;
4791
- readonly __wasm_bindgen_func_elem_4419: (a: number, b: number, c: number) => void;
4792
- readonly __wasm_bindgen_func_elem_4418: (a: number, b: number) => void;
4963
+ readonly __wasm_bindgen_func_elem_4619: (a: number, b: number, c: number) => void;
4964
+ readonly __wasm_bindgen_func_elem_27691: (a: number, b: number, c: number, d: number) => void;
4965
+ readonly __wasm_bindgen_func_elem_27693: (a: number, b: number, c: number, d: number) => void;
4966
+ readonly __wasm_bindgen_func_elem_9785: (a: number, b: number, c: number) => void;
4967
+ readonly __wasm_bindgen_func_elem_4618: (a: number, b: number, c: number) => void;
4968
+ readonly __wasm_bindgen_func_elem_4617: (a: number, b: number) => void;
4793
4969
  readonly __wbindgen_export: (a: number, b: number) => number;
4794
4970
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
4795
4971
  readonly __wbindgen_export3: (a: number) => void;