Joey 3 settimane fa
commit
ca75580917
100 ha cambiato i file con 35297 aggiunte e 0 eliminazioni
  1. 13 0
      .editorconfig
  2. 3 0
      .gitattributes
  3. 8 0
      .idea/.gitignore
  4. 8 0
      .idea/modules.xml
  5. 6 0
      .idea/vcs.xml
  6. 9 0
      .idea/whatsmeow.iml
  7. 31 0
      .pre-commit-config.yaml
  8. 374 0
      LICENSE
  9. 35 0
      README.md
  10. 368 0
      app/accinfo.go
  11. 88 0
      app/mobilevo.go
  12. 32 0
      app/waver.go
  13. 501 0
      appstate.go
  14. 312 0
      appstate/decode.go
  15. 371 0
      appstate/encode.go
  16. 19 0
      appstate/errors.go
  17. 98 0
      appstate/hash.go
  18. 138 0
      appstate/keys.go
  19. 58 0
      appstate/lthash/lthash.go
  20. 0 0
      argo/argo-wire-type-store.argo
  21. 62 0
      argo/argo.go
  22. 306 0
      argo/name-to-queryids.json
  23. 133 0
      armadillomessage.go
  24. 218 0
      binary/attrs.go
  25. 406 0
      binary/decoder.go
  26. 308 0
      binary/encoder.go
  27. 12 0
      binary/errors.go
  28. 139 0
      binary/node.go
  29. 4 0
      binary/proto/doc.go
  30. 1084 0
      binary/proto/legacy.go
  31. 8 0
      binary/token/token.go
  32. 31 0
      binary/unpack.go
  33. 108 0
      binary/xml.go
  34. 143 0
      broadcast.go
  35. 121 0
      call.go
  36. 1047 0
      client.go
  37. 80 0
      client_test.go
  38. 229 0
      connectionevents.go
  39. 234 0
      download-to-file.go
  40. 417 0
      download.go
  41. 265 0
      errors.go
  42. 33 0
      go.mod
  43. 121 0
      go.sum
  44. 1067 0
      group.go
  45. 166 0
      handshake.go
  46. 736 0
      internals.go
  47. 211 0
      internals_generate.go
  48. 87 0
      keepalive.go
  49. 97 0
      mediaconn.go
  50. 185 0
      mediaretry.go
  51. 1046 0
      message.go
  52. 385 0
      msgsecret.go
  53. 455 0
      newsletter.go
  54. 466 0
      notification.go
  55. 243 0
      pair-code.go
  56. 271 0
      pair.go
  57. 277 0
      prekeys.go
  58. 148 0
      presence.go
  59. 169 0
      privacysettings.go
  60. 1 0
      proto/.gitignore
  61. 32 0
      proto/armadilloutil/decode.go
  62. 43 0
      proto/extra.go
  63. 983 0
      proto/instamadilloAddMessage/InstamadilloAddMessage.pb.go
  64. 85 0
      proto/instamadilloAddMessage/InstamadilloAddMessage.proto
  65. 3 0
      proto/instamadilloAddMessage/extra.go
  66. 197 0
      proto/instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.pb.go
  67. 13 0
      proto/instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.proto
  68. 279 0
      proto/instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.pb.go
  69. 21 0
      proto/instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.proto
  70. 137 0
      proto/instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.pb.go
  71. 10 0
      proto/instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.proto
  72. 313 0
      proto/instamadilloCoreTypeLink/InstamadilloCoreTypeLink.pb.go
  73. 27 0
      proto/instamadilloCoreTypeLink/InstamadilloCoreTypeLink.proto
  74. 1299 0
      proto/instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.pb.go
  75. 112 0
      proto/instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto
  76. 514 0
      proto/instamadilloCoreTypeText/InstamadilloCoreTypeText.pb.go
  77. 47 0
      proto/instamadilloCoreTypeText/InstamadilloCoreTypeText.proto
  78. 123 0
      proto/instamadilloDeleteMessage/InstamadilloDeleteMessage.pb.go
  79. 7 0
      proto/instamadilloDeleteMessage/InstamadilloDeleteMessage.proto
  80. 3 0
      proto/instamadilloDeleteMessage/extra.go
  81. 720 0
      proto/instamadilloSupplementMessage/InstamadilloSupplementMessage.pb.go
  82. 59 0
      proto/instamadilloSupplementMessage/InstamadilloSupplementMessage.proto
  83. 3 0
      proto/instamadilloSupplementMessage/extra.go
  84. 365 0
      proto/instamadilloTransportPayload/InstamadilloTransportPayload.pb.go
  85. 33 0
      proto/instamadilloTransportPayload/InstamadilloTransportPayload.proto
  86. 1238 0
      proto/instamadilloXmaContentRef/InstamadilloXmaContentRef.pb.go
  87. 105 0
      proto/instamadilloXmaContentRef/InstamadilloXmaContentRef.proto
  88. 8756 0
      proto/waAICommon/WAAICommon.pb.go
  89. 871 0
      proto/waAICommon/WAAICommon.proto
  90. 515 0
      proto/waAdv/WAAdv.pb.go
  91. 43 0
      proto/waAdv/WAAdv.proto
  92. 3285 0
      proto/waArmadilloApplication/WAArmadilloApplication.pb.go
  93. 283 0
      proto/waArmadilloApplication/WAArmadilloApplication.proto
  94. 3 0
      proto/waArmadilloApplication/extra.go
  95. 132 0
      proto/waArmadilloBackupCommon/WAArmadilloBackupCommon.pb.go
  96. 8 0
      proto/waArmadilloBackupCommon/WAArmadilloBackupCommon.proto
  97. 386 0
      proto/waArmadilloBackupMessage/WAArmadilloBackupMessage.pb.go
  98. 32 0
      proto/waArmadilloBackupMessage/WAArmadilloBackupMessage.proto
  99. 206 0
      proto/waArmadilloICDC/WAArmadilloICDC.pb.go
  100. 15 0
      proto/waArmadilloICDC/WAArmadilloICDC.proto

+ 13 - 0
.editorconfig

@@ -0,0 +1,13 @@
+root = true
+
+[*]
+indent_style = tab
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{yaml,yml}]
+indent_style = space
+indent_size = 2

+ 3 - 0
.gitattributes

@@ -0,0 +1,3 @@
+*.pb.go linguist-generated=true
+*.pb.raw binary linguist-generated=true
+internals.go linguist-generated=true

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/whatsmeow.iml" filepath="$PROJECT_DIR$/.idea/whatsmeow.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>

+ 9 - 0
.idea/whatsmeow.iml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="Go" enabled="true" />
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 31 - 0
.pre-commit-config.yaml

@@ -0,0 +1,31 @@
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v6.0.0
+    hooks:
+      - id: trailing-whitespace
+        exclude_types: [markdown]
+        exclude: LICENSE
+      - id: end-of-file-fixer
+        exclude: LICENSE
+      - id: check-yaml
+      - id: check-added-large-files
+
+  - repo: https://github.com/tekwizely/pre-commit-golang
+    rev: v1.0.0-rc.2
+    hooks:
+      - id: go-imports-repo
+        args:
+          - "-local"
+          - "go.mau.fi/whatsmeow"
+          - "-w"
+      - id: go-vet-repo-mod
+      # TODO enable this
+      #- id: go-staticcheck-repo-mod
+      - id: go-mod-tidy
+
+  - repo: https://github.com/beeper/pre-commit-go
+    rev: v0.4.2
+    hooks:
+      # TODO enable this
+      #- id: zerolog-ban-msgf
+      - id: zerolog-use-stringer

+ 374 - 0
LICENSE

@@ -0,0 +1,374 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in 
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
+

+ 35 - 0
README.md

@@ -0,0 +1,35 @@
+# whatsmeow
+[![Go Reference](https://pkg.go.dev/badge/go.mau.fi/whatsmeow.svg)](https://pkg.go.dev/go.mau.fi/whatsmeow)
+
+whatsmeow is a Go library for the WhatsApp web multidevice API.
+
+## Discussion
+Matrix room: [#whatsmeow:maunium.net](https://matrix.to/#/#whatsmeow:maunium.net)
+
+For questions about the WhatsApp protocol (like how to send a specific type of
+message), you can also use the [WhatsApp protocol Q&A] section on GitHub
+discussions.
+
+[WhatsApp protocol Q&A]: https://github.com/tulir/whatsmeow/discussions/categories/whatsapp-protocol-q-a
+
+## Usage
+The [godoc](https://pkg.go.dev/go.mau.fi/whatsmeow) includes docs for all methods and event types.
+There's also a [simple example](https://pkg.go.dev/go.mau.fi/whatsmeow#example-package) at the top.
+
+## Features
+Most core features are already present:
+
+* Sending messages to private chats and groups (both text and media)
+* Receiving all messages
+* Managing groups and receiving group change events
+* Joining via invite messages, using and creating invite links
+* Sending and receiving typing notifications
+* Sending and receiving delivery and read receipts
+* Reading and writing app state (contact list, chat pin/mute status, etc)
+* Sending and handling retry receipts if message decryption fails
+* Sending status messages (experimental, may not work for large contact lists)
+
+Things that are not yet implemented:
+
+* Sending broadcast list messages (this is not supported on WhatsApp web either)
+* Calls

+ 368 - 0
app/accinfo.go

@@ -0,0 +1,368 @@
+package app
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	waProto "git.bobomao.top/joey/whatsmeow/binary/proto"
+	"github.com/gogf/gf/util/gconv"
+	"github.com/golang/protobuf/proto"
+	"github.com/ulule/deepcopier"
+	"log"
+)
+
+// IsEmpty
+func IsEmpty(s string) bool {
+	return s == "" || len(s) <= 0
+}
+
+type AuthDataDto struct {
+	*ClientPayload
+}
+
+type AuthDataDtoActual struct {
+	*waProto.ClientPayload
+}
+
+// LoginDto 登录信息
+type LoginDto struct {
+	// socks 5 代理
+	UUID           string
+	Socks5         string
+	AuthBody       *AuthDataDto
+	AuthBodyActual *AuthDataDtoActual
+	// AuthHexData 握手认证数据
+	AuthHexData string
+	// StaticPriKey 认证私钥
+	StaticPriKey string
+	// StaticPubKey 认证公钥
+	StaticPubKey string
+	//注册返回
+	ClientStaticKeypair string
+	//EdgeRouting
+	EdgeRouting string
+	//
+	IdentityPubKey string
+	IdentityPriKey string
+	Hash           string
+}
+
+func (loginDto *LoginDto) Init() {
+	loginDto.AuthBodyActual = &AuthDataDtoActual{
+		ClientPayload: &waProto.ClientPayload{
+			UserAgent: &waProto.ClientPayload_UserAgent{
+				AppVersion: &waProto.ClientPayload_UserAgent_AppVersion{},
+			},
+		},
+	}
+	//playload := loginDto.AuthBodyActual.ClientPayload
+	//playloadActual := loginDto.AuthBodyActual.ClientPayload
+	playload := loginDto.AuthBody.ClientPayload
+	playloadActual := loginDto.AuthBodyActual.ClientPayload
+	deepcopier.Copy(playload).To(playloadActual)
+	deepcopier.Copy(playload.UserAgent).To(playloadActual.UserAgent)
+	deepcopier.Copy(playload.UserAgent.AppVersion).To(playloadActual.UserAgent.AppVersion)
+	playloadActual.UserAgent.Platform = (*waProto.ClientPayload_UserAgent_Platform)(playload.UserAgent.Platform)
+
+	//playload
+
+}
+
+type DHKey struct {
+	Private []byte
+	Public  []byte
+}
+
+var DHString = []byte{69, 68, 0, 1}
+var InitString = []byte("WA")
+
+type VerifyCallbackFunc func(publicKey []byte, data []byte) error
+
+// WAProtocolVersion noise 握手版本
+type WAProtocolVersion struct {
+	// 主要版本
+	VersionMajor byte
+	// 次要版本
+	VersionMinor byte
+}
+
+type WAHandshakeSettings struct {
+	RoutingInfo []byte
+	//认证数据
+	Payload []byte //certificates, signs etc
+	// 用户注册时生成的公私秘钥
+	StaticKey DHKey
+	// 服务器公钥
+	PeerStatic []byte
+}
+
+// loginInfo
+type loginInfo struct {
+	ctx context.Context
+	// login info
+	clientPayload  *waProto.ClientPayload
+	priKey, pubKey []byte
+	routingInfo    []byte
+	staticPubKey   *[32]byte
+	staticPriKey   *[32]byte
+}
+
+func (l *loginInfo) GetStaticPubKey() *[32]byte {
+	return l.staticPubKey
+}
+
+func (l *loginInfo) SetStaticPubKey(d string) error {
+	data, err := base64.StdEncoding.DecodeString(d)
+	if err != nil {
+		return err
+	}
+	if len(data) == 33 {
+		data = data[1:]
+	}
+	var byteArray [32]byte
+	copy(byteArray[:], data)
+	l.staticPubKey = &byteArray
+	return nil
+}
+func (l *loginInfo) GetStaticPriKey() *[32]byte {
+	return l.staticPriKey
+}
+func (l *loginInfo) SetStaticPriKey(d string) error {
+	data, err := base64.StdEncoding.DecodeString(d)
+	if err != nil {
+		return err
+	}
+	if len(data) == 33 {
+		data = data[1:]
+	}
+	var byteArray [32]byte
+	copy(byteArray[:], data)
+	l.staticPriKey = &byteArray
+	return nil
+}
+
+func (l *loginInfo) Ctx() context.Context {
+	return l.ctx
+}
+
+func (l *loginInfo) SetRoutingInfo(d []byte) {
+	l.routingInfo = d
+}
+
+func (l *loginInfo) SetStaticHdBase64Keys(pri, pub string) error {
+	priData, err := base64.StdEncoding.DecodeString(pri)
+	if err != nil {
+		return err
+	}
+	pubData, err := base64.StdEncoding.DecodeString(pub)
+	if err != nil {
+		return err
+	}
+
+	if len(priData) != 32 || len(pubData) < 32 {
+		return errors.New("keys length less than 32 bit")
+	}
+
+	if len(pubData) == 33 {
+		pubData = pubData[1:]
+	}
+	if len(priData) == 33 {
+		priData = priData[1:]
+	}
+	// set keys
+	l.priKey, l.pubKey = priData, pubData
+	return nil
+}
+
+func (l *loginInfo) SetStaticHdKeys(pri, pub []byte) error {
+	if len(pri) != 32 || len(pub) != 32 {
+		return errors.New("keys length less than 32 bit")
+	}
+	// set keys
+	l.priKey, l.pubKey = pri, pub
+	return nil
+}
+
+// SetStaticKeys
+func (l *loginInfo) SetStaticKeys(base64Data string) error {
+	skData, err := base64.StdEncoding.DecodeString(base64Data)
+	if err != nil {
+		return err
+	}
+	// if sk data length not 64
+	if len(skData) < 64 {
+		return errors.New("static keys length less than 64 bit")
+	}
+	// set static keys
+	l.priKey, l.pubKey = skData[:32], skData[32:]
+	return nil
+}
+
+func (l *loginInfo) SetCliPayload(payload *waProto.ClientPayload) {
+	if payload != nil {
+		l.clientPayload = payload
+	}
+}
+
+// SetCliPayloadData
+func (l *loginInfo) SetCliPayloadData(data []byte) error {
+	return proto.Unmarshal(data, l.clientPayload)
+}
+
+// GetLoginSettings
+func (l *loginInfo) GetLoginSettings() *WAHandshakeSettings {
+	return &WAHandshakeSettings{
+		RoutingInfo: l.routingInfo,
+		Payload:     l.buildClientPayload(),
+		StaticKey: DHKey{
+			Private: l.priKey,
+			Public:  l.pubKey,
+		},
+		PeerStatic: []byte{},
+	}
+}
+
+func (l *loginInfo) buildClientPayload() []byte {
+	if l.clientPayload == nil {
+		return nil
+	}
+	d, _ := json.MarshalIndent(&l.clientPayload, " ", "  ")
+	log.Println("AUTHDATA:", string(d))
+	//db.PushQueue(
+	//	db.PushMsg{
+	//		Time:     time.Now().Unix(),
+	//		UserName: l.clientPayload.GetUsername(),
+	//		Type:     db.System.Number(),
+	//		Data:     l.clientPayload,
+	//	},
+	//)
+	// marshal
+	payloadData, err := proto.Marshal(l.clientPayload)
+	if err != nil {
+		return nil
+	}
+	log.Println("payloadData", hex.EncodeToString(payloadData))
+	return payloadData
+}
+
+// AccountInfo
+type AccountInfo struct {
+	*loginInfo
+	verifiedName uint64
+}
+
+func EmptyAccountInfo() *AccountInfo {
+	return &AccountInfo{
+		loginInfo: &loginInfo{
+			ctx:           context.Background(),
+			clientPayload: &waProto.ClientPayload{},
+			priKey:        []byte{},
+			pubKey:        []byte{},
+			routingInfo:   []byte{},
+		}}
+}
+
+// GetUserName
+func (a *AccountInfo) GetUserName() string {
+	if a.clientPayload != nil {
+		return gconv.String(a.clientPayload.GetUsername())
+	}
+	return ""
+}
+func (a *AccountInfo) GetVeriFiledName() uint64 {
+	if a.verifiedName != 0 {
+		return a.verifiedName
+	}
+	return 0
+}
+func (a *AccountInfo) SetVeriFiledName(VeriFiledName uint64) {
+	a.verifiedName = VeriFiledName
+}
+
+// 获取平台
+func (a *AccountInfo) GetPlatform() string {
+	if a.clientPayload != nil {
+		return a.clientPayload.GetUserAgent().GetPlatform().String()
+	}
+	return "no"
+}
+
+// SetLogCtx
+func (a *AccountInfo) SetLogCtx(k, v string) {
+	a.ctx = context.WithValue(a.ctx, k, v)
+}
+
+func (a *AccountInfo) SetUserName(u uint64) {
+	if a.clientPayload != nil {
+		a.clientPayload.Username = proto.Uint64(u)
+		//a.clientPayload.SessionId = proto.Int32(0x0e844d0f)
+
+		//a.clientPayload.UserAgent.PhoneId = proto.String("90196710-7a70-45cf-8d8e-364c40d79296")
+	}
+}
+
+func (a *AccountInfo) GetStaticKeys() *DHKey {
+	return &DHKey{
+		Private: a.loginInfo.priKey,
+		Public:  a.loginInfo.pubKey,
+	}
+}
+
+func (a *AccountInfo) GetClientPayload() *waProto.ClientPayload {
+	return a.clientPayload
+}
+
+// GenAuthDataService 生成认证数据
+func GenAuthDataService(payload *waProto.ClientPayload) error {
+	// check parameters
+	if payload.GetUsername() == 0 || IsEmpty(payload.GetPushName()) {
+		return errors.New("IncompleteParametersCode")
+	}
+	// check user agent
+	userAgent := payload.GetUserAgent()
+	if userAgent == nil || IsEmpty(userAgent.GetDevice()) ||
+		IsEmpty(userAgent.GetOsBuildNumber()) ||
+		IsEmpty(userAgent.GetManufacturer()) ||
+		IsEmpty(userAgent.GetPhoneID()) ||
+		IsEmpty(userAgent.GetOsVersion()) {
+		return errors.New("IncompleteParametersCode")
+	}
+	// set other parameters
+	payload.ShortConnect = proto.Bool(false)
+	wifi := waProto.ClientPayload_WIFI_UNKNOWN
+	payload.ConnectType = &wifi
+	// set app version
+	platform := userAgent.GetPlatform().String()
+	//如果为安卓普通版
+	if platform == "ANDROID" {
+		payload.UserAgent.AppVersion.Primary = proto.Uint32(GetVersion42().Primary)
+		payload.UserAgent.AppVersion.Secondary = proto.Uint32(GetVersion42().Secondary)
+		payload.UserAgent.AppVersion.Tertiary = proto.Uint32(GetVersion42().Tertiary)
+		payload.UserAgent.AppVersion.Quaternary = proto.Uint32(GetVersion42().Quaternary)
+		payload.Oc = proto.Bool(true)
+		payload.Lc = proto.Int32(1)
+		payload.YearClass = proto.Int32(2016)
+		payload.MemClass = proto.Int32(256)
+	} else if platform == "SMB_ANDROID" {
+		//安卓企业版
+		payload.UserAgent.AppVersion.Primary = proto.Uint32(GetBusinessVersion42().Primary)
+		payload.UserAgent.AppVersion.Secondary = proto.Uint32(GetBusinessVersion42().Secondary)
+		payload.UserAgent.AppVersion.Tertiary = proto.Uint32(GetBusinessVersion42().Tertiary)
+		payload.UserAgent.AppVersion.Quaternary = proto.Uint32(GetBusinessVersion42().Quaternary)
+	} else {
+		//return vo.AnErrorOccurred(fmt.Errorf("platform参数不正确%s", payload.UserAgent.Platform.String()))
+		return errors.New(fmt.Sprintf("platform参数不正确%s", payload.UserAgent.Platform.String()))
+	}
+	fmt.Sprintln("platform参数=%s", payload.UserAgent.Platform.String())
+	// set locale
+	if payload.UserAgent.LocaleLanguageIso6391 == nil {
+		payload.UserAgent.LocaleLanguageIso6391 = proto.String("zh")
+	}
+	if payload.UserAgent.LocaleCountryIso31661Alpha2 == nil {
+		payload.UserAgent.LocaleCountryIso31661Alpha2 = proto.String("CN")
+	}
+	return nil
+}

+ 88 - 0
app/mobilevo.go

@@ -0,0 +1,88 @@
+package app
+
+type ClientPayload_UserAgent_AppVersion struct {
+	Primary              *uint32  `protobuf:"varint,1,opt,name=primary" json:"primary,omitempty"`
+	Secondary            *uint32  `protobuf:"varint,2,opt,name=secondary" json:"secondary,omitempty"`
+	Tertiary             *uint32  `protobuf:"varint,3,opt,name=tertiary" json:"tertiary,omitempty"`
+	Quaternary           *uint32  `protobuf:"varint,4,opt,name=quaternary" json:"quaternary,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+type ClientPayload_UserAgent struct {
+	Platform                    *int32                              `protobuf:"varint,1,opt,name=platform,enum=int32" json:"platform,omitempty"`
+	AppVersion                  *ClientPayload_UserAgent_AppVersion `protobuf:"bytes,2,opt,name=app_version,json=appVersion" json:"app_version,omitempty"`
+	Mcc                         *string                             `protobuf:"bytes,3,opt,name=mcc" json:"mcc,omitempty"`
+	Mnc                         *string                             `protobuf:"bytes,4,opt,name=mnc" json:"mnc,omitempty"`
+	OsVersion                   *string                             `protobuf:"bytes,5,opt,name=os_version,json=osVersion" json:"os_version,omitempty"`
+	Manufacturer                *string                             `protobuf:"bytes,6,opt,name=manufacturer" json:"manufacturer,omitempty"`
+	Device                      *string                             `protobuf:"bytes,7,opt,name=device" json:"device,omitempty"`
+	OsBuildNumber               *string                             `protobuf:"bytes,8,opt,name=os_build_number,json=osBuildNumber" json:"os_build_number,omitempty"`
+	PhoneId                     *string                             `protobuf:"bytes,9,opt,name=phone_id,json=phoneId" json:"phone_id,omitempty"`
+	ReleaseChannel              *int32                              `protobuf:"varint,10,opt,name=release_channel,json=releaseChannel,enum=int32" json:"release_channel,omitempty"`
+	LocaleLanguageIso6391       *string                             `protobuf:"bytes,11,opt,name=locale_language_iso_639_1,json=localeLanguageIso6391" json:"locale_language_iso_639_1,omitempty"`
+	LocaleCountryIso31661Alpha2 *string                             `protobuf:"bytes,12,opt,name=locale_country_iso_3166_1_alpha_2,json=localeCountryIso31661Alpha2" json:"locale_country_iso_3166_1_alpha_2,omitempty"`
+	XXX_NoUnkeyedLiteral        struct{}                            `json:"-"`
+	XXX_unrecognized            []byte                              `json:"-"`
+	XXX_sizecache               int32                               `json:"-"`
+}
+
+type ClientPayload_WebInfo struct {
+	RefToken             *string                            `protobuf:"bytes,1,opt,name=ref_token,json=refToken" json:"ref_token,omitempty"`
+	Version              *string                            `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"`
+	WebdPayload          *ClientPayload_WebInfo_WebdPayload `protobuf:"bytes,3,opt,name=webd_payload,json=webdPayload" json:"webd_payload,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}                           `json:"-"`
+	XXX_unrecognized     []byte                             `json:"-"`
+	XXX_sizecache        int32                              `json:"-"`
+}
+
+type ClientPayload_WebInfo_WebdPayload struct {
+	UsesParticipantInKey     *bool    `protobuf:"varint,1,opt,name=uses_participant_in_key,json=usesParticipantInKey" json:"uses_participant_in_key,omitempty"`
+	SupportsStarredMessages  *bool    `protobuf:"varint,2,opt,name=supports_starred_messages,json=supportsStarredMessages" json:"supports_starred_messages,omitempty"`
+	SupportsDocumentMessages *bool    `protobuf:"varint,3,opt,name=supports_document_messages,json=supportsDocumentMessages" json:"supports_document_messages,omitempty"`
+	SupportsUrlMessages      *bool    `protobuf:"varint,4,opt,name=supports_url_messages,json=supportsUrlMessages" json:"supports_url_messages,omitempty"`
+	SupportsMediaRetry       *bool    `protobuf:"varint,5,opt,name=supports_media_retry,json=supportsMediaRetry" json:"supports_media_retry,omitempty"`
+	SupportsE2EImage         *bool    `protobuf:"varint,6,opt,name=supports_e2e_image,json=supportsE2eImage" json:"supports_e2e_image,omitempty"`
+	SupportsE2EVideo         *bool    `protobuf:"varint,7,opt,name=supports_e2e_video,json=supportsE2eVideo" json:"supports_e2e_video,omitempty"`
+	SupportsE2EAudio         *bool    `protobuf:"varint,8,opt,name=supports_e2e_audio,json=supportsE2eAudio" json:"supports_e2e_audio,omitempty"`
+	SupportsE2EDocument      *bool    `protobuf:"varint,9,opt,name=supports_e2e_document,json=supportsE2eDocument" json:"supports_e2e_document,omitempty"`
+	DocumentTypes            *string  `protobuf:"bytes,10,opt,name=document_types,json=documentTypes" json:"document_types,omitempty"`
+	XXX_NoUnkeyedLiteral     struct{} `json:"-"`
+	XXX_unrecognized         []byte   `json:"-"`
+	XXX_sizecache            int32    `json:"-"`
+}
+
+type ClientPayload_DnsSource struct {
+	DnsMethod            *int32   `protobuf:"varint,15,opt,name=dnsMethod,enum=int32" json:"dnsMethod,omitempty"`
+	AppCached            *bool    `protobuf:"varint,16,opt,name=appCached" json:"appCached,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+type ClientPayload struct {
+	Username             *uint64                  `protobuf:"varint,1,opt,name=username" json:"username,omitempty"`
+	Passive              *bool                    `protobuf:"varint,3,opt,name=passive" json:"passive,omitempty"`
+	ClientFeatures       []int32                  `protobuf:"varint,4,rep,name=client_features,json=clientFeatures,enum=int32" json:"client_features,omitempty"`
+	UserAgent            *ClientPayload_UserAgent `protobuf:"bytes,5,opt,name=user_agent,json=userAgent" json:"user_agent,omitempty"`
+	WebInfo              *ClientPayload_WebInfo   `protobuf:"bytes,6,opt,name=web_info,json=webInfo" json:"web_info,omitempty"`
+	PushName             *string                  `protobuf:"bytes,7,opt,name=push_name,json=pushName" json:"push_name,omitempty"`
+	SessionId            *int32                   `protobuf:"fixed32,9,opt,name=session_id,json=sessionId" json:"session_id,omitempty"`
+	ShortConnect         *bool                    `protobuf:"varint,10,opt,name=short_connect,json=shortConnect" json:"short_connect,omitempty"`
+	ConnectType          *int32                   `protobuf:"varint,12,opt,name=connect_type,json=connectType,enum=int32" json:"connect_type,omitempty"`
+	ConnectReason        *int32                   `protobuf:"varint,13,opt,name=connect_reason,json=connectReason,enum=int32" json:"connect_reason,omitempty"`
+	Shards               []int32                  `protobuf:"fixed32,14,rep,name=shards" json:"shards,omitempty"`
+	DnsSource            *ClientPayload_DnsSource `protobuf:"bytes,15,opt,name=dns_source,json=dnsSource" json:"dns_source,omitempty"`
+	ConnectAttemptCount  *int32                   `protobuf:"fixed32,16,opt,name=connect_attempt_count,json=connectAttemptCount" json:"connect_attempt_count,omitempty"`
+	Oc                   *bool                    `protobuf:"varint,23,opt,name=oc" json:"oc,omitempty"`
+	Lc                   *int32                   `protobuf:"varint,24,opt,name=lc" json:"lc,omitempty"`
+	IosAppExtension      *int32                   `protobuf:"varint,30,opt,name=ios_app_extension,json=iosAppExtension,enum=int32" json:"ios_app_extension,omitempty"`
+	FbAppId              *uint64                  `protobuf:"varint,31,opt,name=fb_app_id,json=fbAppId" json:"fb_app_id,omitempty"`
+	FbDeviceId           []byte                   `protobuf:"bytes,32,opt,name=fb_device_id,json=fbDeviceId" json:"fb_device_id,omitempty"`
+	YearClass            *int32                   `protobuf:"varint,36,opt,name=ok_36,json=ok36" json:"ok_36,omitempty"`
+	MemClass             *int32                   `protobuf:"varint,37,opt,name=ok_37,json=ok37" json:"ok_37,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}                 `json:"-"`
+	XXX_unrecognized     []byte                   `json:"-"`
+	XXX_sizecache        int32                    `json:"-"`
+}

+ 32 - 0
app/waver.go

@@ -0,0 +1,32 @@
+package app
+
+type Version42 struct {
+	Primary    uint32
+	Secondary  uint32
+	Tertiary   uint32
+	Quaternary uint32
+}
+
+var waVer = "2.25.31.72"
+
+var versionH = &Version42{Primary: 2, Secondary: 25, Tertiary: 31, Quaternary: 72}
+
+func GetVersion42() *Version42 {
+	return versionH
+}
+
+// 企业版
+type BusinessVersion42 struct {
+	Primary    uint32
+	Secondary  uint32
+	Tertiary   uint32
+	Quaternary uint32
+}
+
+var businessWaVer = "2.25.31.72"
+
+var businessVersion = &BusinessVersion42{Primary: 2, Secondary: 25, Tertiary: 31, Quaternary: 72}
+
+func GetBusinessVersion42() *BusinessVersion42 {
+	return businessVersion
+}

+ 501 - 0
appstate.go

@@ -0,0 +1,501 @@
+// Copyright (c) 2022 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"time"
+
+	"github.com/rs/zerolog"
+
+	"go.mau.fi/whatsmeow/appstate"
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/proto/waServerSync"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+// FetchAppState fetches updates to the given type of app state. If fullSync is true, the current
+// cached state will be removed and all app state patches will be re-fetched from the server.
+func (cli *Client) FetchAppState(ctx context.Context, name appstate.WAPatchName, fullSync, onlyIfNotSynced bool) error {
+	eventsToDispatch, err := cli.fetchAppState(ctx, name, fullSync, onlyIfNotSynced)
+	if err != nil {
+		return err
+	}
+	for _, evt := range eventsToDispatch {
+		cli.dispatchEvent(evt)
+	}
+	return nil
+}
+
+func (cli *Client) fetchAppState(ctx context.Context, name appstate.WAPatchName, fullSync, onlyIfNotSynced bool) ([]any, error) {
+	if cli == nil {
+		return nil, ErrClientIsNil
+	}
+	cli.appStateSyncLock.Lock()
+	defer cli.appStateSyncLock.Unlock()
+	if fullSync {
+		err := cli.Store.AppState.DeleteAppStateVersion(ctx, string(name))
+		if err != nil {
+			return nil, fmt.Errorf("failed to reset app state %s version: %w", name, err)
+		}
+	}
+	version, hash, err := cli.Store.AppState.GetAppStateVersion(ctx, string(name))
+	if err != nil {
+		return nil, fmt.Errorf("failed to get app state %s version: %w", name, err)
+	}
+	if version == 0 {
+		fullSync = true
+	} else if onlyIfNotSynced {
+		return nil, nil
+	}
+
+	state := appstate.HashState{Version: version, Hash: hash}
+
+	hasMore := true
+	wantSnapshot := fullSync
+	var eventsToDispatch []any
+	eventsToDispatchPtr := &eventsToDispatch
+	if fullSync && !cli.EmitAppStateEventsOnFullSync {
+		eventsToDispatchPtr = nil
+	}
+	for hasMore {
+		patches, err := cli.fetchAppStatePatches(ctx, name, state.Version, wantSnapshot)
+		wantSnapshot = false
+		if err != nil {
+			return nil, fmt.Errorf("failed to fetch app state %s patches: %w", name, err)
+		}
+		hasMore = patches.HasMorePatches
+		state, err = cli.applyAppStatePatches(ctx, name, state, patches, fullSync, eventsToDispatchPtr)
+		if err != nil {
+			return nil, err
+		}
+	}
+	if fullSync {
+		cli.Log.Debugf("Full sync of app state %s completed. Current version: %d", name, state.Version)
+		eventsToDispatch = append(eventsToDispatch, &events.AppStateSyncComplete{Name: name})
+	} else {
+		cli.Log.Debugf("Synced app state %s from version %d to %d", name, version, state.Version)
+	}
+	return eventsToDispatch, nil
+}
+
+func (cli *Client) applyAppStatePatches(
+	ctx context.Context,
+	name appstate.WAPatchName,
+	state appstate.HashState,
+	patches *appstate.PatchList,
+	fullSync bool,
+	eventsToDispatch *[]any,
+) (appstate.HashState, error) {
+	mutations, newState, err := cli.appStateProc.DecodePatches(ctx, patches, state, true)
+	if err != nil {
+		if errors.Is(err, appstate.ErrKeyNotFound) {
+			go cli.requestMissingAppStateKeys(context.WithoutCancel(ctx), patches)
+		}
+		return state, fmt.Errorf("failed to decode app state %s patches: %w", name, err)
+	}
+	wasFullSync := state.Version == 0 && patches.Snapshot != nil
+	state = newState
+	if name == appstate.WAPatchCriticalUnblockLow && wasFullSync && !cli.EmitAppStateEventsOnFullSync {
+		var contacts []store.ContactEntry
+		mutations, contacts = cli.filterContacts(mutations)
+		cli.Log.Debugf("Mass inserting app state snapshot with %d contacts into the store", len(contacts))
+		err = cli.Store.Contacts.PutAllContactNames(ctx, contacts)
+		if err != nil {
+			// This is a fairly serious failure, so just abort the whole thing
+			return state, fmt.Errorf("failed to update contact store with data from snapshot: %v", err)
+		}
+	}
+	for _, mutation := range mutations {
+		if eventsToDispatch != nil && mutation.Operation == waServerSync.SyncdMutation_SET {
+			*eventsToDispatch = append(*eventsToDispatch, &events.AppState{Index: mutation.Index, SyncActionValue: mutation.Action})
+		}
+		evt := cli.dispatchAppState(ctx, mutation, fullSync)
+		if eventsToDispatch != nil && evt != nil {
+			*eventsToDispatch = append(*eventsToDispatch, evt)
+		}
+	}
+	return state, nil
+}
+
+func (cli *Client) filterContacts(mutations []appstate.Mutation) ([]appstate.Mutation, []store.ContactEntry) {
+	filteredMutations := mutations[:0]
+	contacts := make([]store.ContactEntry, 0, len(mutations))
+	for _, mutation := range mutations {
+		if mutation.Index[0] == "contact" && len(mutation.Index) > 1 {
+			jid, _ := types.ParseJID(mutation.Index[1])
+			act := mutation.Action.GetContactAction()
+			contacts = append(contacts, store.ContactEntry{
+				JID:       jid,
+				FirstName: act.GetFirstName(),
+				FullName:  act.GetFullName(),
+			})
+		} else {
+			filteredMutations = append(filteredMutations, mutation)
+		}
+	}
+	return filteredMutations, contacts
+}
+
+func (cli *Client) dispatchAppState(ctx context.Context, mutation appstate.Mutation, fullSync bool) (eventToDispatch any) {
+	zerolog.Ctx(ctx).Trace().Any("mutation", mutation).Msg("Dispatching app state mutation")
+
+	if mutation.Operation != waServerSync.SyncdMutation_SET {
+		return
+	}
+
+	var jid types.JID
+	if len(mutation.Index) > 1 {
+		jid, _ = types.ParseJID(mutation.Index[1])
+	}
+	ts := time.UnixMilli(mutation.Action.GetTimestamp())
+
+	var storeUpdateError error
+	switch mutation.Index[0] {
+	case appstate.IndexMute:
+		act := mutation.Action.GetMuteAction()
+		eventToDispatch = &events.Mute{JID: jid, Timestamp: ts, Action: act, FromFullSync: fullSync}
+		var mutedUntil time.Time
+		if act.GetMuted() {
+			if act.GetMuteEndTimestamp() < 0 {
+				mutedUntil = store.MutedForever
+			} else {
+				mutedUntil = time.UnixMilli(act.GetMuteEndTimestamp())
+			}
+		}
+		if cli.Store.ChatSettings != nil {
+			storeUpdateError = cli.Store.ChatSettings.PutMutedUntil(ctx, jid, mutedUntil)
+		}
+	case appstate.IndexPin:
+		act := mutation.Action.GetPinAction()
+		eventToDispatch = &events.Pin{JID: jid, Timestamp: ts, Action: act, FromFullSync: fullSync}
+		if cli.Store.ChatSettings != nil {
+			storeUpdateError = cli.Store.ChatSettings.PutPinned(ctx, jid, act.GetPinned())
+		}
+	case appstate.IndexArchive:
+		act := mutation.Action.GetArchiveChatAction()
+		eventToDispatch = &events.Archive{JID: jid, Timestamp: ts, Action: act, FromFullSync: fullSync}
+		if cli.Store.ChatSettings != nil {
+			storeUpdateError = cli.Store.ChatSettings.PutArchived(ctx, jid, act.GetArchived())
+		}
+	case appstate.IndexContact:
+		act := mutation.Action.GetContactAction()
+		eventToDispatch = &events.Contact{JID: jid, Timestamp: ts, Action: act, FromFullSync: fullSync}
+		if cli.Store.Contacts != nil {
+			storeUpdateError = cli.Store.Contacts.PutContactName(ctx, jid, act.GetFirstName(), act.GetFullName())
+		}
+	case appstate.IndexClearChat:
+		act := mutation.Action.GetClearChatAction()
+		eventToDispatch = &events.ClearChat{JID: jid, Timestamp: ts, Action: act, FromFullSync: fullSync}
+	case appstate.IndexDeleteChat:
+		act := mutation.Action.GetDeleteChatAction()
+		eventToDispatch = &events.DeleteChat{JID: jid, Timestamp: ts, Action: act, FromFullSync: fullSync}
+	case appstate.IndexStar:
+		if len(mutation.Index) < 5 {
+			return
+		}
+		evt := events.Star{
+			ChatJID:      jid,
+			MessageID:    mutation.Index[2],
+			Timestamp:    ts,
+			Action:       mutation.Action.GetStarAction(),
+			IsFromMe:     mutation.Index[3] == "1",
+			FromFullSync: fullSync,
+		}
+		if mutation.Index[4] != "0" {
+			evt.SenderJID, _ = types.ParseJID(mutation.Index[4])
+		}
+		eventToDispatch = &evt
+	case appstate.IndexDeleteMessageForMe:
+		if len(mutation.Index) < 5 {
+			return
+		}
+		evt := events.DeleteForMe{
+			ChatJID:      jid,
+			MessageID:    mutation.Index[2],
+			Timestamp:    ts,
+			Action:       mutation.Action.GetDeleteMessageForMeAction(),
+			IsFromMe:     mutation.Index[3] == "1",
+			FromFullSync: fullSync,
+		}
+		if mutation.Index[4] != "0" {
+			evt.SenderJID, _ = types.ParseJID(mutation.Index[4])
+		}
+		eventToDispatch = &evt
+	case appstate.IndexMarkChatAsRead:
+		eventToDispatch = &events.MarkChatAsRead{
+			JID:          jid,
+			Timestamp:    ts,
+			Action:       mutation.Action.GetMarkChatAsReadAction(),
+			FromFullSync: fullSync,
+		}
+	case appstate.IndexSettingPushName:
+		eventToDispatch = &events.PushNameSetting{
+			Timestamp:    ts,
+			Action:       mutation.Action.GetPushNameSetting(),
+			FromFullSync: fullSync,
+		}
+		cli.Store.PushName = mutation.Action.GetPushNameSetting().GetName()
+		err := cli.Store.Save(ctx)
+		if err != nil {
+			cli.Log.Errorf("Failed to save device store after updating push name: %v", err)
+		}
+	case appstate.IndexSettingUnarchiveChats:
+		eventToDispatch = &events.UnarchiveChatsSetting{
+			Timestamp:    ts,
+			Action:       mutation.Action.GetUnarchiveChatsSetting(),
+			FromFullSync: fullSync,
+		}
+	case appstate.IndexUserStatusMute:
+		eventToDispatch = &events.UserStatusMute{
+			JID:          jid,
+			Timestamp:    ts,
+			Action:       mutation.Action.GetUserStatusMuteAction(),
+			FromFullSync: fullSync,
+		}
+	case appstate.IndexLabelEdit:
+		act := mutation.Action.GetLabelEditAction()
+		eventToDispatch = &events.LabelEdit{
+			Timestamp:    ts,
+			LabelID:      mutation.Index[1],
+			Action:       act,
+			FromFullSync: fullSync,
+		}
+	case appstate.IndexLabelAssociationChat:
+		if len(mutation.Index) < 3 {
+			return
+		}
+		jid, _ = types.ParseJID(mutation.Index[2])
+		act := mutation.Action.GetLabelAssociationAction()
+		eventToDispatch = &events.LabelAssociationChat{
+			JID:          jid,
+			Timestamp:    ts,
+			LabelID:      mutation.Index[1],
+			Action:       act,
+			FromFullSync: fullSync,
+		}
+	case appstate.IndexLabelAssociationMessage:
+		if len(mutation.Index) < 6 {
+			return
+		}
+		jid, _ = types.ParseJID(mutation.Index[2])
+		act := mutation.Action.GetLabelAssociationAction()
+		eventToDispatch = &events.LabelAssociationMessage{
+			JID:          jid,
+			Timestamp:    ts,
+			LabelID:      mutation.Index[1],
+			MessageID:    mutation.Index[3],
+			Action:       act,
+			FromFullSync: fullSync,
+		}
+	}
+	if storeUpdateError != nil {
+		cli.Log.Errorf("Failed to update device store after app state mutation: %v", storeUpdateError)
+	}
+	return
+}
+
+func (cli *Client) downloadExternalAppStateBlob(ctx context.Context, ref *waServerSync.ExternalBlobReference) ([]byte, error) {
+	return cli.Download(ctx, ref)
+}
+
+func (cli *Client) fetchAppStatePatches(ctx context.Context, name appstate.WAPatchName, fromVersion uint64, snapshot bool) (*appstate.PatchList, error) {
+	attrs := waBinary.Attrs{
+		"name":            string(name),
+		"return_snapshot": snapshot,
+	}
+	if !snapshot {
+		attrs["version"] = fromVersion
+	}
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "w:sync:app:state",
+		Type:      "set",
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "sync",
+			Content: []waBinary.Node{{
+				Tag:   "collection",
+				Attrs: attrs,
+			}},
+		}},
+	})
+	if err != nil {
+		return nil, err
+	}
+	collection, ok := resp.GetOptionalChildByTag("sync", "collection")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "collection", In: "app state patch response"}
+	}
+	return appstate.ParsePatchList(ctx, &collection, cli.downloadExternalAppStateBlob)
+}
+
+func (cli *Client) requestMissingAppStateKeys(ctx context.Context, patches *appstate.PatchList) {
+	cli.appStateKeyRequestsLock.Lock()
+	rawKeyIDs := cli.appStateProc.GetMissingKeyIDs(ctx, patches)
+	filteredKeyIDs := make([][]byte, 0, len(rawKeyIDs))
+	now := time.Now()
+	for _, keyID := range rawKeyIDs {
+		stringKeyID := hex.EncodeToString(keyID)
+		lastRequestTime := cli.appStateKeyRequests[stringKeyID]
+		if lastRequestTime.IsZero() || lastRequestTime.Add(24*time.Hour).Before(now) {
+			cli.appStateKeyRequests[stringKeyID] = now
+			filteredKeyIDs = append(filteredKeyIDs, keyID)
+		}
+	}
+	cli.appStateKeyRequestsLock.Unlock()
+	cli.requestAppStateKeys(ctx, filteredKeyIDs)
+}
+
+func (cli *Client) requestAppStateKeys(ctx context.Context, rawKeyIDs [][]byte) {
+	keyIDs := make([]*waE2E.AppStateSyncKeyId, len(rawKeyIDs))
+	debugKeyIDs := make([]string, len(rawKeyIDs))
+	for i, keyID := range rawKeyIDs {
+		keyIDs[i] = &waE2E.AppStateSyncKeyId{KeyID: keyID}
+		debugKeyIDs[i] = hex.EncodeToString(keyID)
+	}
+	msg := &waE2E.Message{
+		ProtocolMessage: &waE2E.ProtocolMessage{
+			Type: waE2E.ProtocolMessage_APP_STATE_SYNC_KEY_REQUEST.Enum(),
+			AppStateSyncKeyRequest: &waE2E.AppStateSyncKeyRequest{
+				KeyIDs: keyIDs,
+			},
+		},
+	}
+	ownID := cli.getOwnID().ToNonAD()
+	if ownID.IsEmpty() || len(debugKeyIDs) == 0 {
+		return
+	}
+	cli.Log.Infof("Sending key request for app state keys %+v", debugKeyIDs)
+	_, err := cli.SendMessage(ctx, ownID, msg, SendRequestExtra{Peer: true})
+	if err != nil {
+		cli.Log.Warnf("Failed to send app state key request: %v", err)
+	}
+}
+
+// SendAppState sends the given app state patch, then triggers a background resync of that app state type
+// to update local caches and send events for the updates.
+//
+// You can use the Build methods in the appstate package to build the parameter for this method, e.g.
+//
+//	cli.SendAppState(ctx, appstate.BuildMute(targetJID, true, 24 * time.Hour))
+func (cli *Client) SendAppState(ctx context.Context, patch appstate.PatchInfo) error {
+	return cli.sendAppState(ctx, patch, true)
+}
+
+func (cli *Client) sendAppState(ctx context.Context, patch appstate.PatchInfo, allowRetry bool) error {
+	if cli == nil {
+		return ErrClientIsNil
+	}
+	version, hash, err := cli.Store.AppState.GetAppStateVersion(ctx, string(patch.Type))
+	if err != nil {
+		return err
+	}
+	// TODO create new key instead of reusing the primary client's keys
+	latestKeyID, err := cli.Store.AppStateKeys.GetLatestAppStateSyncKeyID(ctx)
+	if err != nil {
+		return fmt.Errorf("failed to get latest app state key ID: %w", err)
+	} else if latestKeyID == nil {
+		return fmt.Errorf("no app state keys found, creating app state keys is not yet supported")
+	}
+
+	state := appstate.HashState{Version: version, Hash: hash}
+
+	encodedPatch, err := cli.appStateProc.EncodePatch(ctx, latestKeyID, state, patch)
+	if err != nil {
+		return err
+	}
+
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "w:sync:app:state",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "sync",
+			Content: []waBinary.Node{{
+				Tag: "collection",
+				Attrs: waBinary.Attrs{
+					"name":            string(patch.Type),
+					"version":         version,
+					"return_snapshot": false,
+				},
+				Content: []waBinary.Node{{
+					Tag:     "patch",
+					Content: encodedPatch,
+				}},
+			}},
+		}},
+	})
+	if err != nil {
+		return err
+	}
+
+	respCollection, ok := resp.GetOptionalChildByTag("sync", "collection")
+	if !ok {
+		return &ElementMissingError{Tag: "collection", In: "app state send response"}
+	}
+	respCollectionAttr := respCollection.AttrGetter()
+	if respCollectionAttr.OptionalString("type") == "error" {
+		errorTag, ok := respCollection.GetOptionalChildByTag("error")
+
+		mainErr := fmt.Errorf("%w: %s", ErrAppStateUpdate, respCollection.XMLString())
+		if ok {
+			mainErr = fmt.Errorf("%w (%s): %s", ErrAppStateUpdate, patch.Type, errorTag.XMLString())
+		}
+		if ok && errorTag.AttrGetter().Int("code") == 409 && allowRetry {
+			zerolog.Ctx(ctx).Warn().Err(mainErr).Msg("Failed to update app state, trying to apply conflicts and retry")
+			var eventsToDispatch []any
+			patches, err := appstate.ParsePatchList(ctx, &respCollection, cli.downloadExternalAppStateBlob)
+			if err != nil {
+				return fmt.Errorf("%w (also, parsing patches in the response failed: %w)", mainErr, err)
+			} else if state, err = cli.applyAppStatePatches(ctx, patch.Type, state, patches, false, &eventsToDispatch); err != nil {
+				return fmt.Errorf("%w (also, applying patches in the response failed: %w)", mainErr, err)
+			} else {
+				zerolog.Ctx(ctx).Debug().Msg("Retrying app state send after applying conflicting patches")
+				go func() {
+					for _, evt := range eventsToDispatch {
+						cli.dispatchEvent(evt)
+					}
+				}()
+				return cli.sendAppState(ctx, patch, false)
+			}
+		}
+		return mainErr
+	}
+	eventsToDispatch, err := cli.fetchAppState(ctx, patch.Type, false, false)
+	if err != nil {
+		return fmt.Errorf("failed to fetch app state after sending update: %w", err)
+	}
+	go func() {
+		for _, evt := range eventsToDispatch {
+			cli.dispatchEvent(evt)
+		}
+	}()
+
+	return nil
+}
+
+func (cli *Client) MarkNotDirty(ctx context.Context, cleanType string, ts time.Time) error {
+	_, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "urn:xmpp:whatsapp:dirty",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "clean",
+			Attrs: waBinary.Attrs{
+				"type":      cleanType,
+				"timestamp": ts.Unix(),
+			},
+		}},
+	})
+	return err
+}

+ 312 - 0
appstate/decode.go

@@ -0,0 +1,312 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package appstate
+
+import (
+	"bytes"
+	"context"
+	"crypto/sha256"
+	"encoding/json"
+	"fmt"
+
+	"google.golang.org/protobuf/proto"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waServerSync"
+	"go.mau.fi/whatsmeow/proto/waSyncAction"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/util/cbcutil"
+)
+
+// PatchList represents a decoded response to getting app state patches from the WhatsApp servers.
+type PatchList struct {
+	Name           WAPatchName
+	HasMorePatches bool
+	Patches        []*waServerSync.SyncdPatch
+	Snapshot       *waServerSync.SyncdSnapshot
+}
+
+// DownloadExternalFunc is a function that can download a blob of external app state patches.
+type DownloadExternalFunc func(context.Context, *waServerSync.ExternalBlobReference) ([]byte, error)
+
+func parseSnapshotInternal(ctx context.Context, collection *waBinary.Node, downloadExternal DownloadExternalFunc) (*waServerSync.SyncdSnapshot, error) {
+	snapshotNode := collection.GetChildByTag("snapshot")
+	rawSnapshot, ok := snapshotNode.Content.([]byte)
+	if snapshotNode.Tag != "snapshot" || !ok {
+		return nil, nil
+	}
+	var snapshot waServerSync.ExternalBlobReference
+	err := proto.Unmarshal(rawSnapshot, &snapshot)
+	if err != nil {
+		return nil, fmt.Errorf("failed to unmarshal snapshot: %w", err)
+	}
+	var rawData []byte
+	rawData, err = downloadExternal(ctx, &snapshot)
+	if err != nil {
+		return nil, fmt.Errorf("failed to download external mutations: %w", err)
+	}
+	var downloaded waServerSync.SyncdSnapshot
+	err = proto.Unmarshal(rawData, &downloaded)
+	if err != nil {
+		return nil, fmt.Errorf("failed to unmarshal mutation list: %w", err)
+	}
+	return &downloaded, nil
+}
+
+func parsePatchListInternal(ctx context.Context, collection *waBinary.Node, downloadExternal DownloadExternalFunc) ([]*waServerSync.SyncdPatch, error) {
+	patchesNode := collection.GetChildByTag("patches")
+	patchNodes := patchesNode.GetChildren()
+	patches := make([]*waServerSync.SyncdPatch, 0, len(patchNodes))
+	for i, patchNode := range patchNodes {
+		rawPatch, ok := patchNode.Content.([]byte)
+		if patchNode.Tag != "patch" || !ok {
+			continue
+		}
+		var patch waServerSync.SyncdPatch
+		err := proto.Unmarshal(rawPatch, &patch)
+		if err != nil {
+			return nil, fmt.Errorf("failed to unmarshal patch #%d: %w", i+1, err)
+		}
+		if patch.GetExternalMutations() != nil && downloadExternal != nil {
+			var rawData []byte
+			rawData, err = downloadExternal(ctx, patch.GetExternalMutations())
+			if err != nil {
+				return nil, fmt.Errorf("failed to download external mutations: %w", err)
+			}
+			var downloaded waServerSync.SyncdMutations
+			err = proto.Unmarshal(rawData, &downloaded)
+			if err != nil {
+				return nil, fmt.Errorf("failed to unmarshal mutation list: %w", err)
+			} else if len(downloaded.GetMutations()) == 0 {
+				return nil, fmt.Errorf("didn't get any mutations from download")
+			}
+			patch.Mutations = downloaded.Mutations
+		}
+		patches = append(patches, &patch)
+	}
+	return patches, nil
+}
+
+// ParsePatchList will decode an XML node containing app state patches, including downloading any external blobs.
+func ParsePatchList(ctx context.Context, collection *waBinary.Node, downloadExternal DownloadExternalFunc) (*PatchList, error) {
+	ag := collection.AttrGetter()
+	snapshot, err := parseSnapshotInternal(ctx, collection, downloadExternal)
+	if err != nil {
+		return nil, err
+	}
+	patches, err := parsePatchListInternal(ctx, collection, downloadExternal)
+	if err != nil {
+		return nil, err
+	}
+	list := &PatchList{
+		Name:           WAPatchName(ag.String("name")),
+		HasMorePatches: ag.OptionalBool("has_more_patches"),
+		Patches:        patches,
+		Snapshot:       snapshot,
+	}
+	return list, ag.Error()
+}
+
+type patchOutput struct {
+	RemovedMACs [][]byte
+	AddedMACs   []store.AppStateMutationMAC
+	Mutations   []Mutation
+}
+
+func (proc *Processor) decodeMutations(ctx context.Context, mutations []*waServerSync.SyncdMutation, out *patchOutput, validateMACs bool) error {
+	for i, mutation := range mutations {
+		keyID := mutation.GetRecord().GetKeyID().GetID()
+		keys, err := proc.getAppStateKey(ctx, keyID)
+		if err != nil {
+			return fmt.Errorf("failed to get key %X to decode mutation: %w", keyID, err)
+		}
+		content := mutation.GetRecord().GetValue().GetBlob()
+		content, valueMAC := content[:len(content)-32], content[len(content)-32:]
+		if validateMACs {
+			expectedValueMAC := generateContentMAC(mutation.GetOperation(), content, keyID, keys.ValueMAC)
+			if !bytes.Equal(expectedValueMAC, valueMAC) {
+				return fmt.Errorf("failed to verify mutation #%d: %w", i+1, ErrMismatchingContentMAC)
+			}
+		}
+		iv, content := content[:16], content[16:]
+		plaintext, err := cbcutil.Decrypt(keys.ValueEncryption, iv, content)
+		if err != nil {
+			return fmt.Errorf("failed to decrypt mutation #%d: %w", i+1, err)
+		}
+		var syncAction waSyncAction.SyncActionData
+		err = proto.Unmarshal(plaintext, &syncAction)
+		if err != nil {
+			return fmt.Errorf("failed to unmarshal mutation #%d: %w", i+1, err)
+		}
+		indexMAC := mutation.GetRecord().GetIndex().GetBlob()
+		if validateMACs {
+			expectedIndexMAC := concatAndHMAC(sha256.New, keys.Index, syncAction.Index)
+			if !bytes.Equal(expectedIndexMAC, indexMAC) {
+				return fmt.Errorf("failed to verify mutation #%d: %w", i+1, ErrMismatchingIndexMAC)
+			}
+		}
+		var index []string
+		err = json.Unmarshal(syncAction.GetIndex(), &index)
+		if err != nil {
+			return fmt.Errorf("failed to unmarshal index of mutation #%d: %w", i+1, err)
+		}
+		if mutation.GetOperation() == waServerSync.SyncdMutation_REMOVE {
+			out.RemovedMACs = append(out.RemovedMACs, indexMAC)
+		} else if mutation.GetOperation() == waServerSync.SyncdMutation_SET {
+			out.AddedMACs = append(out.AddedMACs, store.AppStateMutationMAC{
+				IndexMAC: indexMAC,
+				ValueMAC: valueMAC,
+			})
+		}
+		out.Mutations = append(out.Mutations, Mutation{
+			Operation: mutation.GetOperation(),
+			Action:    syncAction.GetValue(),
+			Version:   syncAction.GetVersion(),
+			Index:     index,
+			IndexMAC:  indexMAC,
+			ValueMAC:  valueMAC,
+		})
+	}
+	return nil
+}
+
+func (proc *Processor) storeMACs(ctx context.Context, name WAPatchName, currentState HashState, out *patchOutput) {
+	err := proc.Store.AppState.PutAppStateVersion(ctx, string(name), currentState.Version, currentState.Hash)
+	if err != nil {
+		proc.Log.Errorf("Failed to update app state version in the database: %v", err)
+	}
+	err = proc.Store.AppState.DeleteAppStateMutationMACs(ctx, string(name), out.RemovedMACs)
+	if err != nil {
+		proc.Log.Errorf("Failed to remove deleted mutation MACs from the database: %v", err)
+	}
+	err = proc.Store.AppState.PutAppStateMutationMACs(ctx, string(name), currentState.Version, out.AddedMACs)
+	if err != nil {
+		proc.Log.Errorf("Failed to insert added mutation MACs to the database: %v", err)
+	}
+}
+
+func (proc *Processor) validateSnapshotMAC(ctx context.Context, name WAPatchName, currentState HashState, keyID, expectedSnapshotMAC []byte) (keys ExpandedAppStateKeys, err error) {
+	keys, err = proc.getAppStateKey(ctx, keyID)
+	if err != nil {
+		err = fmt.Errorf("failed to get key %X to verify patch v%d MACs: %w", keyID, currentState.Version, err)
+		return
+	}
+	snapshotMAC := currentState.generateSnapshotMAC(name, keys.SnapshotMAC)
+	if !bytes.Equal(snapshotMAC, expectedSnapshotMAC) {
+		err = fmt.Errorf("failed to verify patch v%d: %w", currentState.Version, ErrMismatchingLTHash)
+	}
+	return
+}
+
+func (proc *Processor) decodeSnapshot(ctx context.Context, name WAPatchName, ss *waServerSync.SyncdSnapshot, initialState HashState, validateMACs bool, newMutationsInput []Mutation) (newMutations []Mutation, currentState HashState, err error) {
+	currentState = initialState
+	currentState.Version = ss.GetVersion().GetVersion()
+
+	encryptedMutations := make([]*waServerSync.SyncdMutation, len(ss.GetRecords()))
+	for i, record := range ss.GetRecords() {
+		encryptedMutations[i] = &waServerSync.SyncdMutation{
+			Operation: waServerSync.SyncdMutation_SET.Enum(),
+			Record:    record,
+		}
+	}
+
+	var warn []error
+	warn, err = currentState.updateHash(encryptedMutations, func(indexMAC []byte, maxIndex int) ([]byte, error) {
+		return nil, nil
+	})
+	if len(warn) > 0 {
+		proc.Log.Warnf("Warnings while updating hash for %s: %+v", name, warn)
+	}
+	if err != nil {
+		err = fmt.Errorf("failed to update state hash: %w", err)
+		return
+	}
+
+	if validateMACs {
+		_, err = proc.validateSnapshotMAC(ctx, name, currentState, ss.GetKeyID().GetID(), ss.GetMac())
+		if err != nil {
+			return
+		}
+	}
+
+	var out patchOutput
+	out.Mutations = newMutationsInput
+	err = proc.decodeMutations(ctx, encryptedMutations, &out, validateMACs)
+	if err != nil {
+		err = fmt.Errorf("failed to decode snapshot of v%d: %w", currentState.Version, err)
+		return
+	}
+	proc.storeMACs(ctx, name, currentState, &out)
+	newMutations = out.Mutations
+	return
+}
+
+// DecodePatches will decode all the patches in a PatchList into a list of app state mutations.
+func (proc *Processor) DecodePatches(ctx context.Context, list *PatchList, initialState HashState, validateMACs bool) (newMutations []Mutation, currentState HashState, err error) {
+	currentState = initialState
+	var expectedLength int
+	if list.Snapshot != nil {
+		expectedLength = len(list.Snapshot.GetRecords())
+	}
+	for _, patch := range list.Patches {
+		expectedLength += len(patch.GetMutations())
+	}
+	newMutations = make([]Mutation, 0, expectedLength)
+
+	if list.Snapshot != nil {
+		newMutations, currentState, err = proc.decodeSnapshot(ctx, list.Name, list.Snapshot, currentState, validateMACs, newMutations)
+		if err != nil {
+			return
+		}
+	}
+
+	for _, patch := range list.Patches {
+		version := patch.GetVersion().GetVersion()
+		currentState.Version = version
+		var warn []error
+		warn, err = currentState.updateHash(patch.GetMutations(), func(indexMAC []byte, maxIndex int) ([]byte, error) {
+			for i := maxIndex - 1; i >= 0; i-- {
+				if bytes.Equal(patch.Mutations[i].GetRecord().GetIndex().GetBlob(), indexMAC) {
+					value := patch.Mutations[i].GetRecord().GetValue().GetBlob()
+					return value[len(value)-32:], nil
+				}
+			}
+			// Previous value not found in current patch, look in the database
+			return proc.Store.AppState.GetAppStateMutationMAC(ctx, string(list.Name), indexMAC)
+		})
+		if len(warn) > 0 {
+			proc.Log.Warnf("Warnings while updating hash for %s: %+v", list.Name, warn)
+		}
+		if err != nil {
+			err = fmt.Errorf("failed to update state hash: %w", err)
+			return
+		}
+
+		if validateMACs {
+			var keys ExpandedAppStateKeys
+			keys, err = proc.validateSnapshotMAC(ctx, list.Name, currentState, patch.GetKeyID().GetID(), patch.GetSnapshotMAC())
+			if err != nil {
+				return
+			}
+			patchMAC := generatePatchMAC(patch, list.Name, keys.PatchMAC, patch.GetVersion().GetVersion())
+			if !bytes.Equal(patchMAC, patch.GetPatchMAC()) {
+				err = fmt.Errorf("failed to verify patch v%d: %w", version, ErrMismatchingPatchMAC)
+				return
+			}
+		}
+
+		var out patchOutput
+		out.Mutations = newMutations
+		err = proc.decodeMutations(ctx, patch.GetMutations(), &out, validateMACs)
+		if err != nil {
+			return
+		}
+		proc.storeMACs(ctx, list.Name, currentState, &out)
+		newMutations = out.Mutations
+	}
+	return
+}

+ 371 - 0
appstate/encode.go

@@ -0,0 +1,371 @@
+package appstate
+
+import (
+	"context"
+	"crypto/sha256"
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"google.golang.org/protobuf/proto"
+
+	"go.mau.fi/whatsmeow/proto/waCommon"
+	"go.mau.fi/whatsmeow/proto/waServerSync"
+	"go.mau.fi/whatsmeow/proto/waSyncAction"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/util/cbcutil"
+)
+
+// MutationInfo contains information about a single mutation to the app state.
+type MutationInfo struct {
+	// Index contains the thing being mutated (like `mute` or `pin_v1`), followed by parameters like the target JID.
+	Index []string
+	// Version is a static number that depends on the thing being mutated.
+	Version int32
+	// Value contains the data for the mutation.
+	Value *waSyncAction.SyncActionValue
+}
+
+// PatchInfo contains information about a patch to the app state.
+// A patch can contain multiple mutations, as long as all mutations are in the same app state type.
+type PatchInfo struct {
+	// Timestamp is the time when the patch was created. This will be filled automatically in EncodePatch if it's zero.
+	Timestamp time.Time
+	// Type is the app state type being mutated.
+	Type WAPatchName
+	// Mutations contains the individual mutations to apply to the app state in this patch.
+	Mutations []MutationInfo
+}
+
+// BuildMute builds an app state patch for muting or unmuting a chat.
+//
+// If mute is true and the mute duration is zero, the chat is muted forever.
+func BuildMute(target types.JID, mute bool, muteDuration time.Duration) PatchInfo {
+	var muteEndTimestamp *int64
+	if muteDuration > 0 {
+		muteEndTimestamp = proto.Int64(time.Now().Add(muteDuration).UnixMilli())
+	}
+	return BuildMuteAbs(target, mute, muteEndTimestamp)
+}
+
+// BuildMuteAbs builds an app state patch for muting or unmuting a chat with an absolute timestamp.
+func BuildMuteAbs(target types.JID, mute bool, muteEndTimestamp *int64) PatchInfo {
+	if muteEndTimestamp == nil && mute {
+		muteEndTimestamp = proto.Int64(-1)
+	}
+	return PatchInfo{
+		Type: WAPatchRegularHigh,
+		Mutations: []MutationInfo{{
+			Index:   []string{IndexMute, target.String()},
+			Version: 2,
+			Value: &waSyncAction.SyncActionValue{
+				MuteAction: &waSyncAction.MuteAction{
+					Muted:            proto.Bool(mute),
+					MuteEndTimestamp: muteEndTimestamp,
+				},
+			},
+		}},
+	}
+}
+
+func newPinMutationInfo(target types.JID, pin bool) MutationInfo {
+	return MutationInfo{
+		Index:   []string{IndexPin, target.String()},
+		Version: 5,
+		Value: &waSyncAction.SyncActionValue{
+			PinAction: &waSyncAction.PinAction{
+				Pinned: &pin,
+			},
+		},
+	}
+}
+
+// BuildPin builds an app state patch for pinning or unpinning a chat.
+func BuildPin(target types.JID, pin bool) PatchInfo {
+	return PatchInfo{
+		Type: WAPatchRegularLow,
+		Mutations: []MutationInfo{
+			newPinMutationInfo(target, pin),
+		},
+	}
+}
+
+// BuildArchive builds an app state patch for archiving or unarchiving a chat.
+//
+// The last message timestamp and last message key are optional and can be set to zero values (`time.Time{}` and `nil`).
+//
+// Archiving a chat will also unpin it automatically.
+func BuildArchive(target types.JID, archive bool, lastMessageTimestamp time.Time, lastMessageKey *waCommon.MessageKey) PatchInfo {
+	archiveMutationInfo := MutationInfo{
+		Index:   []string{IndexArchive, target.String()},
+		Version: 3,
+		Value: &waSyncAction.SyncActionValue{
+			ArchiveChatAction: &waSyncAction.ArchiveChatAction{
+				Archived:     &archive,
+				MessageRange: newMessageRange(lastMessageTimestamp, lastMessageKey),
+				// TODO set LastSystemMessageTimestamp?
+			},
+		},
+	}
+
+	mutations := []MutationInfo{archiveMutationInfo}
+	if archive {
+		mutations = append(mutations, newPinMutationInfo(target, false))
+	}
+
+	result := PatchInfo{
+		Type:      WAPatchRegularLow,
+		Mutations: mutations,
+	}
+
+	return result
+}
+
+// BuildMarkChatAsRead builds an app state patch for marking a chat as read or unread.
+func BuildMarkChatAsRead(target types.JID, read bool, lastMessageTimestamp time.Time, lastMessageKey *waCommon.MessageKey) PatchInfo {
+	action := &waSyncAction.MarkChatAsReadAction{
+		Read:         proto.Bool(read),
+		MessageRange: newMessageRange(lastMessageTimestamp, lastMessageKey),
+	}
+
+	return PatchInfo{
+		Type: WAPatchRegularLow,
+		Mutations: []MutationInfo{{
+			Index:   []string{IndexMarkChatAsRead, target.String()},
+			Version: 3,
+			Value: &waSyncAction.SyncActionValue{
+				MarkChatAsReadAction: action,
+			},
+		}},
+	}
+}
+
+func newLabelChatMutation(target types.JID, labelID string, labeled bool) MutationInfo {
+	return MutationInfo{
+		Index:   []string{IndexLabelAssociationChat, labelID, target.String()},
+		Version: 3,
+		Value: &waSyncAction.SyncActionValue{
+			LabelAssociationAction: &waSyncAction.LabelAssociationAction{
+				Labeled: &labeled,
+			},
+		},
+	}
+}
+
+// BuildLabelChat builds an app state patch for labeling or un(labeling) a chat.
+func BuildLabelChat(target types.JID, labelID string, labeled bool) PatchInfo {
+	return PatchInfo{
+		Type: WAPatchRegular,
+		Mutations: []MutationInfo{
+			newLabelChatMutation(target, labelID, labeled),
+		},
+	}
+}
+
+func newLabelMessageMutation(target types.JID, labelID, messageID string, labeled bool) MutationInfo {
+	return MutationInfo{
+		Index:   []string{IndexLabelAssociationMessage, labelID, target.String(), messageID, "0", "0"},
+		Version: 3,
+		Value: &waSyncAction.SyncActionValue{
+			LabelAssociationAction: &waSyncAction.LabelAssociationAction{
+				Labeled: &labeled,
+			},
+		},
+	}
+}
+
+// BuildLabelMessage builds an app state patch for labeling or un(labeling) a message.
+func BuildLabelMessage(target types.JID, labelID, messageID string, labeled bool) PatchInfo {
+	return PatchInfo{
+		Type: WAPatchRegular,
+		Mutations: []MutationInfo{
+			newLabelMessageMutation(target, labelID, messageID, labeled),
+		},
+	}
+}
+
+func newLabelEditMutation(labelID string, labelName string, labelColor int32, deleted bool) MutationInfo {
+	return MutationInfo{
+		Index:   []string{IndexLabelEdit, labelID},
+		Version: 3,
+		Value: &waSyncAction.SyncActionValue{
+			LabelEditAction: &waSyncAction.LabelEditAction{
+				Name:    &labelName,
+				Color:   &labelColor,
+				Deleted: &deleted,
+			},
+		},
+	}
+}
+
+// BuildLabelEdit builds an app state patch for editing a label.
+func BuildLabelEdit(labelID string, labelName string, labelColor int32, deleted bool) PatchInfo {
+	return PatchInfo{
+		Type: WAPatchRegular,
+		Mutations: []MutationInfo{
+			newLabelEditMutation(labelID, labelName, labelColor, deleted),
+		},
+	}
+}
+
+func newSettingPushNameMutation(pushName string) MutationInfo {
+	return MutationInfo{
+		Index:   []string{IndexSettingPushName},
+		Version: 1,
+		Value: &waSyncAction.SyncActionValue{
+			PushNameSetting: &waSyncAction.PushNameSetting{
+				Name: &pushName,
+			},
+		},
+	}
+}
+
+// BuildSettingPushName builds an app state patch for setting the push name.
+func BuildSettingPushName(pushName string) PatchInfo {
+	return PatchInfo{
+		Type: WAPatchCriticalBlock,
+		Mutations: []MutationInfo{
+			newSettingPushNameMutation(pushName),
+		},
+	}
+}
+
+func newStarMutation(targetJID, senderJID string, messageID types.MessageID, fromMe string, starred bool) MutationInfo {
+	return MutationInfo{
+		Index:   []string{IndexStar, targetJID, messageID, fromMe, senderJID},
+		Version: 2,
+		Value: &waSyncAction.SyncActionValue{
+			StarAction: &waSyncAction.StarAction{
+				Starred: &starred,
+			},
+		},
+	}
+}
+
+// BuildStar builds an app state patch for starring or unstarring a message.
+func BuildStar(target, sender types.JID, messageID types.MessageID, fromMe, starred bool) PatchInfo {
+	isFromMe := "0"
+	if fromMe {
+		isFromMe = "1"
+	}
+	targetJID, senderJID := target.String(), sender.String()
+	if target.User == sender.User {
+		senderJID = "0"
+	}
+	return PatchInfo{
+		Type: WAPatchRegularHigh,
+		Mutations: []MutationInfo{
+			newStarMutation(targetJID, senderJID, messageID, isFromMe, starred),
+		},
+	}
+}
+
+func (proc *Processor) EncodePatch(ctx context.Context, keyID []byte, state HashState, patchInfo PatchInfo) ([]byte, error) {
+	keys, err := proc.getAppStateKey(ctx, keyID)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get app state key details with key ID %x: %w", keyID, err)
+	}
+
+	if patchInfo.Timestamp.IsZero() {
+		patchInfo.Timestamp = time.Now()
+	}
+
+	mutations := make([]*waServerSync.SyncdMutation, 0, len(patchInfo.Mutations))
+	for _, mutationInfo := range patchInfo.Mutations {
+		mutationInfo.Value.Timestamp = proto.Int64(patchInfo.Timestamp.UnixMilli())
+
+		indexBytes, err := json.Marshal(mutationInfo.Index)
+		if err != nil {
+			return nil, fmt.Errorf("failed to marshal mutation index: %w", err)
+		}
+
+		pbObj := &waSyncAction.SyncActionData{
+			Index:   indexBytes,
+			Value:   mutationInfo.Value,
+			Padding: []byte{},
+			Version: &mutationInfo.Version,
+		}
+
+		content, err := proto.Marshal(pbObj)
+		if err != nil {
+			return nil, fmt.Errorf("failed to marshal mutation: %w", err)
+		}
+
+		encryptedContent, err := cbcutil.Encrypt(keys.ValueEncryption, nil, content)
+		if err != nil {
+			return nil, fmt.Errorf("failed to encrypt mutation: %w", err)
+		}
+
+		valueMac := generateContentMAC(waServerSync.SyncdMutation_SET, encryptedContent, keyID, keys.ValueMAC)
+		indexMac := concatAndHMAC(sha256.New, keys.Index, indexBytes)
+
+		mutations = append(mutations, &waServerSync.SyncdMutation{
+			Operation: waServerSync.SyncdMutation_SET.Enum(),
+			Record: &waServerSync.SyncdRecord{
+				Index: &waServerSync.SyncdIndex{Blob: indexMac},
+				Value: &waServerSync.SyncdValue{Blob: append(encryptedContent, valueMac...)},
+				KeyID: &waServerSync.KeyId{ID: keyID},
+			},
+		})
+	}
+
+	warn, err := state.updateHash(mutations, func(indexMAC []byte, _ int) ([]byte, error) {
+		return proc.Store.AppState.GetAppStateMutationMAC(ctx, string(patchInfo.Type), indexMAC)
+	})
+	if len(warn) > 0 {
+		proc.Log.Warnf("Warnings while updating hash for %s (sending new app state): %+v", patchInfo.Type, warn)
+	}
+	if err != nil {
+		return nil, fmt.Errorf("failed to update state hash: %w", err)
+	}
+
+	state.Version += 1
+
+	syncdPatch := &waServerSync.SyncdPatch{
+		SnapshotMAC: state.generateSnapshotMAC(patchInfo.Type, keys.SnapshotMAC),
+		KeyID:       &waServerSync.KeyId{ID: keyID},
+		Mutations:   mutations,
+	}
+	syncdPatch.PatchMAC = generatePatchMAC(syncdPatch, patchInfo.Type, keys.PatchMAC, state.Version)
+
+	result, err := proto.Marshal(syncdPatch)
+	if err != nil {
+		return nil, fmt.Errorf("failed to marshal compiled patch: %w", err)
+	}
+
+	return result, nil
+}
+
+// BuildDeleteChat builds an app state patch for deleting a chat.
+func BuildDeleteChat(target types.JID, lastMessageTimestamp time.Time, lastMessageKey *waCommon.MessageKey) PatchInfo {
+	action := &waSyncAction.DeleteChatAction{
+		MessageRange: newMessageRange(lastMessageTimestamp, lastMessageKey),
+	}
+
+	return PatchInfo{
+		Type: WAPatchRegular,
+		Mutations: []MutationInfo{{
+			Index:   []string{IndexDeleteChat, target.String()},
+			Version: 6,
+			Value: &waSyncAction.SyncActionValue{
+				DeleteChatAction: action,
+			},
+		}},
+	}
+}
+
+func newMessageRange(lastMessageTimestamp time.Time, lastMessageKey *waCommon.MessageKey) *waSyncAction.SyncActionMessageRange {
+	if lastMessageTimestamp.IsZero() {
+		lastMessageTimestamp = time.Now()
+	}
+	messageRange := &waSyncAction.SyncActionMessageRange{
+		LastMessageTimestamp: proto.Int64(lastMessageTimestamp.Unix()),
+	}
+	if lastMessageKey != nil {
+		messageRange.Messages = []*waSyncAction.SyncActionMessage{{
+			Key:       lastMessageKey,
+			Timestamp: proto.Int64(lastMessageTimestamp.Unix()),
+		}}
+	}
+	return messageRange
+}

+ 19 - 0
appstate/errors.go

@@ -0,0 +1,19 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package appstate
+
+import "errors"
+
+// Errors that this package can return.
+var (
+	ErrMissingPreviousSetValueOperation = errors.New("missing value MAC of previous SET operation")
+	ErrMismatchingLTHash                = errors.New("mismatching LTHash")
+	ErrMismatchingPatchMAC              = errors.New("mismatching patch MAC")
+	ErrMismatchingContentMAC            = errors.New("mismatching content MAC")
+	ErrMismatchingIndexMAC              = errors.New("mismatching index MAC")
+	ErrKeyNotFound                      = errors.New("didn't find app state key")
+)

+ 98 - 0
appstate/hash.go

@@ -0,0 +1,98 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package appstate
+
+import (
+	"crypto/hmac"
+	"crypto/sha256"
+	"crypto/sha512"
+	"encoding/binary"
+	"fmt"
+	"hash"
+
+	"go.mau.fi/whatsmeow/appstate/lthash"
+	"go.mau.fi/whatsmeow/proto/waServerSync"
+	"go.mau.fi/whatsmeow/proto/waSyncAction"
+)
+
+type Mutation struct {
+	Operation waServerSync.SyncdMutation_SyncdOperation
+	Action    *waSyncAction.SyncActionValue
+	Version   int32
+	Index     []string
+	IndexMAC  []byte
+	ValueMAC  []byte
+}
+
+type HashState struct {
+	Version uint64
+	Hash    [128]byte
+}
+
+func (hs *HashState) updateHash(mutations []*waServerSync.SyncdMutation, getPrevSetValueMAC func(indexMAC []byte, maxIndex int) ([]byte, error)) ([]error, error) {
+	var added, removed [][]byte
+	var warnings []error
+
+	for i, mutation := range mutations {
+		if mutation.GetOperation() == waServerSync.SyncdMutation_SET {
+			value := mutation.GetRecord().GetValue().GetBlob()
+			added = append(added, value[len(value)-32:])
+		}
+		indexMAC := mutation.GetRecord().GetIndex().GetBlob()
+		removal, err := getPrevSetValueMAC(indexMAC, i)
+		if err != nil {
+			return warnings, fmt.Errorf("failed to get value MAC of previous SET operation: %w", err)
+		} else if removal != nil {
+			removed = append(removed, removal)
+		} else if mutation.GetOperation() == waServerSync.SyncdMutation_REMOVE {
+			// TODO figure out if there are certain cases that are safe to ignore and others that aren't
+			// At least removing contact access from WhatsApp seems to create a REMOVE op for your own JID
+			// that points to a non-existent index and is safe to ignore here. Other keys might not be safe to ignore.
+			warnings = append(warnings, fmt.Errorf("%w for %X", ErrMissingPreviousSetValueOperation, indexMAC))
+			//return ErrMissingPreviousSetValueOperation
+		}
+	}
+
+	lthash.WAPatchIntegrity.SubtractThenAddInPlace(hs.Hash[:], removed, added)
+	return warnings, nil
+}
+
+func uint64ToBytes(val uint64) []byte {
+	data := make([]byte, 8)
+	binary.BigEndian.PutUint64(data, val)
+	return data
+}
+
+func concatAndHMAC(alg func() hash.Hash, key []byte, data ...[]byte) []byte {
+	h := hmac.New(alg, key)
+	for _, item := range data {
+		h.Write(item)
+	}
+	return h.Sum(nil)
+}
+
+func (hs *HashState) generateSnapshotMAC(name WAPatchName, key []byte) []byte {
+	return concatAndHMAC(sha256.New, key, hs.Hash[:], uint64ToBytes(hs.Version), []byte(name))
+}
+
+func generatePatchMAC(patch *waServerSync.SyncdPatch, name WAPatchName, key []byte, version uint64) []byte {
+	dataToHash := make([][]byte, len(patch.GetMutations())+3)
+	dataToHash[0] = patch.GetSnapshotMAC()
+	for i, mutation := range patch.Mutations {
+		val := mutation.GetRecord().GetValue().GetBlob()
+		dataToHash[i+1] = val[len(val)-32:]
+	}
+	dataToHash[len(dataToHash)-2] = uint64ToBytes(version)
+	dataToHash[len(dataToHash)-1] = []byte(name)
+	return concatAndHMAC(sha256.New, key, dataToHash...)
+}
+
+func generateContentMAC(operation waServerSync.SyncdMutation_SyncdOperation, data, keyID, key []byte) []byte {
+	operationBytes := []byte{byte(operation) + 1}
+	keyDataLength := uint64ToBytes(uint64(len(keyID) + 1))
+	return concatAndHMAC(sha512.New, key, operationBytes, keyID, data, keyDataLength)[:32]
+}

+ 138 - 0
appstate/keys.go

@@ -0,0 +1,138 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Package appstate implements encoding and decoding WhatsApp's app state patches.
+package appstate
+
+import (
+	"context"
+	"encoding/base64"
+	"sync"
+
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/util/hkdfutil"
+	waLog "go.mau.fi/whatsmeow/util/log"
+)
+
+// WAPatchName represents a type of app state patch.
+type WAPatchName string
+
+const (
+	// WAPatchCriticalBlock contains the user's settings like push name and locale.
+	WAPatchCriticalBlock WAPatchName = "critical_block"
+	// WAPatchCriticalUnblockLow contains the user's contact list.
+	WAPatchCriticalUnblockLow WAPatchName = "critical_unblock_low"
+	// WAPatchRegularLow contains some local chat settings like pin, archive status, and the setting of whether to unarchive chats when messages come in.
+	WAPatchRegularLow WAPatchName = "regular_low"
+	// WAPatchRegularHigh contains more local chat settings like mute status and starred messages.
+	WAPatchRegularHigh WAPatchName = "regular_high"
+	// WAPatchRegular contains protocol info about app state patches like key expiration.
+	WAPatchRegular WAPatchName = "regular"
+)
+
+// AllPatchNames contains all currently known patch state names.
+var AllPatchNames = [...]WAPatchName{WAPatchCriticalBlock, WAPatchCriticalUnblockLow, WAPatchRegularHigh, WAPatchRegular, WAPatchRegularLow}
+
+// Constants for the first part of app state indexes.
+const (
+	IndexMute                    = "mute"
+	IndexPin                     = "pin_v1"
+	IndexArchive                 = "archive"
+	IndexContact                 = "contact"
+	IndexClearChat               = "clearChat"
+	IndexDeleteChat              = "deleteChat"
+	IndexStar                    = "star"
+	IndexDeleteMessageForMe      = "deleteMessageForMe"
+	IndexMarkChatAsRead          = "markChatAsRead"
+	IndexSettingPushName         = "setting_pushName"
+	IndexSettingUnarchiveChats   = "setting_unarchiveChats"
+	IndexUserStatusMute          = "userStatusMute"
+	IndexLabelEdit               = "label_edit"
+	IndexLabelAssociationChat    = "label_jid"
+	IndexLabelAssociationMessage = "label_message"
+)
+
+type Processor struct {
+	keyCache     map[string]ExpandedAppStateKeys
+	keyCacheLock sync.Mutex
+	Store        *store.Device
+	Log          waLog.Logger
+}
+
+func NewProcessor(store *store.Device, log waLog.Logger) *Processor {
+	return &Processor{
+		keyCache: make(map[string]ExpandedAppStateKeys),
+		Store:    store,
+		Log:      log,
+	}
+}
+
+type ExpandedAppStateKeys struct {
+	Index           []byte
+	ValueEncryption []byte
+	ValueMAC        []byte
+	SnapshotMAC     []byte
+	PatchMAC        []byte
+}
+
+func expandAppStateKeys(keyData []byte) (keys ExpandedAppStateKeys) {
+	appStateKeyExpanded := hkdfutil.SHA256(keyData, nil, []byte("WhatsApp Mutation Keys"), 160)
+	return ExpandedAppStateKeys{appStateKeyExpanded[0:32], appStateKeyExpanded[32:64], appStateKeyExpanded[64:96], appStateKeyExpanded[96:128], appStateKeyExpanded[128:160]}
+}
+
+func (proc *Processor) getAppStateKey(ctx context.Context, keyID []byte) (keys ExpandedAppStateKeys, err error) {
+	keyCacheID := base64.RawStdEncoding.EncodeToString(keyID)
+	var ok bool
+
+	proc.keyCacheLock.Lock()
+	defer proc.keyCacheLock.Unlock()
+
+	keys, ok = proc.keyCache[keyCacheID]
+	if !ok {
+		var keyData *store.AppStateSyncKey
+		keyData, err = proc.Store.AppStateKeys.GetAppStateSyncKey(ctx, keyID)
+		if keyData != nil {
+			keys = expandAppStateKeys(keyData.Data)
+			proc.keyCache[keyCacheID] = keys
+		} else if err == nil {
+			err = ErrKeyNotFound
+		}
+	}
+	return
+}
+
+func (proc *Processor) GetMissingKeyIDs(ctx context.Context, pl *PatchList) [][]byte {
+	cache := make(map[string]bool)
+	var missingKeys [][]byte
+	checkMissing := func(keyID []byte) {
+		if keyID == nil {
+			return
+		}
+		stringKeyID := base64.RawStdEncoding.EncodeToString(keyID)
+		_, alreadyAdded := cache[stringKeyID]
+		if !alreadyAdded {
+			keyData, err := proc.Store.AppStateKeys.GetAppStateSyncKey(ctx, keyID)
+			if err != nil {
+				proc.Log.Warnf("Error fetching key %X while checking if it's missing: %v", keyID, err)
+			}
+			missing := keyData == nil && err == nil
+			cache[stringKeyID] = missing
+			if missing {
+				missingKeys = append(missingKeys, keyID)
+			}
+		}
+	}
+	if pl.Snapshot != nil {
+		checkMissing(pl.Snapshot.GetKeyID().GetID())
+		for _, record := range pl.Snapshot.GetRecords() {
+			checkMissing(record.GetKeyID().GetID())
+		}
+	}
+	for _, patch := range pl.Patches {
+		checkMissing(patch.GetKeyID().GetID())
+	}
+	return missingKeys
+}

+ 58 - 0
appstate/lthash/lthash.go

@@ -0,0 +1,58 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Package lthash implements a summation based hash algorithm that maintains the
+// integrity of a piece of data over a series of mutations. You can add/remove
+// mutations, and it'll return a hash equal to if the same series of mutations
+// was made sequentially.
+package lthash
+
+import (
+	"encoding/binary"
+
+	"go.mau.fi/whatsmeow/util/hkdfutil"
+)
+
+type LTHash struct {
+	HKDFInfo []byte
+	HKDFSize uint8
+}
+
+// WAPatchIntegrity is a LTHash instance initialized with the details used for verifying integrity of WhatsApp app state sync patches.
+var WAPatchIntegrity = LTHash{[]byte("WhatsApp Patch Integrity"), 128}
+
+func (lth LTHash) SubtractThenAdd(base []byte, subtract, add [][]byte) []byte {
+	output := make([]byte, len(base))
+	copy(output, base)
+	lth.SubtractThenAddInPlace(output, subtract, add)
+	return output
+}
+
+func (lth LTHash) SubtractThenAddInPlace(base []byte, subtract, add [][]byte) {
+	lth.multipleOp(base, subtract, true)
+	lth.multipleOp(base, add, false)
+}
+
+func (lth LTHash) multipleOp(base []byte, input [][]byte, subtract bool) {
+	for _, item := range input {
+		performPointwiseWithOverflow(base, hkdfutil.SHA256(item, nil, lth.HKDFInfo, lth.HKDFSize), subtract)
+	}
+}
+
+func performPointwiseWithOverflow(base, input []byte, subtract bool) []byte {
+	for i := 0; i < len(base); i += 2 {
+		x := binary.LittleEndian.Uint16(base[i : i+2])
+		y := binary.LittleEndian.Uint16(input[i : i+2])
+		var result uint16
+		if subtract {
+			result = x - y
+		} else {
+			result = x + y
+		}
+		binary.LittleEndian.PutUint16(base[i:i+2], result)
+	}
+	return base
+}

File diff suppressed because it is too large
+ 0 - 0
argo/argo-wire-type-store.argo


+ 62 - 0
argo/argo.go

@@ -0,0 +1,62 @@
+package argo
+
+import (
+	_ "embed"
+	"encoding/json"
+	"sync"
+
+	"github.com/beeper/argo-go/wire"
+	"github.com/beeper/argo-go/wirecodec"
+)
+
+var (
+	Store                map[string]wire.Type
+	QueryIDToMessageName map[string]string
+
+	//go:embed argo-wire-type-store.argo
+	wireTypeStoreBytes []byte
+
+	//go:embed name-to-queryids.json
+	jsonMapBytes []byte
+
+	loadOnce sync.Once
+	initErr  error
+)
+
+func Init() error {
+	loadOnce.Do(func() {
+		var err error
+
+		Store, err = wirecodec.DecodeWireTypeStoreFile(wireTypeStoreBytes)
+		if err != nil {
+			initErr = err
+			return
+		}
+
+		var src map[string]string
+		if err := json.Unmarshal(jsonMapBytes, &src); err != nil {
+			initErr = err
+			return
+		}
+
+		m := make(map[string]string, len(src))
+		for name, id := range src {
+			m[id] = name
+		}
+		QueryIDToMessageName = m
+	})
+	return initErr
+}
+
+func GetStore() (map[string]wire.Type, error) {
+	if err := Init(); err != nil {
+		return nil, err
+	}
+	return Store, nil
+}
+func GetQueryIDToMessageName() (map[string]string, error) {
+	if err := Init(); err != nil {
+		return nil, err
+	}
+	return QueryIDToMessageName, nil
+}

+ 306 - 0
argo/name-to-queryids.json

@@ -0,0 +1,306 @@
+{
+	"AIStudioWAManageMemoryDeleteAllMutation": "29052043257719788",
+	"AIStudioWAManageMemoryDeleteMutation": "7544143899043492",
+	"AIStudioWAManageMemoryQuery": "9127813997336237",
+	"AcDcCreateDigitalCommerceNonse": "24409813818642948",
+	"AcceptAffiliationRequest": "27688116220836225",
+	"AccountSyncUsernameNotification": "7858197960949065",
+	"AccountTransferNotification": "8220475834742024",
+	"AddMultiAccountLink": "24893947900219705",
+	"AddParticipantsToGroup": "26828081150171064",
+	"AddParticipantsToGroupV2": "28712042245061067",
+	"AddParticipantsToInteropGroup": "24096891046636046",
+	"AddSmbAgentAndCoexQr": "30086066011007103",
+	"AgeCollection": "26879887431657309",
+	"AiCharacterUpdateHideStatus": "8839874476113994",
+	"AiCreationCheckCreatedByMe": "9815362228482855",
+	"AiCreationDeletePersona": "8696516227091665",
+	"AiCreationFetchAiPersonaForEditing": "9904567389669075",
+	"AiCreationFetchCreatedBot": "9978792015508840",
+	"AiCreationFetchVoiceSample": "23916680671255181",
+	"AiCreationGenerateImageCandidate": "24079598261680837",
+	"AiCreationUpdatePersona": "10035356286584105",
+	"AiCreationUploadImageMutation": "24138890235741746",
+	"AiHomeFetchUserCreatedPersonasQuery": "24004744805826063",
+	"AiHomeLayoutQuery": "8534063353384687",
+	"AiHomeSearchQuery": "30238411035774898",
+	"AiHomeSectionQuery": "23974658895484544",
+	"AiImmersiveBotQuery": "23880659328262645",
+	"AiImmersiveQuery": "23897130903241751",
+	"AiPersonalizationRecordNotice": "9095896127204206",
+	"AiPlannerStopGenerationMutation": "24452566171046804",
+	"AiSearchEmptyStateConversationStartersQuery": "24859646513652301",
+	"AllowNonAdminGroupCreation": "7519835874701878",
+	"BizIntegrityQuery": "9952408304882625",
+	"BotProactiveMessageControlStatus": "24107778775576749",
+	"BotProactiveMessageControlStatusUpdate": "9867720136669699",
+	"BotProfilePictureUrlQuery": "24968786916054502",
+	"BotProfileSyncQuery": "8739375796187001",
+	"BrandIdsGetPhoneNumbers": "30488425480748795",
+	"CanonicalEntQueryFeature": "24576316608621283",
+	"CanonicalEntSetupFeature": "24337933855819598",
+	"CanonicalEntTeardownFeature": "24041030982231710",
+	"CheckAutoConfConsent": "9625438944164624",
+	"CoexMultiAppEligiblity": "8336924149750786",
+	"CoexProcessNativeOnboardingRequest": "9878176882212860",
+	"CoexistenceProcessAuthChallenge": "9684040624947821",
+	"CompleteTopicOnboarding": "7742297632561058",
+	"ContactIntegrityQuery": "8370845569632382",
+	"ContactsBackupMutation": "7898229300257102",
+	"ContactsBackupQuery": "7307717639327756",
+	"CreateEnforcementAppeal": "8821533821282490",
+	"CreateGroup": "9639739449412631",
+	"CreateInviteCode": "24113619438328626",
+	"CtwaAdsContextBizQuery": "9455487237842382",
+	"CtwaNativeUploadAdMediaMutation": "9181032062008816",
+	"DeleteAIKnowledge": "9734241303310288",
+	"DeleteGenAiTasks": "9267681663329336",
+	"DeleteImagineMeOnboarding": "8726914694003146",
+	"DigitalContentIAPPurchaseQuoteMutation": "8922485457790070",
+	"EditAGenAiTask": "9419617158093386",
+	"ExternalCtxAuthoriseWAChat": "26901859259428948",
+	"FetchAIAbilities": "9640511419331019",
+	"FetchAiReplySettings": "10086110871440121",
+	"FetchFBSSOLoginTokensMutation": "26599490752999797",
+	"FetchOrderedKnowledge": "9537936276334771",
+	"FetchReachoutTimelockQuery": "9462376090546244",
+	"FetchUserNoticesByID": "8870435989745078",
+	"GenApprovePotentialKnowledge": "24098685746388521",
+	"GenDeletePotentialKnowledge": "9332003590258784",
+	"GenEditPotentialKnowledge": "9741569319237798",
+	"GenLoadPotentialKnowledgeForReview": "9703484983043955",
+	"GenTiggerMultiFileKnowledgeExtraction": "24175511598781021",
+	"GenWhatsAppSMBDebugContentGenProfileResponse": "23985621637769232",
+	"GenerateWhatsAppP2BReport": "8051218588298508",
+	"GetAutoConfConfidenceChallenge": "9449283601809884",
+	"GetBillerPlans": "24230130823283004",
+	"GetBusinessProfileWebsiteShimUrlQuery": "8842045022505438",
+	"GetCustomUrlsQuery": "24160261910236968",
+	"GetDcpProductsQuery": "27554084174237806",
+	"GetDynamicRegistrationUpsells": "10043673822314027",
+	"GetImagineMeOnboarded": "7464954973630740",
+	"GetInviteInfo": "9274981439273619",
+	"GetRecommendedTier": "8845639942219954",
+	"GetRegistrationUpsells": "7561558900567547",
+	"GetSMBAgentOnboardingInfo": "8654799644605375",
+	"GetSubscribedTasksForThread": "28928340753448628",
+	"GetSubscriptions": "8876107472483541",
+	"GetSuggestedContacts": "24497904963133841",
+	"GetTextStatus": "6681894428597832",
+	"GetTextStatusList": "7313153618713617",
+	"GetUpiAccounts": "29334452936170022",
+	"GetWaMeLinkQuery": "8590101537750204",
+	"GroupUpdateParticipantLabelEnabledMutation": "9336450899772182",
+	"GroupsCreateInteropGroup": "23994919786772328",
+	"HasBusinessIntent": "7865157416866111",
+	"ImmersiveCreationCompleteCreationMutation": "9913715632037438",
+	"ImmersiveCreationConfigurationQuery": "9361733867204147",
+	"ImmersiveCreationInitiateCreationMutation": "31232734296341497",
+	"ImmersiveCreationUpdateIntroFieldMutation": "24195839360054094",
+	"ImmersiveCreationUpdateNameFieldMutation": "9650650568373143",
+	"ImmersiveCreationUpdatePersonalityFieldMutation": "30190466170599132",
+	"ImmersiveCreationUpdateVoiceFieldMutation": "24787533637583171",
+	"IplsClientHandshakeInitRequest": "7841955639221430",
+	"IplsClientHelloPayload": "7574986815915518",
+	"LidChangeNotification": "8920679384728188",
+	"LinkCatalogToWhatsAppSMB": "8872455936130646",
+	"LinkedProfilesRemove": "8909688149086913",
+	"LinkedProfilesUpdate": "9784377594930152",
+	"LoadAvatarPoses": "9074762182534903",
+	"MaibaDeleteFileKnowledgeSource": "9993739917330936",
+	"MaibaGetCurrentCatalog": "9795957660487019",
+	"MaibaQueryUploadedFiles": "23913245624959696",
+	"MaibaStartFileKnowledgeExtraction": "9845305758879437",
+	"MetaAIBizAgentWACoachingMutation": "9259901980755931",
+	"MetaAIMemoryDelete": "8481408331896133",
+	"MetaAIMemoryDeleteAll": "8935315639836425",
+	"MetaAIMemoryQuery": "8869074713151146",
+	"MetaAIVoiceWAOptionsFetchQuery": "27538353179144114",
+	"MetaAIVoiceWAOptionsWithDefaultFetchQuery": "6784800994977131",
+	"MetaPoiTypeAhead": "10011518742299182",
+	"MigrateBlocklistLid": "29610788451869855",
+	"MultiAccountRevokeAccount": "8754214324686446",
+	"NewsletterAcceptAdminInvite": "6179636105471882",
+	"NewsletterAdminDemote": "7220922401252829",
+	"NewsletterAdminInvite": "24943748628557365",
+	"NewsletterAdminInviteRevoke": "6550386328343169",
+	"NewsletterAdminMetadataQuery": "7785791618136078",
+	"NewsletterBlockUser": "30495729640073636",
+	"NewsletterChangeOwner": "6951013521615265",
+	"NewsletterChangeWamoSub": "27448193018097359",
+	"NewsletterCreate": "27527996220149684",
+	"NewsletterCreateReportAppeal": "23913563504921106",
+	"NewsletterCreateVerified": "27385241581120782",
+	"NewsletterDelete": "6285734628148226",
+	"NewsletterDirectoryCategoryPreview": "28199252546357255",
+	"NewsletterDirectoryList": "8629852843766813",
+	"NewsletterDirectorySearch": "8422355807877290",
+	"NewsletterDisableWamoSub": "7644433872334704",
+	"NewsletterEnableWamoSub": "7833900003373753",
+	"NewsletterEnforcements": "9883696571653834",
+	"NewsletterHide": "9847547868624220",
+	"NewsletterInsights": "7685666401499724",
+	"NewsletterJoin": "6742622672428529",
+	"NewsletterKotlinExample": "9702143139802327",
+	"NewsletterLeave": "6548204731885183",
+	"NewsletterLinkPreviewCheck": "6842506979173950",
+	"NewsletterLogExposure": "7395568390543223",
+	"NewsletterMetadata": "9779843322044422",
+	"NewsletterMetadataNotification": "6326535000799900",
+	"NewsletterMetadataUpdate": "8580212968761751",
+	"NewsletterMute": "5971669009605755",
+	"NewsletterPollVoterList": "24677763351869464",
+	"NewsletterQueryMessageDeliveryUpdates": "6920948374651895",
+	"NewsletterQuestionResponseStateUpdate": "24589034820694583",
+	"NewsletterReactionSendersList": "6868098736578560",
+	"NewsletterRecommended": "27256776790637714",
+	"NewsletterResponseStateUpdate": "24222471884053526",
+	"NewsletterSearch": "9006011396096776",
+	"NewsletterSimilar": "8845781528777207",
+	"NewsletterSubscribed": "8621797084555037",
+	"NewsletterSubscribers": "25403502652570342",
+	"NewsletterUnhide": "9323568947747934",
+	"NewsletterUnmute": "6104029483058502",
+	"NewsletterUpdateVerification": "8877210142312361",
+	"NewsletterUserReports": "24063801373308138",
+	"NotificationAgeCollection": "8470338583083616",
+	"NotificationCommunityOwnerUpdate": "23926761323617949",
+	"NotificationGroupCreateUpdate": "7172226612882255",
+	"NotificationGroupHiddenPropertyUpdate": "24486508950944602",
+	"NotificationGroupLimitSharingPropertyUpdate": "23921409724194417",
+	"NotificationGroupMemberLinkPropertyUpdate": "30514374534874976",
+	"NotificationGroupParticipantLabelParticipantPropertyUpdate": "28721666060781185",
+	"NotificationGroupParticipantLabelPropertyUpdate": "9605044949588542",
+	"NotificationGroupPropertyUpdate": "24428504903421728",
+	"NotificationGroupSafetyCheckPropertyUpdate": "9713942958657827",
+	"NotificationInteropGroupCreateUpdate": "29624102497234486",
+	"NotificationInteropGroupParticipantsUpdate": "23987398490899606",
+	"NotificationInteropMsgrGroupAddParticipantsUpdate": "9929050243890055",
+	"NotificationInteropMsgrGroupCreateUpdate": "9875620322487003",
+	"NotificationInteropMsgrGroupPropertyUpdate": "31018490114463946",
+	"NotificationLinkedProfilesUpdates": "29516109634642858",
+	"NotificationLinkedProfilesUpdatesSideSub": "9277991622261208",
+	"NotificationNewsletterAdminDemote": "6634787226625860",
+	"NotificationNewsletterAdminInviteRevoke": "7497017380360026",
+	"NotificationNewsletterAdminMetadataUpdate": "9828601590514736",
+	"NotificationNewsletterAdminPromote": "7054784991295295",
+	"NotificationNewsletterBlockUser": "9822503934524230",
+	"NotificationNewsletterJoin": "29241810008797405",
+	"NotificationNewsletterLeave": "7294702320556387",
+	"NotificationNewsletterMuteChange": "6653725748024899",
+	"NotificationNewsletterOwnerUpdate": "7088224791298632",
+	"NotificationNewsletterStateChange": "7078192942214381",
+	"NotificationNewsletterUpdate": "7839742399440946",
+	"NotificationNewsletterWamoSubStatusChange": "8222443127778481",
+	"NotificationNotifySenderOnGuestDeletionInactive": "9751802081581770",
+	"NotificationNotifySenderOnGuestDeletionRegistered": "10020077494748622",
+	"NotificationNotifySenderOnGuestJoin": "30407276695583063",
+	"NotificationNotifySenderOnGuestTransition": "29876639681927056",
+	"NotificationNotifySenderOnReceiverJoin": "9244657255644098",
+	"NotificationReminder": "29581768531470837",
+	"NotificationUserBrigadingUpdate": "8289465197770293",
+	"NotificationUserReachoutTimelockUpdate": "8639040062862879",
+	"OhaiKeyConfigQuery": "8699487313397273",
+	"PasskeyExistResponseQuery": "24280390751624940",
+	"ProcessMultiOffboarding": "8305078249594217",
+	"ProcessMultiOnboarding": "8665042316912941",
+	"QueryBatchGetGroups": "9649176255164364",
+	"QueryCommunityParticipantCount": "8826001857513910",
+	"QueryGroupInfo": "24853715544235144",
+	"QueryGroupInfoByCode": "9936511276382237",
+	"QueryInteropGroupInfo": "23960878493549033",
+	"QueryInviteLink": "24965552223089656",
+	"QueryLinkedGroupInfo": "9323243201132275",
+	"QueryParticipatingGroups": "23940562365561484",
+	"QuerySubgroupParticipantCount": "6987167604717709",
+	"QuerySubgroups": "7822701281123381",
+	"QuerySuggestedGroups": "8077882158902147",
+	"RegAccountTransferVerifyTokenMutation": "6864936900275764",
+	"RegistrationDynamicUpsellShown": "8778425068925687",
+	"RegistrationPasskeyClear": "9379175628767649",
+	"RegistrationPasskeyEnableMutation": "24513078668282891",
+	"RegistrationPasskeyFinishRegisterMutation": "8863736077067250",
+	"RegistrationPasskeyStartRegisterMutation": "28380481564900991",
+	"RegistrationUpsellShown": "7480997188628461",
+	"ReminderCreate": "23893837570245751",
+	"ReminderDelete": "29800433312937353",
+	"SMBBotSync": "10011962528916982",
+	"SMBMarketingMessageQuotaData": "23997573626526381",
+	"SMBMarketingMessagesGetBizInfo": "8698055193597480",
+	"SMBMarketingMessagesPromoTemplate": "27335929922718021",
+	"SaveAvatarPose": "7922098614562797",
+	"SelectedOrDefaultPoseQuery": "7649832701812240",
+	"SelfContactsQuery": "9982837645142393",
+	"SetGroupProperty": "9207174359373176",
+	"SetGroupResetInviteLink": "9834530503251303",
+	"SetProfilePicture": "25827464620177848",
+	"SetWamoUserIdVersion": "25457378233907275",
+	"SubmitAge": "8849188358438998",
+	"SuggestedContactsV2": "9172270102828385",
+	"TeeSecureChannel": "7807820402660929",
+	"TeeSecureQuery": "26663763556600822",
+	"TeeSnpAttestation": "7613906245386944",
+	"TestQuery": "7241805649253401",
+	"TextStatusUpdateNotification": "6601560246628795",
+	"TextStatusUpdateNotificationSideSub": "6808064125919757",
+	"TosSetResult": "8733233133472407",
+	"UnifiedConversationStartersQuery": "30659058203707682",
+	"UpdateAIKnowledge": "8992224977546616",
+	"UpdateAiReplyBotEnabledTime": "29521031190828773",
+	"UpdateAiReplyChatTrigger": "29048215068157355",
+	"UpdateAutoConfConsent": "9547173492019407",
+	"UpdateCommunityOwner": "7554036211316744",
+	"UpdateGroupParticipantLabelMutation": "9474133135955233",
+	"UpdateTextStatus": "6679986965420430",
+	"UpdateUserStatus": "8702204706516599",
+	"UpiOnboardingSendOtpMutation": "9750189185067185",
+	"UpiOnboardingVerifyOtpQuery": "29721450344166819",
+	"UserCountryCodeGet": "9319768474776384",
+	"UsernameCheck": "23938900255774163",
+	"UsernameDeleteNotification": "9074620385982648",
+	"UsernameGet": "7533911316677636",
+	"UsernamePinSet": "8277542455646085",
+	"UsernameRecommendationsQuery": "29936714359277584",
+	"UsernameSet": "7539839152759345",
+	"UsernameSetNotification": "7777773138910784",
+	"UsernameUpdateNotification": "7690268147674188",
+	"UsyncQuery": "8925664914155696",
+	"ValidateVerifierConfidence": "6167147383402771",
+	"WABinaryDemoQuery": "9216664025057904",
+	"WWWCreateAccessToken": "25355063454141992",
+	"WWWCreateUser": "7418342681612667",
+	"WWWDeleteUser": "7952120364827799",
+	"WWWExchangeNonceForAccessToken": "9410129542399925",
+	"WWWGetCertificates": "7821205087931198",
+	"WWWGetNonceForCompanionDevice": "24279515318321806",
+	"WWWTradeNonceForAccessTokens": "24471556995761226",
+	"WWWTriggerAcountRecovery": "23966926942898128",
+	"WamoAssetCollection": "8821483957952305",
+	"WamoSubCancelSubscription": "8782612271820087",
+	"WamoSubGetComplianceInfo": "9133707526723587",
+	"WamoSubQueryFinancialEntity": "8002750676472779",
+	"WamoSubQueryStatus": "8560674097367905",
+	"WamoUserIdVersion": "7527285483991164",
+	"WhatsAppBizAccountNonceMutation": "9394029384025067",
+	"WhatsAppBusinessLinkedAccountsQuery": "9750926348293158",
+	"WhatsAppBusinessUnlinkAccountMutation": "9055152041257507",
+	"WhatsAppCatalogAddProduct": "8886227818135185",
+	"WhatsAppCatalogCommerceSettings": "8499535920153424",
+	"WhatsAppCatalogCreateCollections": "8425362434250817",
+	"WhatsAppCatalogCreateMutation": "28658341153753102",
+	"WhatsAppCatalogDeleteCollection": "8560882437365569",
+	"WhatsAppCatalogDeleteProduct": "9160045830673468",
+	"WhatsAppCatalogEditProduct": "7866291200141147",
+	"WhatsAppCatalogGetLinkedCatalogEligibility": "9275740725769789",
+	"WhatsAppCatalogProductVisibilityUpdate": "8663534337063686",
+	"WhatsAppCatalogUnlinkMetaCatalog": "7874105519359462",
+	"WhatsAppCatalogUpdateCollection": "8333405736788282",
+	"WhatsAppCatalogUpdateCollectionList": "8011916185576719",
+	"WhatsAppCoexistenceBSPInfoQuery": "9761834693829429",
+	"WhatsAppSMBGenAIImage": "7846304058822381",
+	"WhatsappCatalogAppealProduct": "28258864727045852",
+	"WhatsappCatalogReportProduct": "8798913583502365",
+	"WhatsappOrderCompliance": "6646812275409584",
+	"WhatsappSMBOrderEducation": "6854177671335204",
+	"XWA2MessageCappingInfoQuery": "25275321118723031"
+}

+ 133 - 0
armadillomessage.go

@@ -0,0 +1,133 @@
+// Copyright (c) 2024 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"fmt"
+
+	"google.golang.org/protobuf/proto"
+
+	armadillo "go.mau.fi/whatsmeow/proto"
+	"go.mau.fi/whatsmeow/proto/armadilloutil"
+	"go.mau.fi/whatsmeow/proto/instamadilloTransportPayload"
+	"go.mau.fi/whatsmeow/proto/waCommon"
+	"go.mau.fi/whatsmeow/proto/waMsgApplication"
+	"go.mau.fi/whatsmeow/proto/waMsgTransport"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+func (cli *Client) handleDecryptedArmadillo(ctx context.Context, info *types.MessageInfo, decrypted []byte, retryCount int) (handlerFailed, protobufFailed bool) {
+	dec, err := decodeArmadillo(decrypted)
+	if err != nil {
+		cli.Log.Warnf("Failed to decode armadillo message from %s: %v", info.SourceString(), err)
+		protobufFailed = true
+		return
+	}
+	dec.Info = *info
+	dec.RetryCount = retryCount
+	if dec.Transport.GetProtocol().GetAncillary().GetSkdm() != nil {
+		if !info.IsGroup {
+			cli.Log.Warnf("Got sender key distribution message in non-group chat from %s", info.Sender)
+		} else {
+			skdm := dec.Transport.GetProtocol().GetAncillary().GetSkdm()
+			cli.handleSenderKeyDistributionMessage(ctx, info.Chat, info.Sender, skdm.AxolotlSenderKeyDistributionMessage)
+		}
+	}
+	if dec.Message != nil || dec.FBApplication != nil {
+		handlerFailed = cli.dispatchEvent(&dec)
+	}
+	return
+}
+
+func decodeArmadillo(data []byte) (dec events.FBMessage, err error) {
+	var transport waMsgTransport.MessageTransport
+	err = proto.Unmarshal(data, &transport)
+	if err != nil {
+		return dec, fmt.Errorf("failed to unmarshal transport: %w", err)
+	}
+	dec.Transport = &transport
+	if transport.GetPayload() == nil {
+		return
+	}
+	appPayloadVer := transport.GetPayload().GetApplicationPayload().GetVersion()
+	switch appPayloadVer {
+	case waMsgTransport.FBMessageApplicationVersion:
+		return decodeFBArmadillo(&transport)
+	case waMsgTransport.IGMessageApplicationVersion:
+		return decodeIGArmadillo(&transport)
+	default:
+		return dec, fmt.Errorf("%w %d in MessageTransport", armadilloutil.ErrUnsupportedVersion, appPayloadVer)
+	}
+}
+
+func decodeFBArmadillo(transport *waMsgTransport.MessageTransport) (dec events.FBMessage, err error) {
+	var application *waMsgApplication.MessageApplication
+	application, err = transport.GetPayload().DecodeFB()
+	if err != nil {
+		return dec, fmt.Errorf("failed to unmarshal application: %w", err)
+	}
+	dec.FBApplication = application
+	if application.GetPayload() == nil {
+		return
+	}
+
+	switch typedContent := application.GetPayload().GetContent().(type) {
+	case *waMsgApplication.MessageApplication_Payload_CoreContent:
+		err = fmt.Errorf("unsupported core content payload")
+	case *waMsgApplication.MessageApplication_Payload_Signal:
+		err = fmt.Errorf("unsupported signal payload")
+	case *waMsgApplication.MessageApplication_Payload_ApplicationData:
+		err = fmt.Errorf("unsupported application data payload")
+	case *waMsgApplication.MessageApplication_Payload_SubProtocol:
+		var protoMsg proto.Message
+		var subData *waCommon.SubProtocol
+		switch subProtocol := typedContent.SubProtocol.GetSubProtocol().(type) {
+		case *waMsgApplication.MessageApplication_SubProtocolPayload_ConsumerMessage:
+			dec.Message, err = subProtocol.Decode()
+		case *waMsgApplication.MessageApplication_SubProtocolPayload_BusinessMessage:
+			dec.Message = (*armadillo.Unsupported_BusinessApplication)(subProtocol.BusinessMessage)
+		case *waMsgApplication.MessageApplication_SubProtocolPayload_PaymentMessage:
+			dec.Message = (*armadillo.Unsupported_PaymentApplication)(subProtocol.PaymentMessage)
+		case *waMsgApplication.MessageApplication_SubProtocolPayload_MultiDevice:
+			dec.Message, err = subProtocol.Decode()
+		case *waMsgApplication.MessageApplication_SubProtocolPayload_Voip:
+			dec.Message = (*armadillo.Unsupported_Voip)(subProtocol.Voip)
+		case *waMsgApplication.MessageApplication_SubProtocolPayload_Armadillo:
+			dec.Message, err = subProtocol.Decode()
+		default:
+			return dec, fmt.Errorf("unsupported subprotocol type: %T", subProtocol)
+		}
+		if protoMsg != nil {
+			err = proto.Unmarshal(subData.GetPayload(), protoMsg)
+			if err != nil {
+				return dec, fmt.Errorf("failed to unmarshal application subprotocol payload (%T v%d): %w", protoMsg, subData.GetVersion(), err)
+			}
+		}
+	default:
+		err = fmt.Errorf("unsupported application payload content type: %T", typedContent)
+	}
+	return
+}
+
+func decodeIGArmadillo(transport *waMsgTransport.MessageTransport) (dec events.FBMessage, err error) {
+	innerTransport, err := transport.GetPayload().DecodeIG()
+	if err != nil {
+		return dec, fmt.Errorf("failed to unmarshal IG transport: %w", err)
+	}
+	dec.IGTransport = innerTransport
+	switch typedContent := innerTransport.GetTransportPayload().(type) {
+	case *instamadilloTransportPayload.TransportPayload_Add:
+		dec.Message = typedContent.Add
+	case *instamadilloTransportPayload.TransportPayload_Supplement:
+		dec.Message = typedContent.Supplement
+	case *instamadilloTransportPayload.TransportPayload_Delete:
+		dec.Message = typedContent.Delete
+	}
+	return
+}

+ 218 - 0
binary/attrs.go

@@ -0,0 +1,218 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package binary
+
+import (
+	"fmt"
+	"strconv"
+	"time"
+
+	"go.mau.fi/whatsmeow/types"
+)
+
+// AttrUtility is a helper struct for reading multiple XML attributes and checking for errors afterwards.
+//
+// The functions return values directly and append any decoding errors to the Errors slice. The
+// slice can then be checked after all necessary attributes are read, instead of having to check
+// each attribute for errors separately.
+type AttrUtility struct {
+	Attrs  Attrs
+	Errors []error
+}
+
+// AttrGetter returns the AttrUtility for this Node.
+func (n *Node) AttrGetter() *AttrUtility {
+	return &AttrUtility{Attrs: n.Attrs, Errors: make([]error, 0)}
+}
+
+func (au *AttrUtility) GetJID(key string, require bool) (jidVal types.JID, ok bool) {
+	var val interface{}
+	if val, ok = au.Attrs[key]; !ok {
+		if require {
+			au.Errors = append(au.Errors, fmt.Errorf("didn't find required JID attribute '%s'", key))
+		}
+	} else if jidVal, ok = val.(types.JID); !ok {
+		au.Errors = append(au.Errors, fmt.Errorf("expected attribute '%s' to be JID, but was %T", key, val))
+	}
+	return
+}
+
+// OptionalJID returns the JID under the given key. If there's no valid JID under the given key, this will return nil.
+// However, if the attribute is completely missing, this will not store an error.
+func (au *AttrUtility) OptionalJID(key string) *types.JID {
+	jid, ok := au.GetJID(key, false)
+	if ok {
+		return &jid
+	}
+	return nil
+}
+
+// OptionalJIDOrEmpty returns the JID under the given key. If there's no valid JID under the given key, this will return an empty JID.
+// However, if the attribute is completely missing, this will not store an error.
+func (au *AttrUtility) OptionalJIDOrEmpty(key string) types.JID {
+	jid, ok := au.GetJID(key, false)
+	if ok {
+		return jid
+	}
+	return types.EmptyJID
+}
+
+// JID returns the JID under the given key.
+// If there's no valid JID under the given key, an error will be stored and a blank JID struct will be returned.
+func (au *AttrUtility) JID(key string) types.JID {
+	jid, _ := au.GetJID(key, true)
+	return jid
+}
+
+func (au *AttrUtility) GetString(key string, require bool) (strVal string, ok bool) {
+	var val interface{}
+	if val, ok = au.Attrs[key]; !ok {
+		if require {
+			au.Errors = append(au.Errors, fmt.Errorf("didn't find required attribute '%s'", key))
+		}
+	} else if strVal, ok = val.(string); !ok {
+		au.Errors = append(au.Errors, fmt.Errorf("expected attribute '%s' to be string, but was %T", key, val))
+	}
+	return
+}
+
+func (au *AttrUtility) GetInt64(key string, require bool) (int64, bool) {
+	if strVal, ok := au.GetString(key, require); !ok {
+		return 0, false
+	} else if intVal, err := strconv.ParseInt(strVal, 10, 64); err != nil {
+		au.Errors = append(au.Errors, fmt.Errorf("failed to parse int in attribute '%s': %w", key, err))
+		return 0, false
+	} else {
+		return intVal, true
+	}
+}
+
+func (au *AttrUtility) GetUint64(key string, require bool) (uint64, bool) {
+	if strVal, ok := au.GetString(key, require); !ok {
+		return 0, false
+	} else if intVal, err := strconv.ParseUint(strVal, 10, 64); err != nil {
+		au.Errors = append(au.Errors, fmt.Errorf("failed to parse uint in attribute '%s': %w", key, err))
+		return 0, false
+	} else {
+		return intVal, true
+	}
+}
+
+func (au *AttrUtility) GetBool(key string, require bool) (bool, bool) {
+	if strVal, ok := au.GetString(key, require); !ok {
+		return false, false
+	} else if boolVal, err := strconv.ParseBool(strVal); err != nil {
+		au.Errors = append(au.Errors, fmt.Errorf("failed to parse bool in attribute '%s': %w", key, err))
+		return false, false
+	} else {
+		return boolVal, true
+	}
+}
+
+func (au *AttrUtility) GetUnixTime(key string, require bool) (time.Time, bool) {
+	if intVal, ok := au.GetInt64(key, require); !ok {
+		return time.Time{}, false
+	} else if intVal == 0 {
+		return time.Time{}, true
+	} else {
+		return time.Unix(intVal, 0), true
+	}
+}
+
+func (au *AttrUtility) GetUnixMilli(key string, require bool) (time.Time, bool) {
+	if intVal, ok := au.GetInt64(key, require); !ok {
+		return time.Time{}, false
+	} else if intVal == 0 {
+		return time.Time{}, true
+	} else {
+		return time.UnixMilli(intVal), true
+	}
+}
+
+// OptionalString returns the string under the given key.
+func (au *AttrUtility) OptionalString(key string) string {
+	strVal, _ := au.GetString(key, false)
+	return strVal
+}
+
+// String returns the string under the given key.
+// If there's no valid string under the given key, an error will be stored and an empty string will be returned.
+func (au *AttrUtility) String(key string) string {
+	strVal, _ := au.GetString(key, true)
+	return strVal
+}
+
+func (au *AttrUtility) OptionalInt(key string) int {
+	val, _ := au.GetInt64(key, false)
+	return int(val)
+}
+
+func (au *AttrUtility) Int(key string) int {
+	val, _ := au.GetInt64(key, true)
+	return int(val)
+}
+
+func (au *AttrUtility) Int64(key string) int64 {
+	val, _ := au.GetInt64(key, true)
+	return val
+}
+
+func (au *AttrUtility) Uint64(key string) uint64 {
+	val, _ := au.GetUint64(key, true)
+	return val
+}
+
+func (au *AttrUtility) OptionalBool(key string) bool {
+	val, _ := au.GetBool(key, false)
+	return val
+}
+
+func (au *AttrUtility) Bool(key string) bool {
+	val, _ := au.GetBool(key, true)
+	return val
+}
+
+func (au *AttrUtility) OptionalUnixTime(key string) time.Time {
+	val, _ := au.GetUnixTime(key, false)
+	return val
+}
+
+func (au *AttrUtility) UnixTime(key string) time.Time {
+	val, _ := au.GetUnixTime(key, true)
+	return val
+}
+
+func (au *AttrUtility) OptionalUnixMilli(key string) time.Time {
+	val, _ := au.GetUnixMilli(key, false)
+	return val
+}
+
+func (au *AttrUtility) UnixMilli(key string) time.Time {
+	val, _ := au.GetUnixMilli(key, true)
+	return val
+}
+
+// OK returns true if there are no errors.
+func (au *AttrUtility) OK() bool {
+	return len(au.Errors) == 0
+}
+
+// Error returns the list of errors as a single error interface, or nil if there are no errors.
+func (au *AttrUtility) Error() error {
+	if au.OK() {
+		return nil
+	}
+	return ErrorList(au.Errors)
+}
+
+// ErrorList is a list of errors that implements the error interface itself.
+type ErrorList []error
+
+// Error returns all the errors in the list as a string.
+func (el ErrorList) Error() string {
+	return fmt.Sprintf("%+v", []error(el))
+}

+ 406 - 0
binary/decoder.go

@@ -0,0 +1,406 @@
+package binary
+
+import (
+	"fmt"
+	"io"
+	"strings"
+
+	"go.mau.fi/whatsmeow/binary/token"
+	"go.mau.fi/whatsmeow/types"
+)
+
+type binaryDecoder struct {
+	data  []byte
+	index int
+}
+
+func newDecoder(data []byte) *binaryDecoder {
+	return &binaryDecoder{data, 0}
+}
+
+func (r *binaryDecoder) checkEOS(length int) error {
+	if r.index+length > len(r.data) {
+		return io.EOF
+	}
+
+	return nil
+}
+
+func (r *binaryDecoder) readByte() (byte, error) {
+	if err := r.checkEOS(1); err != nil {
+		return 0, err
+	}
+
+	b := r.data[r.index]
+	r.index++
+
+	return b, nil
+}
+
+func (r *binaryDecoder) readIntN(n int, littleEndian bool) (int, error) {
+	if err := r.checkEOS(n); err != nil {
+		return 0, err
+	}
+
+	var ret int
+
+	for i := 0; i < n; i++ {
+		var curShift int
+		if littleEndian {
+			curShift = i
+		} else {
+			curShift = n - i - 1
+		}
+		ret |= int(r.data[r.index+i]) << uint(curShift*8)
+	}
+
+	r.index += n
+	return ret, nil
+}
+
+func (r *binaryDecoder) readInt8(littleEndian bool) (int, error) {
+	return r.readIntN(1, littleEndian)
+}
+
+func (r *binaryDecoder) readInt16(littleEndian bool) (int, error) {
+	return r.readIntN(2, littleEndian)
+}
+
+func (r *binaryDecoder) readInt20() (int, error) {
+	if err := r.checkEOS(3); err != nil {
+		return 0, err
+	}
+
+	ret := ((int(r.data[r.index]) & 15) << 16) + (int(r.data[r.index+1]) << 8) + int(r.data[r.index+2])
+	r.index += 3
+	return ret, nil
+}
+
+func (r *binaryDecoder) readInt32(littleEndian bool) (int, error) {
+	return r.readIntN(4, littleEndian)
+}
+
+func (r *binaryDecoder) readPacked8(tag int) (string, error) {
+	startByte, err := r.readByte()
+	if err != nil {
+		return "", err
+	}
+
+	var build strings.Builder
+
+	for i := 0; i < int(startByte&127); i++ {
+		currByte, err := r.readByte()
+		if err != nil {
+			return "", err
+		}
+
+		lower, err := unpackByte(tag, currByte&0xF0>>4)
+		if err != nil {
+			return "", err
+		}
+
+		upper, err := unpackByte(tag, currByte&0x0F)
+		if err != nil {
+			return "", err
+		}
+
+		build.WriteByte(lower)
+		build.WriteByte(upper)
+	}
+
+	ret := build.String()
+	if startByte>>7 != 0 {
+		ret = ret[:len(ret)-1]
+	}
+	return ret, nil
+}
+
+func unpackByte(tag int, value byte) (byte, error) {
+	switch tag {
+	case token.Nibble8:
+		return unpackNibble(value)
+	case token.Hex8:
+		return unpackHex(value)
+	default:
+		return 0, fmt.Errorf("unpackByte with unknown tag %d", tag)
+	}
+}
+
+func unpackNibble(value byte) (byte, error) {
+	switch {
+	case value < 10:
+		return '0' + value, nil
+	case value == 10:
+		return '-', nil
+	case value == 11:
+		return '.', nil
+	case value == 15:
+		return 0, nil
+	default:
+		return 0, fmt.Errorf("unpackNibble with value %d", value)
+	}
+}
+
+func unpackHex(value byte) (byte, error) {
+	switch {
+	case value < 10:
+		return '0' + value, nil
+	case value < 16:
+		return 'A' + value - 10, nil
+	default:
+		return 0, fmt.Errorf("unpackHex with value %d", value)
+	}
+}
+
+func (r *binaryDecoder) readListSize(tag int) (int, error) {
+	switch tag {
+	case token.ListEmpty:
+		return 0, nil
+	case token.List8:
+		return r.readInt8(false)
+	case token.List16:
+		return r.readInt16(false)
+	default:
+		return 0, fmt.Errorf("readListSize with unknown tag %d at position %d", tag, r.index)
+	}
+}
+
+func (r *binaryDecoder) read(string bool) (interface{}, error) {
+	tagByte, err := r.readByte()
+	if err != nil {
+		return nil, err
+	}
+	tag := int(tagByte)
+	switch tag {
+	case token.ListEmpty:
+		return nil, nil
+	case token.List8, token.List16:
+		return r.readList(tag)
+	case token.Binary8:
+		size, err := r.readInt8(false)
+		if err != nil {
+			return nil, err
+		}
+
+		return r.readBytesOrString(size, string)
+	case token.Binary20:
+		size, err := r.readInt20()
+		if err != nil {
+			return nil, err
+		}
+
+		return r.readBytesOrString(size, string)
+	case token.Binary32:
+		size, err := r.readInt32(false)
+		if err != nil {
+			return nil, err
+		}
+
+		return r.readBytesOrString(size, string)
+	case token.Dictionary0, token.Dictionary1, token.Dictionary2, token.Dictionary3:
+		i, err := r.readInt8(false)
+		if err != nil {
+			return "", err
+		}
+
+		return token.GetDoubleToken(tag-token.Dictionary0, i)
+	case token.FBJID:
+		return r.readFBJID()
+	case token.InteropJID:
+		return r.readInteropJID()
+	case token.JIDPair:
+		return r.readJIDPair()
+	case token.ADJID:
+		return r.readADJID()
+	case token.Nibble8, token.Hex8:
+		return r.readPacked8(tag)
+	default:
+		if tag >= 1 && tag < len(token.SingleByteTokens) {
+			return token.SingleByteTokens[tag], nil
+		}
+		return "", fmt.Errorf("%w %d at position %d", ErrInvalidToken, tag, r.index)
+	}
+}
+
+func (r *binaryDecoder) readJIDPair() (interface{}, error) {
+	user, err := r.read(true)
+	if err != nil {
+		return nil, err
+	}
+	server, err := r.read(true)
+	if err != nil {
+		return nil, err
+	} else if server == nil {
+		return nil, ErrInvalidJIDType
+	} else if user == nil {
+		return types.NewJID("", server.(string)), nil
+	}
+	return types.NewJID(user.(string), server.(string)), nil
+}
+
+func (r *binaryDecoder) readInteropJID() (interface{}, error) {
+	user, err := r.read(true)
+	if err != nil {
+		return nil, err
+	}
+	device, err := r.readInt16(false)
+	if err != nil {
+		return nil, err
+	}
+	integrator, err := r.readInt16(false)
+	if err != nil {
+		return nil, err
+	}
+	server, err := r.read(true)
+	if err != nil {
+		return nil, err
+	} else if server != types.InteropServer {
+		return nil, fmt.Errorf("%w: expected %q, got %q", ErrInvalidJIDType, types.InteropServer, server)
+	}
+	return types.JID{
+		User:       user.(string),
+		Device:     uint16(device),
+		Integrator: uint16(integrator),
+		Server:     types.InteropServer,
+	}, nil
+}
+
+func (r *binaryDecoder) readFBJID() (interface{}, error) {
+	user, err := r.read(true)
+	if err != nil {
+		return nil, err
+	}
+	device, err := r.readInt16(false)
+	if err != nil {
+		return nil, err
+	}
+	server, err := r.read(true)
+	if err != nil {
+		return nil, err
+	} else if server != types.MessengerServer {
+		return nil, fmt.Errorf("%w: expected %q, got %q", ErrInvalidJIDType, types.MessengerServer, server)
+	}
+	return types.JID{
+		User:   user.(string),
+		Device: uint16(device),
+		Server: server.(string),
+	}, nil
+}
+
+func (r *binaryDecoder) readADJID() (interface{}, error) {
+	agent, err := r.readByte()
+	if err != nil {
+		return nil, err
+	}
+	device, err := r.readByte()
+	if err != nil {
+		return nil, err
+	}
+	user, err := r.read(true)
+	if err != nil {
+		return nil, err
+	}
+	return types.NewADJID(user.(string), agent, device), nil
+}
+
+func (r *binaryDecoder) readAttributes(n int) (Attrs, error) {
+	if n == 0 {
+		return nil, nil
+	}
+
+	ret := make(Attrs)
+	for i := 0; i < n; i++ {
+		keyIfc, err := r.read(true)
+		if err != nil {
+			return nil, err
+		}
+
+		key, ok := keyIfc.(string)
+		if !ok {
+			return nil, fmt.Errorf("%[1]w at position %[3]d (%[2]T): %+[2]v", ErrNonStringKey, key, r.index)
+		}
+
+		ret[key], err = r.read(true)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return ret, nil
+}
+
+func (r *binaryDecoder) readList(tag int) ([]Node, error) {
+	size, err := r.readListSize(tag)
+	if err != nil {
+		return nil, err
+	}
+
+	ret := make([]Node, size)
+	for i := 0; i < size; i++ {
+		n, err := r.readNode()
+
+		if err != nil {
+			return nil, err
+		}
+
+		ret[i] = *n
+	}
+
+	return ret, nil
+}
+
+func (r *binaryDecoder) readNode() (*Node, error) {
+	ret := &Node{}
+
+	size, err := r.readInt8(false)
+	if err != nil {
+		return nil, err
+	}
+	listSize, err := r.readListSize(size)
+	if err != nil {
+		return nil, err
+	}
+
+	rawDesc, err := r.read(true)
+	if err != nil {
+		return nil, err
+	}
+	ret.Tag = rawDesc.(string)
+	if listSize == 0 || ret.Tag == "" {
+		return nil, ErrInvalidNode
+	}
+
+	ret.Attrs, err = r.readAttributes((listSize - 1) >> 1)
+	if err != nil {
+		return nil, err
+	}
+
+	if listSize%2 == 1 {
+		return ret, nil
+	}
+
+	ret.Content, err = r.read(false)
+	return ret, err
+}
+
+func (r *binaryDecoder) readBytesOrString(length int, asString bool) (interface{}, error) {
+	data, err := r.readRaw(length)
+	if err != nil {
+		return nil, err
+	}
+	if asString {
+		return string(data), nil
+	}
+	return data, nil
+}
+
+func (r *binaryDecoder) readRaw(length int) ([]byte, error) {
+	if err := r.checkEOS(length); err != nil {
+		return nil, err
+	}
+
+	ret := r.data[r.index : r.index+length]
+	r.index += length
+
+	return ret, nil
+}

+ 308 - 0
binary/encoder.go

@@ -0,0 +1,308 @@
+package binary
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+
+	"go.mau.fi/whatsmeow/binary/token"
+	"go.mau.fi/whatsmeow/types"
+)
+
+type binaryEncoder struct {
+	data []byte
+}
+
+func newEncoder() *binaryEncoder {
+	return &binaryEncoder{[]byte{0}}
+}
+
+func (w *binaryEncoder) getData() []byte {
+	return w.data
+}
+
+func (w *binaryEncoder) pushByte(b byte) {
+	w.data = append(w.data, b)
+}
+
+func (w *binaryEncoder) pushBytes(bytes []byte) {
+	w.data = append(w.data, bytes...)
+}
+
+func (w *binaryEncoder) pushIntN(value, n int, littleEndian bool) {
+	for i := 0; i < n; i++ {
+		var curShift int
+		if littleEndian {
+			curShift = i
+		} else {
+			curShift = n - i - 1
+		}
+		w.pushByte(byte((value >> uint(curShift*8)) & 0xFF))
+	}
+}
+
+func (w *binaryEncoder) pushInt20(value int) {
+	w.pushBytes([]byte{byte((value >> 16) & 0x0F), byte((value >> 8) & 0xFF), byte(value & 0xFF)})
+}
+
+func (w *binaryEncoder) pushInt8(value int) {
+	w.pushIntN(value, 1, false)
+}
+
+func (w *binaryEncoder) pushInt16(value int) {
+	w.pushIntN(value, 2, false)
+}
+
+func (w *binaryEncoder) pushInt32(value int) {
+	w.pushIntN(value, 4, false)
+}
+
+func (w *binaryEncoder) pushString(value string) {
+	w.pushBytes([]byte(value))
+}
+
+func (w *binaryEncoder) writeByteLength(length int) {
+	if length < 256 {
+		w.pushByte(token.Binary8)
+		w.pushInt8(length)
+	} else if length < (1 << 20) {
+		w.pushByte(token.Binary20)
+		w.pushInt20(length)
+	} else if length < math.MaxInt32 {
+		w.pushByte(token.Binary32)
+		w.pushInt32(length)
+	} else {
+		panic(fmt.Errorf("length is too large: %d", length))
+	}
+}
+
+const tagSize = 1
+
+func (w *binaryEncoder) writeNode(n Node) {
+	if n.Tag == "0" {
+		w.pushByte(token.List8)
+		w.pushByte(token.ListEmpty)
+		return
+	}
+
+	hasContent := 0
+	if n.Content != nil {
+		hasContent = 1
+	}
+
+	w.writeListStart(2*w.countAttributes(n.Attrs) + tagSize + hasContent)
+	w.writeString(n.Tag)
+	w.writeAttributes(n.Attrs)
+	if n.Content != nil {
+		w.write(n.Content)
+	}
+}
+
+func (w *binaryEncoder) write(data interface{}) {
+	switch typedData := data.(type) {
+	case nil:
+		w.pushByte(token.ListEmpty)
+	case types.JID:
+		w.writeJID(typedData)
+	case string:
+		w.writeString(typedData)
+	case int:
+		w.writeString(strconv.Itoa(typedData))
+	case int32:
+		w.writeString(strconv.FormatInt(int64(typedData), 10))
+	case uint:
+		w.writeString(strconv.FormatUint(uint64(typedData), 10))
+	case uint32:
+		w.writeString(strconv.FormatUint(uint64(typedData), 10))
+	case int64:
+		w.writeString(strconv.FormatInt(typedData, 10))
+	case uint64:
+		w.writeString(strconv.FormatUint(typedData, 10))
+	case bool:
+		w.writeString(strconv.FormatBool(typedData))
+	case []byte:
+		w.writeBytes(typedData)
+	case []Node:
+		w.writeListStart(len(typedData))
+		for _, n := range typedData {
+			w.writeNode(n)
+		}
+	default:
+		panic(fmt.Errorf("%w: %T", ErrInvalidType, typedData))
+	}
+}
+
+func (w *binaryEncoder) writeString(data string) {
+	var dictIndex byte
+	if tokenIndex, ok := token.IndexOfSingleToken(data); ok {
+		w.pushByte(tokenIndex)
+	} else if dictIndex, tokenIndex, ok = token.IndexOfDoubleByteToken(data); ok {
+		w.pushByte(token.Dictionary0 + dictIndex)
+		w.pushByte(tokenIndex)
+	} else if validateNibble(data) {
+		w.writePackedBytes(data, token.Nibble8)
+	} else if validateHex(data) {
+		w.writePackedBytes(data, token.Hex8)
+	} else {
+		w.writeStringRaw(data)
+	}
+}
+
+func (w *binaryEncoder) writeBytes(value []byte) {
+	w.writeByteLength(len(value))
+	w.pushBytes(value)
+}
+
+func (w *binaryEncoder) writeStringRaw(value string) {
+	w.writeByteLength(len(value))
+	w.pushString(value)
+}
+
+func (w *binaryEncoder) writeJID(jid types.JID) {
+	if ((jid.Server == types.DefaultUserServer || jid.Server == types.HiddenUserServer) && jid.Device > 0) || jid.Server == types.HostedServer {
+		w.pushByte(token.ADJID)
+		w.pushByte(jid.ActualAgent())
+		w.pushByte(uint8(jid.Device))
+		w.writeString(jid.User)
+	} else if jid.Server == types.MessengerServer {
+		w.pushByte(token.FBJID)
+		w.write(jid.User)
+		w.pushInt16(int(jid.Device))
+		w.write(jid.Server)
+	} else if jid.Server == types.InteropServer {
+		w.pushByte(token.InteropJID)
+		w.write(jid.User)
+		w.pushInt16(int(jid.Device))
+		w.pushInt16(int(jid.Integrator))
+		w.write(jid.Server)
+	} else {
+		w.pushByte(token.JIDPair)
+		if len(jid.User) == 0 {
+			w.pushByte(token.ListEmpty)
+		} else {
+			w.write(jid.User)
+		}
+		w.write(jid.Server)
+	}
+}
+
+func (w *binaryEncoder) writeAttributes(attributes Attrs) {
+	for key, val := range attributes {
+		if val == "" || val == nil {
+			continue
+		}
+
+		w.writeString(key)
+		w.write(val)
+	}
+}
+
+func (w *binaryEncoder) countAttributes(attributes Attrs) (count int) {
+	for _, val := range attributes {
+		if val == "" || val == nil {
+			continue
+		}
+		count += 1
+	}
+	return
+}
+
+func (w *binaryEncoder) writeListStart(listSize int) {
+	if listSize == 0 {
+		w.pushByte(byte(token.ListEmpty))
+	} else if listSize < 256 {
+		w.pushByte(byte(token.List8))
+		w.pushInt8(listSize)
+	} else {
+		w.pushByte(byte(token.List16))
+		w.pushInt16(listSize)
+	}
+}
+
+func (w *binaryEncoder) writePackedBytes(value string, dataType int) {
+	if len(value) > token.PackedMax {
+		panic(fmt.Errorf("too many bytes to pack: %d", len(value)))
+	}
+
+	w.pushByte(byte(dataType))
+
+	roundedLength := byte(math.Ceil(float64(len(value)) / 2.0))
+	if len(value)%2 != 0 {
+		roundedLength |= 128
+	}
+	w.pushByte(roundedLength)
+	var packer func(byte) byte
+	if dataType == token.Nibble8 {
+		packer = packNibble
+	} else if dataType == token.Hex8 {
+		packer = packHex
+	} else {
+		// This should only be called with the correct values
+		panic(fmt.Errorf("invalid packed byte data type %v", dataType))
+	}
+	for i, l := 0, len(value)/2; i < l; i++ {
+		w.pushByte(w.packBytePair(packer, value[2*i], value[2*i+1]))
+	}
+	if len(value)%2 != 0 {
+		w.pushByte(w.packBytePair(packer, value[len(value)-1], '\x00'))
+	}
+}
+
+func (w *binaryEncoder) packBytePair(packer func(byte) byte, part1, part2 byte) byte {
+	return (packer(part1) << 4) | packer(part2)
+}
+
+func validateNibble(value string) bool {
+	if len(value) > token.PackedMax {
+		return false
+	}
+	for _, char := range value {
+		if !(char >= '0' && char <= '9') && char != '-' && char != '.' {
+			return false
+		}
+	}
+	return true
+}
+
+func packNibble(value byte) byte {
+	switch value {
+	case '-':
+		return 10
+	case '.':
+		return 11
+	case 0:
+		return 15
+	default:
+		if value >= '0' && value <= '9' {
+			return value - '0'
+		}
+		// This should be validated beforehand
+		panic(fmt.Errorf("invalid string to pack as nibble: %d / '%s'", value, string(value)))
+	}
+}
+
+func validateHex(value string) bool {
+	if len(value) > token.PackedMax {
+		return false
+	}
+	for _, char := range value {
+		if !(char >= '0' && char <= '9') && !(char >= 'A' && char <= 'F') {
+			return false
+		}
+	}
+	return true
+}
+
+func packHex(value byte) byte {
+	switch {
+	case value >= '0' && value <= '9':
+		return value - '0'
+	case value >= 'A' && value <= 'F':
+		return 10 + value - 'A'
+	case value == 0:
+		return 15
+	default:
+		// This should be validated beforehand
+		panic(fmt.Errorf("invalid string to pack as hex: %d / '%s'", value, string(value)))
+	}
+}

+ 12 - 0
binary/errors.go

@@ -0,0 +1,12 @@
+package binary
+
+import "errors"
+
+// Errors returned by the binary XML decoder.
+var (
+	ErrInvalidType    = errors.New("unsupported payload type")
+	ErrInvalidJIDType = errors.New("invalid JID type")
+	ErrInvalidNode    = errors.New("invalid node")
+	ErrInvalidToken   = errors.New("invalid token with tag")
+	ErrNonStringKey   = errors.New("non-string key")
+)

+ 139 - 0
binary/node.go

@@ -0,0 +1,139 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Package binary implements encoding and decoding documents in WhatsApp's binary XML format.
+package binary
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"go.mau.fi/whatsmeow/types"
+)
+
+// Attrs is a type alias for the attributes of an XML element (Node).
+type Attrs = map[string]any
+
+// Node represents an XML element.
+type Node struct {
+	Tag     string      // The tag of the element.
+	Attrs   Attrs       // The attributes of the element.
+	Content interface{} // The content inside the element. Can be nil, a list of Nodes, or a byte array.
+}
+
+type marshalableNode struct {
+	Tag     string
+	Attrs   Attrs
+	Content json.RawMessage
+}
+
+func (n *Node) UnmarshalJSON(data []byte) error {
+	var mn marshalableNode
+	err := json.Unmarshal(data, &mn)
+	if err != nil {
+		return err
+	}
+	for key, val := range mn.Attrs {
+		switch typedVal := val.(type) {
+		case string:
+			parsed, err := types.ParseJID(typedVal)
+			if err == nil && parsed.Server == types.DefaultUserServer || parsed.Server == types.NewsletterServer || parsed.Server == types.GroupServer || parsed.Server == types.BroadcastServer {
+				mn.Attrs[key] = parsed
+			}
+		case float64:
+			mn.Attrs[key] = int64(typedVal)
+		}
+	}
+	n.Tag = mn.Tag
+	n.Attrs = mn.Attrs
+	if len(mn.Content) > 0 {
+		if mn.Content[0] == '[' {
+			var nodes []Node
+			err = json.Unmarshal(mn.Content, &nodes)
+			if err != nil {
+				return err
+			}
+			n.Content = nodes
+		} else if mn.Content[0] == '"' {
+			var binaryContent []byte
+			err = json.Unmarshal(mn.Content, &binaryContent)
+			if err != nil {
+				return err
+			}
+			n.Content = binaryContent
+		} else {
+			return fmt.Errorf("node content must be an array of nodes or a base64 string")
+		}
+	}
+	return nil
+}
+
+// GetChildren returns the Content of the node as a list of nodes. If the content is not a list of nodes, this returns nil.
+func (n *Node) GetChildren() []Node {
+	if n.Content == nil {
+		return nil
+	}
+	children, ok := n.Content.([]Node)
+	if !ok {
+		return nil
+	}
+	return children
+}
+
+// GetChildrenByTag returns the same list as GetChildren, but filters it by tag first.
+func (n *Node) GetChildrenByTag(tag string) (children []Node) {
+	for _, node := range n.GetChildren() {
+		if node.Tag == tag {
+			children = append(children, node)
+		}
+	}
+	return
+}
+
+// GetOptionalChildByTag finds the first child with the given tag and returns it.
+// Each provided tag will recurse in, so this is useful for getting a specific nested element.
+func (n *Node) GetOptionalChildByTag(tags ...string) (val Node, ok bool) {
+	val = *n
+Outer:
+	for _, tag := range tags {
+		for _, child := range val.GetChildren() {
+			if child.Tag == tag {
+				val = child
+				continue Outer
+			}
+		}
+		// If no matching children are found, return false
+		return
+	}
+	// All iterations of loop found a matching child, return it
+	ok = true
+	return
+}
+
+// GetChildByTag does the same thing as GetOptionalChildByTag, but returns the Node directly without the ok boolean.
+func (n *Node) GetChildByTag(tags ...string) Node {
+	node, _ := n.GetOptionalChildByTag(tags...)
+	return node
+}
+
+// Marshal encodes an XML element (Node) into WhatsApp's binary XML representation.
+func Marshal(n Node) ([]byte, error) {
+	w := newEncoder()
+	w.writeNode(n)
+	return w.getData(), nil
+}
+
+// Unmarshal decodes WhatsApp's binary XML representation into a Node.
+func Unmarshal(data []byte) (*Node, error) {
+	r := newDecoder(data)
+	n, err := r.readNode()
+	if err != nil {
+		return nil, err
+	} else if r.index != len(r.data) {
+		return n, fmt.Errorf("%d leftover bytes after decoding", len(r.data)-r.index)
+	}
+	return n, nil
+}

+ 4 - 0
binary/proto/doc.go

@@ -0,0 +1,4 @@
+// Package proto contains type aliases for backwards compatibility.
+//
+// Deprecated: New code should reference the protobuf types in the go.mau.fi/whatsmeow/proto/wa* packages directly.
+package proto

+ 1084 - 0
binary/proto/legacy.go

@@ -0,0 +1,1084 @@
+// DO NOT MODIFY: Generated by generatelegacy.sh
+
+package proto
+
+import (
+	"go.mau.fi/whatsmeow/proto/waAICommon"
+	"go.mau.fi/whatsmeow/proto/waAdv"
+	"go.mau.fi/whatsmeow/proto/waBotMetadata"
+	"go.mau.fi/whatsmeow/proto/waCert"
+	"go.mau.fi/whatsmeow/proto/waChatLockSettings"
+	"go.mau.fi/whatsmeow/proto/waCommon"
+	"go.mau.fi/whatsmeow/proto/waCompanionReg"
+	"go.mau.fi/whatsmeow/proto/waDeviceCapabilities"
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/proto/waEphemeral"
+	"go.mau.fi/whatsmeow/proto/waHistorySync"
+	"go.mau.fi/whatsmeow/proto/waMmsRetry"
+	"go.mau.fi/whatsmeow/proto/waMsgTransport"
+	"go.mau.fi/whatsmeow/proto/waQuickPromotionSurfaces"
+	"go.mau.fi/whatsmeow/proto/waServerSync"
+	"go.mau.fi/whatsmeow/proto/waSyncAction"
+	"go.mau.fi/whatsmeow/proto/waUserPassword"
+	"go.mau.fi/whatsmeow/proto/waVnameCert"
+	"go.mau.fi/whatsmeow/proto/waWa6"
+	"go.mau.fi/whatsmeow/proto/waWeb"
+)
+
+// Deprecated: use new packages directly
+type (
+	ADVEncryptionType                                                                                                   = waAdv.ADVEncryptionType
+	KeepType                                                                                                            = waE2E.KeepType
+	PeerDataOperationRequestType                                                                                        = waE2E.PeerDataOperationRequestType
+	MediaVisibility                                                                                                     = waHistorySync.MediaVisibility
+	DeviceProps_PlatformType                                                                                            = waCompanionReg.DeviceProps_PlatformType
+	ImageMessage_ImageSourceType                                                                                        = waE2E.ImageMessage_ImageSourceType
+	HistorySyncNotification_HistorySyncType                                                                             = waE2E.HistorySyncType
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_DayOfWeekType                      = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_DayOfWeekType
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_CalendarType                       = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_CalendarType
+	GroupInviteMessage_GroupType                                                                                        = waE2E.GroupInviteMessage_GroupType
+	ExtendedTextMessage_PreviewType                                                                                     = waE2E.ExtendedTextMessage_PreviewType
+	ExtendedTextMessage_InviteLinkGroupType                                                                             = waE2E.ExtendedTextMessage_InviteLinkGroupType
+	ExtendedTextMessage_FontType                                                                                        = waE2E.ExtendedTextMessage_FontType
+	EventResponseMessage_EventResponseType                                                                              = waE2E.EventResponseMessage_EventResponseType
+	CallLogMessage_CallType                                                                                             = waE2E.CallLogMessage_CallType
+	CallLogMessage_CallOutcome                                                                                          = waE2E.CallLogMessage_CallOutcome
+	ButtonsResponseMessage_Type                                                                                         = waE2E.ButtonsResponseMessage_Type
+	ButtonsMessage_HeaderType                                                                                           = waE2E.ButtonsMessage_HeaderType
+	ButtonsMessage_Button_Type                                                                                          = waE2E.ButtonsMessage_Button_Type
+	BotFeedbackMessage_BotFeedbackKindMultiplePositive                                                                  = waAICommon.BotFeedbackMessage_BotFeedbackKindMultiplePositive
+	BotFeedbackMessage_BotFeedbackKindMultipleNegative                                                                  = waAICommon.BotFeedbackMessage_BotFeedbackKindMultipleNegative
+	BotFeedbackMessage_BotFeedbackKind                                                                                  = waAICommon.BotFeedbackMessage_BotFeedbackKind
+	BCallMessage_MediaType                                                                                              = waE2E.BCallMessage_MediaType
+	HydratedTemplateButton_HydratedURLButton_WebviewPresentationType                                                    = waE2E.HydratedTemplateButton_HydratedURLButton_WebviewPresentationType
+	DisappearingMode_Trigger                                                                                            = waE2E.DisappearingMode_Trigger
+	DisappearingMode_Initiator                                                                                          = waE2E.DisappearingMode_Initiator
+	ContextInfo_ExternalAdReplyInfo_MediaType                                                                           = waE2E.ContextInfo_ExternalAdReplyInfo_MediaType
+	ContextInfo_AdReplyInfo_MediaType                                                                                   = waE2E.ContextInfo_AdReplyInfo_MediaType
+	ForwardedNewsletterMessageInfo_ContentType                                                                          = waE2E.ContextInfo_ForwardedNewsletterMessageInfo_ContentType
+	BotPluginMetadata_SearchProvider                                                                                    = waBotMetadata.BotPluginMetadata_SearchProvider
+	BotPluginMetadata_PluginType                                                                                        = waBotMetadata.BotPluginMetadata_PluginType
+	PaymentBackground_Type                                                                                              = waE2E.PaymentBackground_Type
+	VideoMessage_Attribution                                                                                            = waE2E.VideoMessage_Attribution
+	SecretEncryptedMessage_SecretEncType                                                                                = waE2E.SecretEncryptedMessage_SecretEncType
+	ScheduledCallEditMessage_EditType                                                                                   = waE2E.ScheduledCallEditMessage_EditType
+	ScheduledCallCreationMessage_CallType                                                                               = waE2E.ScheduledCallCreationMessage_CallType
+	RequestWelcomeMessageMetadata_LocalChatState                                                                        = waE2E.RequestWelcomeMessageMetadata_LocalChatState
+	ProtocolMessage_Type                                                                                                = waE2E.ProtocolMessage_Type
+	PlaceholderMessage_PlaceholderType                                                                                  = waE2E.PlaceholderMessage_PlaceholderType
+	PinInChatMessage_Type                                                                                               = waE2E.PinInChatMessage_Type
+	PaymentInviteMessage_ServiceType                                                                                    = waE2E.PaymentInviteMessage_ServiceType
+	OrderMessage_OrderSurface                                                                                           = waE2E.OrderMessage_OrderSurface
+	OrderMessage_OrderStatus                                                                                            = waE2E.OrderMessage_OrderStatus
+	ListResponseMessage_ListType                                                                                        = waE2E.ListResponseMessage_ListType
+	ListMessage_ListType                                                                                                = waE2E.ListMessage_ListType
+	InvoiceMessage_AttachmentType                                                                                       = waE2E.InvoiceMessage_AttachmentType
+	InteractiveResponseMessage_Body_Format                                                                              = waE2E.InteractiveResponseMessage_Body_Format
+	InteractiveMessage_ShopMessage_Surface                                                                              = waE2E.InteractiveMessage_ShopMessage_Surface
+	PastParticipant_LeaveReason                                                                                         = waHistorySync.PastParticipant_LeaveReason
+	HistorySync_HistorySyncType                                                                                         = waHistorySync.HistorySync_HistorySyncType
+	HistorySync_BotAIWaitListState                                                                                      = waHistorySync.HistorySync_BotAIWaitListState
+	GroupParticipant_Rank                                                                                               = waHistorySync.GroupParticipant_Rank
+	Conversation_EndOfHistoryTransferType                                                                               = waHistorySync.Conversation_EndOfHistoryTransferType
+	MediaRetryNotification_ResultType                                                                                   = waMmsRetry.MediaRetryNotification_ResultType
+	SyncdMutation_SyncdOperation                                                                                        = waServerSync.SyncdMutation_SyncdOperation
+	StatusPrivacyAction_StatusDistributionMode                                                                          = waSyncAction.StatusPrivacyAction_StatusDistributionMode
+	MarketingMessageAction_MarketingMessagePrototypeType                                                                = waSyncAction.MarketingMessageAction_MarketingMessagePrototypeType
+	PatchDebugData_Platform                                                                                             = waSyncAction.PatchDebugData_Platform
+	CallLogRecord_SilenceReason                                                                                         = waSyncAction.CallLogRecord_SilenceReason
+	CallLogRecord_CallType                                                                                              = waSyncAction.CallLogRecord_CallType
+	CallLogRecord_CallResult                                                                                            = waSyncAction.CallLogRecord_CallResult
+	BizIdentityInfo_VerifiedLevelValue                                                                                  = waVnameCert.BizIdentityInfo_VerifiedLevelValue
+	BizIdentityInfo_HostStorageType                                                                                     = waVnameCert.BizIdentityInfo_HostStorageType
+	BizIdentityInfo_ActualActorsType                                                                                    = waVnameCert.BizIdentityInfo_ActualActorsType
+	BizAccountLinkInfo_HostStorageType                                                                                  = waVnameCert.BizAccountLinkInfo_HostStorageType
+	BizAccountLinkInfo_AccountType                                                                                      = waVnameCert.BizAccountLinkInfo_AccountType
+	ClientPayload_Product                                                                                               = waWa6.ClientPayload_Product
+	ClientPayload_IOSAppExtension                                                                                       = waWa6.ClientPayload_IOSAppExtension
+	ClientPayload_ConnectType                                                                                           = waWa6.ClientPayload_ConnectType
+	ClientPayload_ConnectReason                                                                                         = waWa6.ClientPayload_ConnectReason
+	ClientPayload_WebInfo_WebSubPlatform                                                                                = waWa6.ClientPayload_WebInfo_WebSubPlatform
+	ClientPayload_UserAgent_ReleaseChannel                                                                              = waWa6.ClientPayload_UserAgent_ReleaseChannel
+	ClientPayload_UserAgent_Platform                                                                                    = waWa6.ClientPayload_UserAgent_Platform
+	ClientPayload_UserAgent_DeviceType                                                                                  = waWa6.ClientPayload_UserAgent_DeviceType
+	ClientPayload_DNSSource_DNSResolutionMethod                                                                         = waWa6.ClientPayload_DNSSource_DNSResolutionMethod
+	WebMessageInfo_StubType                                                                                             = waWeb.WebMessageInfo_StubType
+	WebMessageInfo_Status                                                                                               = waWeb.WebMessageInfo_Status
+	WebMessageInfo_BizPrivacyStatus                                                                                     = waWeb.WebMessageInfo_BizPrivacyStatus
+	WebFeatures_Flag                                                                                                    = waWeb.WebFeatures_Flag
+	PinInChat_Type                                                                                                      = waWeb.PinInChat_Type
+	PaymentInfo_TxnStatus                                                                                               = waWeb.PaymentInfo_TxnStatus
+	PaymentInfo_Status                                                                                                  = waWeb.PaymentInfo_Status
+	PaymentInfo_Currency                                                                                                = waWeb.PaymentInfo_Currency
+	QP_FilterResult                                                                                                     = waQuickPromotionSurfaces.QP_FilterResult
+	QP_FilterClientNotSupportedConfig                                                                                   = waQuickPromotionSurfaces.QP_FilterClientNotSupportedConfig
+	QP_ClauseType                                                                                                       = waQuickPromotionSurfaces.QP_ClauseType
+	DeviceCapabilities_ChatLockSupportLevel                                                                             = waDeviceCapabilities.DeviceCapabilities_ChatLockSupportLevel
+	UserPassword_Transformer                                                                                            = waUserPassword.UserPassword_Transformer
+	UserPassword_Encoding                                                                                               = waUserPassword.UserPassword_Encoding
+	ADVSignedKeyIndexList                                                                                               = waAdv.ADVSignedKeyIndexList
+	ADVSignedDeviceIdentity                                                                                             = waAdv.ADVSignedDeviceIdentity
+	ADVSignedDeviceIdentityHMAC                                                                                         = waAdv.ADVSignedDeviceIdentityHMAC
+	ADVKeyIndexList                                                                                                     = waAdv.ADVKeyIndexList
+	ADVDeviceIdentity                                                                                                   = waAdv.ADVDeviceIdentity
+	DeviceProps                                                                                                         = waCompanionReg.DeviceProps
+	InitialSecurityNotificationSettingSync                                                                              = waE2E.InitialSecurityNotificationSettingSync
+	ImageMessage                                                                                                        = waE2E.ImageMessage
+	HistorySyncNotification                                                                                             = waE2E.HistorySyncNotification
+	HighlyStructuredMessage                                                                                             = waE2E.HighlyStructuredMessage
+	GroupInviteMessage                                                                                                  = waE2E.GroupInviteMessage
+	FutureProofMessage                                                                                                  = waE2E.FutureProofMessage
+	ExtendedTextMessage                                                                                                 = waE2E.ExtendedTextMessage
+	EventResponseMessage                                                                                                = waE2E.EventResponseMessage
+	EventMessage                                                                                                        = waE2E.EventMessage
+	EncReactionMessage                                                                                                  = waE2E.EncReactionMessage
+	EncEventResponseMessage                                                                                             = waE2E.EncEventResponseMessage
+	EncCommentMessage                                                                                                   = waE2E.EncCommentMessage
+	DocumentMessage                                                                                                     = waE2E.DocumentMessage
+	DeviceSentMessage                                                                                                   = waE2E.DeviceSentMessage
+	DeclinePaymentRequestMessage                                                                                        = waE2E.DeclinePaymentRequestMessage
+	ContactsArrayMessage                                                                                                = waE2E.ContactsArrayMessage
+	ContactMessage                                                                                                      = waE2E.ContactMessage
+	CommentMessage                                                                                                      = waE2E.CommentMessage
+	Chat                                                                                                                = waE2E.Chat
+	CancelPaymentRequestMessage                                                                                         = waE2E.CancelPaymentRequestMessage
+	Call                                                                                                                = waE2E.Call
+	CallLogMessage                                                                                                      = waE2E.CallLogMessage
+	ButtonsResponseMessage                                                                                              = waE2E.ButtonsResponseMessage
+	ButtonsResponseMessage_SelectedDisplayText                                                                          = waE2E.ButtonsResponseMessage_SelectedDisplayText
+	ButtonsMessage                                                                                                      = waE2E.ButtonsMessage
+	ButtonsMessage_Text                                                                                                 = waE2E.ButtonsMessage_Text
+	ButtonsMessage_DocumentMessage                                                                                      = waE2E.ButtonsMessage_DocumentMessage
+	ButtonsMessage_ImageMessage                                                                                         = waE2E.ButtonsMessage_ImageMessage
+	ButtonsMessage_VideoMessage                                                                                         = waE2E.ButtonsMessage_VideoMessage
+	ButtonsMessage_LocationMessage                                                                                      = waE2E.ButtonsMessage_LocationMessage
+	BotFeedbackMessage                                                                                                  = waAICommon.BotFeedbackMessage
+	BCallMessage                                                                                                        = waE2E.BCallMessage
+	AudioMessage                                                                                                        = waE2E.AudioMessage
+	AppStateSyncKey                                                                                                     = waE2E.AppStateSyncKey
+	AppStateSyncKeyShare                                                                                                = waE2E.AppStateSyncKeyShare
+	AppStateSyncKeyRequest                                                                                              = waE2E.AppStateSyncKeyRequest
+	AppStateSyncKeyId                                                                                                   = waE2E.AppStateSyncKeyId
+	AppStateSyncKeyFingerprint                                                                                          = waE2E.AppStateSyncKeyFingerprint
+	AppStateSyncKeyData                                                                                                 = waE2E.AppStateSyncKeyData
+	AppStateFatalExceptionNotification                                                                                  = waE2E.AppStateFatalExceptionNotification
+	MediaNotifyMessage                                                                                                  = waE2E.MediaNotifyMessage
+	Location                                                                                                            = waE2E.Location
+	InteractiveAnnotation                                                                                               = waE2E.InteractiveAnnotation
+	InteractiveAnnotation_Location                                                                                      = waE2E.InteractiveAnnotation_Location
+	InteractiveAnnotation_Newsletter                                                                                    = waE2E.InteractiveAnnotation_Newsletter
+	HydratedTemplateButton                                                                                              = waE2E.HydratedTemplateButton
+	HydratedTemplateButton_QuickReplyButton                                                                             = waE2E.HydratedTemplateButton_QuickReplyButton
+	HydratedTemplateButton_UrlButton                                                                                    = waE2E.HydratedTemplateButton_UrlButton
+	HydratedTemplateButton_CallButton                                                                                   = waE2E.HydratedTemplateButton_CallButton
+	GroupMention                                                                                                        = waE2E.GroupMention
+	DisappearingMode                                                                                                    = waE2E.DisappearingMode
+	DeviceListMetadata                                                                                                  = waMsgTransport.DeviceListMetadata
+	ContextInfo                                                                                                         = waE2E.ContextInfo
+	ForwardedNewsletterMessageInfo                                                                                      = waE2E.ContextInfo_ForwardedNewsletterMessageInfo
+	BotSuggestedPromptMetadata                                                                                          = waBotMetadata.BotSuggestedPromptMetadata
+	BotPluginMetadata                                                                                                   = waBotMetadata.BotPluginMetadata
+	BotMetadata                                                                                                         = waBotMetadata.BotMetadata
+	BotAvatarMetadata                                                                                                   = waBotMetadata.BotAvatarMetadata
+	ActionLink                                                                                                          = waE2E.ActionLink
+	TemplateButton                                                                                                      = waE2E.TemplateButton
+	TemplateButton_QuickReplyButton_                                                                                    = waE2E.TemplateButton_QuickReplyButton_
+	TemplateButton_UrlButton                                                                                            = waE2E.TemplateButton_UrlButton
+	TemplateButton_CallButton_                                                                                          = waE2E.TemplateButton_CallButton_
+	Point                                                                                                               = waE2E.Point
+	PaymentBackground                                                                                                   = waE2E.PaymentBackground
+	Money                                                                                                               = waE2E.Money
+	Message                                                                                                             = waE2E.Message
+	MessageSecretMessage                                                                                                = waE2E.MessageSecretMessage
+	MessageContextInfo                                                                                                  = waE2E.MessageContextInfo
+	VideoMessage                                                                                                        = waE2E.VideoMessage
+	TemplateMessage                                                                                                     = waE2E.TemplateMessage
+	TemplateMessage_FourRowTemplate_                                                                                    = waE2E.TemplateMessage_FourRowTemplate_
+	TemplateMessage_HydratedFourRowTemplate_                                                                            = waE2E.TemplateMessage_HydratedFourRowTemplate_
+	TemplateMessage_InteractiveMessageTemplate                                                                          = waE2E.TemplateMessage_InteractiveMessageTemplate
+	TemplateButtonReplyMessage                                                                                          = waE2E.TemplateButtonReplyMessage
+	StickerSyncRMRMessage                                                                                               = waE2E.StickerSyncRMRMessage
+	StickerMessage                                                                                                      = waE2E.StickerMessage
+	SenderKeyDistributionMessage                                                                                        = waE2E.SenderKeyDistributionMessage
+	SendPaymentMessage                                                                                                  = waE2E.SendPaymentMessage
+	SecretEncryptedMessage                                                                                              = waE2E.SecretEncryptedMessage
+	ScheduledCallEditMessage                                                                                            = waE2E.ScheduledCallEditMessage
+	ScheduledCallCreationMessage                                                                                        = waE2E.ScheduledCallCreationMessage
+	RequestWelcomeMessageMetadata                                                                                       = waE2E.RequestWelcomeMessageMetadata
+	RequestPhoneNumberMessage                                                                                           = waE2E.RequestPhoneNumberMessage
+	RequestPaymentMessage                                                                                               = waE2E.RequestPaymentMessage
+	ReactionMessage                                                                                                     = waE2E.ReactionMessage
+	ProtocolMessage                                                                                                     = waE2E.ProtocolMessage
+	ProductMessage                                                                                                      = waE2E.ProductMessage
+	PollVoteMessage                                                                                                     = waE2E.PollVoteMessage
+	PollUpdateMessage                                                                                                   = waE2E.PollUpdateMessage
+	PollUpdateMessageMetadata                                                                                           = waE2E.PollUpdateMessageMetadata
+	PollEncValue                                                                                                        = waE2E.PollEncValue
+	PollCreationMessage                                                                                                 = waE2E.PollCreationMessage
+	PlaceholderMessage                                                                                                  = waE2E.PlaceholderMessage
+	PinInChatMessage                                                                                                    = waE2E.PinInChatMessage
+	PeerDataOperationRequestResponseMessage                                                                             = waE2E.PeerDataOperationRequestResponseMessage
+	PeerDataOperationRequestMessage                                                                                     = waE2E.PeerDataOperationRequestMessage
+	PaymentInviteMessage                                                                                                = waE2E.PaymentInviteMessage
+	OrderMessage                                                                                                        = waE2E.OrderMessage
+	NewsletterAdminInviteMessage                                                                                        = waE2E.NewsletterAdminInviteMessage
+	MessageHistoryBundle                                                                                                = waE2E.MessageHistoryBundle
+	LocationMessage                                                                                                     = waE2E.LocationMessage
+	LiveLocationMessage                                                                                                 = waE2E.LiveLocationMessage
+	ListResponseMessage                                                                                                 = waE2E.ListResponseMessage
+	ListMessage                                                                                                         = waE2E.ListMessage
+	KeepInChatMessage                                                                                                   = waE2E.KeepInChatMessage
+	InvoiceMessage                                                                                                      = waE2E.InvoiceMessage
+	InteractiveResponseMessage                                                                                          = waE2E.InteractiveResponseMessage
+	InteractiveResponseMessage_NativeFlowResponseMessage_                                                               = waE2E.InteractiveResponseMessage_NativeFlowResponseMessage_
+	InteractiveMessage                                                                                                  = waE2E.InteractiveMessage
+	InteractiveMessage_ShopStorefrontMessage                                                                            = waE2E.InteractiveMessage_ShopStorefrontMessage
+	InteractiveMessage_CollectionMessage_                                                                               = waE2E.InteractiveMessage_CollectionMessage_
+	InteractiveMessage_NativeFlowMessage_                                                                               = waE2E.InteractiveMessage_NativeFlowMessage_
+	InteractiveMessage_CarouselMessage_                                                                                 = waE2E.InteractiveMessage_CarouselMessage_
+	EphemeralSetting                                                                                                    = waEphemeral.EphemeralSetting
+	WallpaperSettings                                                                                                   = waHistorySync.WallpaperSettings
+	StickerMetadata                                                                                                     = waHistorySync.StickerMetadata
+	Pushname                                                                                                            = waHistorySync.Pushname
+	PhoneNumberToLIDMapping                                                                                             = waHistorySync.PhoneNumberToLIDMapping
+	PastParticipants                                                                                                    = waHistorySync.PastParticipants
+	PastParticipant                                                                                                     = waHistorySync.PastParticipant
+	NotificationSettings                                                                                                = waHistorySync.NotificationSettings
+	HistorySync                                                                                                         = waHistorySync.HistorySync
+	HistorySyncMsg                                                                                                      = waHistorySync.HistorySyncMsg
+	GroupParticipant                                                                                                    = waHistorySync.GroupParticipant
+	GlobalSettings                                                                                                      = waHistorySync.GlobalSettings
+	Conversation                                                                                                        = waHistorySync.Conversation
+	AvatarUserSettings                                                                                                  = waHistorySync.AvatarUserSettings
+	AutoDownloadSettings                                                                                                = waHistorySync.AutoDownloadSettings
+	ServerErrorReceipt                                                                                                  = waMmsRetry.ServerErrorReceipt
+	MediaRetryNotification                                                                                              = waMmsRetry.MediaRetryNotification
+	MessageKey                                                                                                          = waCommon.MessageKey
+	SyncdVersion                                                                                                        = waServerSync.SyncdVersion
+	SyncdValue                                                                                                          = waServerSync.SyncdValue
+	SyncdSnapshot                                                                                                       = waServerSync.SyncdSnapshot
+	SyncdRecord                                                                                                         = waServerSync.SyncdRecord
+	SyncdPatch                                                                                                          = waServerSync.SyncdPatch
+	SyncdMutations                                                                                                      = waServerSync.SyncdMutations
+	SyncdMutation                                                                                                       = waServerSync.SyncdMutation
+	SyncdIndex                                                                                                          = waServerSync.SyncdIndex
+	KeyId                                                                                                               = waServerSync.KeyId
+	ExternalBlobReference                                                                                               = waServerSync.ExternalBlobReference
+	ExitCode                                                                                                            = waServerSync.ExitCode
+	SyncActionValue                                                                                                     = waSyncAction.SyncActionValue
+	WamoUserIdentifierAction                                                                                            = waSyncAction.WamoUserIdentifierAction
+	UserStatusMuteAction                                                                                                = waSyncAction.UserStatusMuteAction
+	UnarchiveChatsSetting                                                                                               = waSyncAction.UnarchiveChatsSetting
+	TimeFormatAction                                                                                                    = waSyncAction.TimeFormatAction
+	SyncActionMessage                                                                                                   = waSyncAction.SyncActionMessage
+	SyncActionMessageRange                                                                                              = waSyncAction.SyncActionMessageRange
+	SubscriptionAction                                                                                                  = waSyncAction.SubscriptionAction
+	StickerAction                                                                                                       = waSyncAction.StickerAction
+	StatusPrivacyAction                                                                                                 = waSyncAction.StatusPrivacyAction
+	StarAction                                                                                                          = waSyncAction.StarAction
+	RemoveRecentStickerAction                                                                                           = waSyncAction.RemoveRecentStickerAction
+	RecentEmojiWeightsAction                                                                                            = waSyncAction.RecentEmojiWeightsAction
+	QuickReplyAction                                                                                                    = waSyncAction.QuickReplyAction
+	PushNameSetting                                                                                                     = waSyncAction.PushNameSetting
+	PrivacySettingRelayAllCalls                                                                                         = waSyncAction.PrivacySettingRelayAllCalls
+	PrivacySettingDisableLinkPreviewsAction                                                                             = waSyncAction.PrivacySettingDisableLinkPreviewsAction
+	PrimaryVersionAction                                                                                                = waSyncAction.PrimaryVersionAction
+	PrimaryFeature                                                                                                      = waSyncAction.PrimaryFeature
+	PnForLidChatAction                                                                                                  = waSyncAction.PnForLidChatAction
+	PinAction                                                                                                           = waSyncAction.PinAction
+	PaymentInfoAction                                                                                                   = waSyncAction.PaymentInfoAction
+	NuxAction                                                                                                           = waSyncAction.NuxAction
+	MuteAction                                                                                                          = waSyncAction.MuteAction
+	MarketingMessageBroadcastAction                                                                                     = waSyncAction.MarketingMessageBroadcastAction
+	MarketingMessageAction                                                                                              = waSyncAction.MarketingMessageAction
+	MarkChatAsReadAction                                                                                                = waSyncAction.MarkChatAsReadAction
+	LockChatAction                                                                                                      = waSyncAction.LockChatAction
+	LocaleSetting                                                                                                       = waSyncAction.LocaleSetting
+	LabelReorderingAction                                                                                               = waSyncAction.LabelReorderingAction
+	LabelEditAction                                                                                                     = waSyncAction.LabelEditAction
+	LabelAssociationAction                                                                                              = waSyncAction.LabelAssociationAction
+	KeyExpiration                                                                                                       = waSyncAction.KeyExpiration
+	ExternalWebBetaAction                                                                                               = waSyncAction.ExternalWebBetaAction
+	DeleteMessageForMeAction                                                                                            = waSyncAction.DeleteMessageForMeAction
+	DeleteIndividualCallLogAction                                                                                       = waSyncAction.DeleteIndividualCallLogAction
+	DeleteChatAction                                                                                                    = waSyncAction.DeleteChatAction
+	CustomPaymentMethodsAction                                                                                          = waSyncAction.CustomPaymentMethodsAction
+	CustomPaymentMethod                                                                                                 = waSyncAction.CustomPaymentMethod
+	CustomPaymentMethodMetadata                                                                                         = waSyncAction.CustomPaymentMethodMetadata
+	ContactAction                                                                                                       = waSyncAction.ContactAction
+	ClearChatAction                                                                                                     = waSyncAction.ClearChatAction
+	ChatAssignmentOpenedStatusAction                                                                                    = waSyncAction.ChatAssignmentOpenedStatusAction
+	ChatAssignmentAction                                                                                                = waSyncAction.ChatAssignmentAction
+	CallLogAction                                                                                                       = waSyncAction.CallLogAction
+	BotWelcomeRequestAction                                                                                             = waSyncAction.BotWelcomeRequestAction
+	ArchiveChatAction                                                                                                   = waSyncAction.ArchiveChatAction
+	AndroidUnsupportedActions                                                                                           = waSyncAction.AndroidUnsupportedActions
+	AgentAction                                                                                                         = waSyncAction.AgentAction
+	SyncActionData                                                                                                      = waSyncAction.SyncActionData
+	RecentEmojiWeight                                                                                                   = waSyncAction.RecentEmojiWeight
+	PatchDebugData                                                                                                      = waSyncAction.PatchDebugData
+	CallLogRecord                                                                                                       = waSyncAction.CallLogRecord
+	VerifiedNameCertificate                                                                                             = waVnameCert.VerifiedNameCertificate
+	LocalizedName                                                                                                       = waVnameCert.LocalizedName
+	BizIdentityInfo                                                                                                     = waVnameCert.BizIdentityInfo
+	BizAccountPayload                                                                                                   = waVnameCert.BizAccountPayload
+	BizAccountLinkInfo                                                                                                  = waVnameCert.BizAccountLinkInfo
+	HandshakeMessage                                                                                                    = waWa6.HandshakeMessage
+	HandshakeServerHello                                                                                                = waWa6.HandshakeMessage_ServerHello
+	HandshakeClientHello                                                                                                = waWa6.HandshakeMessage_ClientHello
+	HandshakeClientFinish                                                                                               = waWa6.HandshakeMessage_ClientFinish
+	ClientPayload                                                                                                       = waWa6.ClientPayload
+	WebNotificationsInfo                                                                                                = waWeb.WebNotificationsInfo
+	WebMessageInfo                                                                                                      = waWeb.WebMessageInfo
+	WebFeatures                                                                                                         = waWeb.WebFeatures
+	UserReceipt                                                                                                         = waWeb.UserReceipt
+	StatusPSA                                                                                                           = waWeb.StatusPSA
+	ReportingTokenInfo                                                                                                  = waWeb.ReportingTokenInfo
+	Reaction                                                                                                            = waWeb.Reaction
+	PremiumMessageInfo                                                                                                  = waWeb.PremiumMessageInfo
+	PollUpdate                                                                                                          = waWeb.PollUpdate
+	PollAdditionalMetadata                                                                                              = waWeb.PollAdditionalMetadata
+	PinInChat                                                                                                           = waWeb.PinInChat
+	PhotoChange                                                                                                         = waWeb.PhotoChange
+	PaymentInfo                                                                                                         = waWeb.PaymentInfo
+	NotificationMessageInfo                                                                                             = waWeb.NotificationMessageInfo
+	MessageAddOnContextInfo                                                                                             = waWeb.MessageAddOnContextInfo
+	MediaData                                                                                                           = waWeb.MediaData
+	KeepInChat                                                                                                          = waWeb.KeepInChat
+	EventResponse                                                                                                       = waWeb.EventResponse
+	EventAdditionalMetadata                                                                                             = waWeb.EventAdditionalMetadata
+	CommentMetadata                                                                                                     = waWeb.CommentMetadata
+	NoiseCertificate                                                                                                    = waCert.NoiseCertificate
+	CertChain                                                                                                           = waCert.CertChain
+	QP                                                                                                                  = waQuickPromotionSurfaces.QP
+	ChatLockSettings                                                                                                    = waChatLockSettings.ChatLockSettings
+	DeviceCapabilities                                                                                                  = waDeviceCapabilities.DeviceCapabilities
+	UserPassword                                                                                                        = waUserPassword.UserPassword
+	DeviceProps_HistorySyncConfig                                                                                       = waCompanionReg.DeviceProps_HistorySyncConfig
+	DeviceProps_AppVersion                                                                                              = waCompanionReg.DeviceProps_AppVersion
+	HighlyStructuredMessage_HSMLocalizableParameter                                                                     = waE2E.HighlyStructuredMessage_HSMLocalizableParameter
+	HighlyStructuredMessage_HSMLocalizableParameter_Currency                                                            = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_Currency
+	HighlyStructuredMessage_HSMLocalizableParameter_DateTime                                                            = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_DateTime
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime                                                         = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_Component                                               = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_Component
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_UnixEpoch                                               = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_UnixEpoch
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMCurrency                                                         = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMCurrency
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeUnixEpoch                                    = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeUnixEpoch
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent                                    = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent
+	CallLogMessage_CallParticipant                                                                                      = waE2E.CallLogMessage_CallParticipant
+	ButtonsMessage_Button                                                                                               = waE2E.ButtonsMessage_Button
+	ButtonsMessage_Button_NativeFlowInfo                                                                                = waE2E.ButtonsMessage_Button_NativeFlowInfo
+	ButtonsMessage_Button_ButtonText                                                                                    = waE2E.ButtonsMessage_Button_ButtonText
+	HydratedTemplateButton_HydratedURLButton                                                                            = waE2E.HydratedTemplateButton_HydratedURLButton
+	HydratedTemplateButton_HydratedQuickReplyButton                                                                     = waE2E.HydratedTemplateButton_HydratedQuickReplyButton
+	HydratedTemplateButton_HydratedCallButton                                                                           = waE2E.HydratedTemplateButton_HydratedCallButton
+	ContextInfo_UTMInfo                                                                                                 = waE2E.ContextInfo_UTMInfo
+	ContextInfo_ExternalAdReplyInfo                                                                                     = waE2E.ContextInfo_ExternalAdReplyInfo
+	ContextInfo_DataSharingContext                                                                                      = waE2E.ContextInfo_DataSharingContext
+	ContextInfo_BusinessMessageForwardInfo                                                                              = waE2E.ContextInfo_BusinessMessageForwardInfo
+	ContextInfo_AdReplyInfo                                                                                             = waE2E.ContextInfo_AdReplyInfo
+	TemplateButton_URLButton                                                                                            = waE2E.TemplateButton_URLButton
+	TemplateButton_QuickReplyButton                                                                                     = waE2E.TemplateButton_QuickReplyButton
+	TemplateButton_CallButton                                                                                           = waE2E.TemplateButton_CallButton
+	PaymentBackground_MediaData                                                                                         = waE2E.PaymentBackground_MediaData
+	TemplateMessage_HydratedFourRowTemplate                                                                             = waE2E.TemplateMessage_HydratedFourRowTemplate
+	TemplateMessage_HydratedFourRowTemplate_DocumentMessage                                                             = waE2E.TemplateMessage_HydratedFourRowTemplate_DocumentMessage
+	TemplateMessage_HydratedFourRowTemplate_HydratedTitleText                                                           = waE2E.TemplateMessage_HydratedFourRowTemplate_HydratedTitleText
+	TemplateMessage_HydratedFourRowTemplate_ImageMessage                                                                = waE2E.TemplateMessage_HydratedFourRowTemplate_ImageMessage
+	TemplateMessage_HydratedFourRowTemplate_VideoMessage                                                                = waE2E.TemplateMessage_HydratedFourRowTemplate_VideoMessage
+	TemplateMessage_HydratedFourRowTemplate_LocationMessage                                                             = waE2E.TemplateMessage_HydratedFourRowTemplate_LocationMessage
+	TemplateMessage_FourRowTemplate                                                                                     = waE2E.TemplateMessage_FourRowTemplate
+	TemplateMessage_FourRowTemplate_DocumentMessage                                                                     = waE2E.TemplateMessage_FourRowTemplate_DocumentMessage
+	TemplateMessage_FourRowTemplate_HighlyStructuredMessage                                                             = waE2E.TemplateMessage_FourRowTemplate_HighlyStructuredMessage
+	TemplateMessage_FourRowTemplate_ImageMessage                                                                        = waE2E.TemplateMessage_FourRowTemplate_ImageMessage
+	TemplateMessage_FourRowTemplate_VideoMessage                                                                        = waE2E.TemplateMessage_FourRowTemplate_VideoMessage
+	TemplateMessage_FourRowTemplate_LocationMessage                                                                     = waE2E.TemplateMessage_FourRowTemplate_LocationMessage
+	ProductMessage_ProductSnapshot                                                                                      = waE2E.ProductMessage_ProductSnapshot
+	ProductMessage_CatalogSnapshot                                                                                      = waE2E.ProductMessage_CatalogSnapshot
+	PollCreationMessage_Option                                                                                          = waE2E.PollCreationMessage_Option
+	PeerDataOperationRequestResponseMessage_PeerDataOperationResult                                                     = waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult
+	PeerDataOperationRequestResponseMessage_PeerDataOperationResult_PlaceholderMessageResendResponse                    = waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_PlaceholderMessageResendResponse
+	PeerDataOperationRequestResponseMessage_PeerDataOperationResult_LinkPreviewResponse                                 = waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_LinkPreviewResponse
+	PeerDataOperationRequestResponseMessage_PeerDataOperationResult_LinkPreviewResponse_LinkPreviewHighQualityThumbnail = waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_LinkPreviewResponse_LinkPreviewHighQualityThumbnail
+	PeerDataOperationRequestMessage_RequestUrlPreview                                                                   = waE2E.PeerDataOperationRequestMessage_RequestUrlPreview
+	PeerDataOperationRequestMessage_RequestStickerReupload                                                              = waE2E.PeerDataOperationRequestMessage_RequestStickerReupload
+	PeerDataOperationRequestMessage_PlaceholderMessageResendRequest                                                     = waE2E.PeerDataOperationRequestMessage_PlaceholderMessageResendRequest
+	PeerDataOperationRequestMessage_HistorySyncOnDemandRequest                                                          = waE2E.PeerDataOperationRequestMessage_HistorySyncOnDemandRequest
+	ListResponseMessage_SingleSelectReply                                                                               = waE2E.ListResponseMessage_SingleSelectReply
+	ListMessage_Section                                                                                                 = waE2E.ListMessage_Section
+	ListMessage_Row                                                                                                     = waE2E.ListMessage_Row
+	ListMessage_Product                                                                                                 = waE2E.ListMessage_Product
+	ListMessage_ProductSection                                                                                          = waE2E.ListMessage_ProductSection
+	ListMessage_ProductListInfo                                                                                         = waE2E.ListMessage_ProductListInfo
+	ListMessage_ProductListHeaderImage                                                                                  = waE2E.ListMessage_ProductListHeaderImage
+	InteractiveResponseMessage_NativeFlowResponseMessage                                                                = waE2E.InteractiveResponseMessage_NativeFlowResponseMessage
+	InteractiveResponseMessage_Body                                                                                     = waE2E.InteractiveResponseMessage_Body
+	InteractiveMessage_NativeFlowMessage                                                                                = waE2E.InteractiveMessage_NativeFlowMessage
+	InteractiveMessage_Header                                                                                           = waE2E.InteractiveMessage_Header
+	InteractiveMessage_Header_DocumentMessage                                                                           = waE2E.InteractiveMessage_Header_DocumentMessage
+	InteractiveMessage_Header_ImageMessage                                                                              = waE2E.InteractiveMessage_Header_ImageMessage
+	InteractiveMessage_Header_JpegThumbnail                                                                             = waE2E.InteractiveMessage_Header_JPEGThumbnail
+	InteractiveMessage_Header_VideoMessage                                                                              = waE2E.InteractiveMessage_Header_VideoMessage
+	InteractiveMessage_Header_LocationMessage                                                                           = waE2E.InteractiveMessage_Header_LocationMessage
+	InteractiveMessage_Header_ProductMessage                                                                            = waE2E.InteractiveMessage_Header_ProductMessage
+	InteractiveMessage_Footer                                                                                           = waE2E.InteractiveMessage_Footer
+	InteractiveMessage_CollectionMessage                                                                                = waE2E.InteractiveMessage_CollectionMessage
+	InteractiveMessage_CarouselMessage                                                                                  = waE2E.InteractiveMessage_CarouselMessage
+	InteractiveMessage_Body                                                                                             = waE2E.InteractiveMessage_Body
+	InteractiveMessage_ShopMessage                                                                                      = waE2E.InteractiveMessage_ShopMessage
+	InteractiveMessage_NativeFlowMessage_NativeFlowButton                                                               = waE2E.InteractiveMessage_NativeFlowMessage_NativeFlowButton
+	CallLogRecord_ParticipantInfo                                                                                       = waSyncAction.CallLogRecord_ParticipantInfo
+	VerifiedNameCertificate_Details                                                                                     = waVnameCert.VerifiedNameCertificate_Details
+	ClientPayload_WebInfo                                                                                               = waWa6.ClientPayload_WebInfo
+	ClientPayload_UserAgent                                                                                             = waWa6.ClientPayload_UserAgent
+	ClientPayload_InteropData                                                                                           = waWa6.ClientPayload_InteropData
+	ClientPayload_DevicePairingRegistrationData                                                                         = waWa6.ClientPayload_DevicePairingRegistrationData
+	ClientPayload_DNSSource                                                                                             = waWa6.ClientPayload_DNSSource
+	ClientPayload_WebInfo_WebdPayload                                                                                   = waWa6.ClientPayload_WebInfo_WebdPayload
+	ClientPayload_UserAgent_AppVersion                                                                                  = waWa6.ClientPayload_UserAgent_AppVersion
+	NoiseCertificate_Details                                                                                            = waCert.NoiseCertificate_Details
+	CertChain_NoiseCertificate                                                                                          = waCert.CertChain_NoiseCertificate
+	CertChain_NoiseCertificate_Details                                                                                  = waCert.CertChain_NoiseCertificate_Details
+	QP_Filter                                                                                                           = waQuickPromotionSurfaces.QP_Filter
+	QP_FilterParameters                                                                                                 = waQuickPromotionSurfaces.QP_FilterParameters
+	QP_FilterClause                                                                                                     = waQuickPromotionSurfaces.QP_FilterClause
+	UserPassword_TransformerArg                                                                                         = waUserPassword.UserPassword_TransformerArg
+	UserPassword_TransformerArg_Value                                                                                   = waUserPassword.UserPassword_TransformerArg_Value
+	UserPassword_TransformerArg_Value_AsBlob                                                                            = waUserPassword.UserPassword_TransformerArg_Value_AsBlob
+	UserPassword_TransformerArg_Value_AsUnsignedInteger                                                                 = waUserPassword.UserPassword_TransformerArg_Value_AsUnsignedInteger
+)
+
+// Deprecated: use new packages directly
+const (
+	ADVEncryptionType_E2EE                                                                       = waAdv.ADVEncryptionType_E2EE
+	ADVEncryptionType_HOSTED                                                                     = waAdv.ADVEncryptionType_HOSTED
+	KeepType_UNKNOWN                                                                             = waE2E.KeepType_UNKNOWN_KEEP_TYPE
+	KeepType_KEEP_FOR_ALL                                                                        = waE2E.KeepType_KEEP_FOR_ALL
+	KeepType_UNDO_KEEP_FOR_ALL                                                                   = waE2E.KeepType_UNDO_KEEP_FOR_ALL
+	PeerDataOperationRequestType_UPLOAD_STICKER                                                  = waE2E.PeerDataOperationRequestType_UPLOAD_STICKER
+	PeerDataOperationRequestType_SEND_RECENT_STICKER_BOOTSTRAP                                   = waE2E.PeerDataOperationRequestType_SEND_RECENT_STICKER_BOOTSTRAP
+	PeerDataOperationRequestType_GENERATE_LINK_PREVIEW                                           = waE2E.PeerDataOperationRequestType_GENERATE_LINK_PREVIEW
+	PeerDataOperationRequestType_HISTORY_SYNC_ON_DEMAND                                          = waE2E.PeerDataOperationRequestType_HISTORY_SYNC_ON_DEMAND
+	PeerDataOperationRequestType_PLACEHOLDER_MESSAGE_RESEND                                      = waE2E.PeerDataOperationRequestType_PLACEHOLDER_MESSAGE_RESEND
+	MediaVisibility_DEFAULT                                                                      = waHistorySync.MediaVisibility_DEFAULT
+	MediaVisibility_OFF                                                                          = waHistorySync.MediaVisibility_OFF
+	MediaVisibility_ON                                                                           = waHistorySync.MediaVisibility_ON
+	DeviceProps_UNKNOWN                                                                          = waCompanionReg.DeviceProps_UNKNOWN
+	DeviceProps_CHROME                                                                           = waCompanionReg.DeviceProps_CHROME
+	DeviceProps_FIREFOX                                                                          = waCompanionReg.DeviceProps_FIREFOX
+	DeviceProps_IE                                                                               = waCompanionReg.DeviceProps_IE
+	DeviceProps_OPERA                                                                            = waCompanionReg.DeviceProps_OPERA
+	DeviceProps_SAFARI                                                                           = waCompanionReg.DeviceProps_SAFARI
+	DeviceProps_EDGE                                                                             = waCompanionReg.DeviceProps_EDGE
+	DeviceProps_DESKTOP                                                                          = waCompanionReg.DeviceProps_DESKTOP
+	DeviceProps_IPAD                                                                             = waCompanionReg.DeviceProps_IPAD
+	DeviceProps_ANDROID_TABLET                                                                   = waCompanionReg.DeviceProps_ANDROID_TABLET
+	DeviceProps_OHANA                                                                            = waCompanionReg.DeviceProps_OHANA
+	DeviceProps_ALOHA                                                                            = waCompanionReg.DeviceProps_ALOHA
+	DeviceProps_CATALINA                                                                         = waCompanionReg.DeviceProps_CATALINA
+	DeviceProps_TCL_TV                                                                           = waCompanionReg.DeviceProps_TCL_TV
+	DeviceProps_IOS_PHONE                                                                        = waCompanionReg.DeviceProps_IOS_PHONE
+	DeviceProps_IOS_CATALYST                                                                     = waCompanionReg.DeviceProps_IOS_CATALYST
+	DeviceProps_ANDROID_PHONE                                                                    = waCompanionReg.DeviceProps_ANDROID_PHONE
+	DeviceProps_ANDROID_AMBIGUOUS                                                                = waCompanionReg.DeviceProps_ANDROID_AMBIGUOUS
+	DeviceProps_WEAR_OS                                                                          = waCompanionReg.DeviceProps_WEAR_OS
+	DeviceProps_AR_WRIST                                                                         = waCompanionReg.DeviceProps_AR_WRIST
+	DeviceProps_AR_DEVICE                                                                        = waCompanionReg.DeviceProps_AR_DEVICE
+	DeviceProps_UWP                                                                              = waCompanionReg.DeviceProps_UWP
+	DeviceProps_VR                                                                               = waCompanionReg.DeviceProps_VR
+	ImageMessage_USER_IMAGE                                                                      = waE2E.ImageMessage_USER_IMAGE
+	ImageMessage_AI_GENERATED                                                                    = waE2E.ImageMessage_AI_GENERATED
+	ImageMessage_AI_MODIFIED                                                                     = waE2E.ImageMessage_AI_MODIFIED
+	HistorySyncNotification_INITIAL_BOOTSTRAP                                                    = waE2E.HistorySyncType_INITIAL_BOOTSTRAP
+	HistorySyncNotification_INITIAL_STATUS_V3                                                    = waE2E.HistorySyncType_INITIAL_STATUS_V3
+	HistorySyncNotification_FULL                                                                 = waE2E.HistorySyncType_FULL
+	HistorySyncNotification_RECENT                                                               = waE2E.HistorySyncType_RECENT
+	HistorySyncNotification_PUSH_NAME                                                            = waE2E.HistorySyncType_PUSH_NAME
+	HistorySyncNotification_NON_BLOCKING_DATA                                                    = waE2E.HistorySyncType_NON_BLOCKING_DATA
+	HistorySyncNotification_ON_DEMAND                                                            = waE2E.HistorySyncType_ON_DEMAND
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_MONDAY      = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_MONDAY
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_TUESDAY     = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_TUESDAY
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_WEDNESDAY   = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_WEDNESDAY
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_THURSDAY    = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_THURSDAY
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_FRIDAY      = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_FRIDAY
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_SATURDAY    = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_SATURDAY
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_SUNDAY      = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_SUNDAY
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_GREGORIAN   = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_GREGORIAN
+	HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_SOLAR_HIJRI = waE2E.HighlyStructuredMessage_HSMLocalizableParameter_HSMDateTime_HSMDateTimeComponent_SOLAR_HIJRI
+	GroupInviteMessage_DEFAULT                                                                   = waE2E.GroupInviteMessage_DEFAULT
+	GroupInviteMessage_PARENT                                                                    = waE2E.GroupInviteMessage_PARENT
+	ExtendedTextMessage_NONE                                                                     = waE2E.ExtendedTextMessage_NONE
+	ExtendedTextMessage_VIDEO                                                                    = waE2E.ExtendedTextMessage_VIDEO
+	ExtendedTextMessage_PLACEHOLDER                                                              = waE2E.ExtendedTextMessage_PLACEHOLDER
+	ExtendedTextMessage_IMAGE                                                                    = waE2E.ExtendedTextMessage_IMAGE
+	ExtendedTextMessage_DEFAULT                                                                  = waE2E.ExtendedTextMessage_DEFAULT
+	ExtendedTextMessage_PARENT                                                                   = waE2E.ExtendedTextMessage_PARENT
+	ExtendedTextMessage_SUB                                                                      = waE2E.ExtendedTextMessage_SUB
+	ExtendedTextMessage_DEFAULT_SUB                                                              = waE2E.ExtendedTextMessage_DEFAULT_SUB
+	ExtendedTextMessage_SYSTEM                                                                   = waE2E.ExtendedTextMessage_SYSTEM
+	ExtendedTextMessage_SYSTEM_TEXT                                                              = waE2E.ExtendedTextMessage_SYSTEM_TEXT
+	ExtendedTextMessage_FB_SCRIPT                                                                = waE2E.ExtendedTextMessage_FB_SCRIPT
+	ExtendedTextMessage_SYSTEM_BOLD                                                              = waE2E.ExtendedTextMessage_SYSTEM_BOLD
+	ExtendedTextMessage_MORNINGBREEZE_REGULAR                                                    = waE2E.ExtendedTextMessage_MORNINGBREEZE_REGULAR
+	ExtendedTextMessage_CALISTOGA_REGULAR                                                        = waE2E.ExtendedTextMessage_CALISTOGA_REGULAR
+	ExtendedTextMessage_EXO2_EXTRABOLD                                                           = waE2E.ExtendedTextMessage_EXO2_EXTRABOLD
+	ExtendedTextMessage_COURIERPRIME_BOLD                                                        = waE2E.ExtendedTextMessage_COURIERPRIME_BOLD
+	EventResponseMessage_UNKNOWN                                                                 = waE2E.EventResponseMessage_UNKNOWN
+	EventResponseMessage_GOING                                                                   = waE2E.EventResponseMessage_GOING
+	EventResponseMessage_NOT_GOING                                                               = waE2E.EventResponseMessage_NOT_GOING
+	CallLogMessage_REGULAR                                                                       = waE2E.CallLogMessage_REGULAR
+	CallLogMessage_SCHEDULED_CALL                                                                = waE2E.CallLogMessage_SCHEDULED_CALL
+	CallLogMessage_VOICE_CHAT                                                                    = waE2E.CallLogMessage_VOICE_CHAT
+	CallLogMessage_CONNECTED                                                                     = waE2E.CallLogMessage_CONNECTED
+	CallLogMessage_MISSED                                                                        = waE2E.CallLogMessage_MISSED
+	CallLogMessage_FAILED                                                                        = waE2E.CallLogMessage_FAILED
+	CallLogMessage_REJECTED                                                                      = waE2E.CallLogMessage_REJECTED
+	CallLogMessage_ACCEPTED_ELSEWHERE                                                            = waE2E.CallLogMessage_ACCEPTED_ELSEWHERE
+	CallLogMessage_ONGOING                                                                       = waE2E.CallLogMessage_ONGOING
+	CallLogMessage_SILENCED_BY_DND                                                               = waE2E.CallLogMessage_SILENCED_BY_DND
+	CallLogMessage_SILENCED_UNKNOWN_CALLER                                                       = waE2E.CallLogMessage_SILENCED_UNKNOWN_CALLER
+	ButtonsResponseMessage_UNKNOWN                                                               = waE2E.ButtonsResponseMessage_UNKNOWN
+	ButtonsResponseMessage_DISPLAY_TEXT                                                          = waE2E.ButtonsResponseMessage_DISPLAY_TEXT
+	ButtonsMessage_UNKNOWN                                                                       = waE2E.ButtonsMessage_UNKNOWN
+	ButtonsMessage_EMPTY                                                                         = waE2E.ButtonsMessage_EMPTY
+	ButtonsMessage_TEXT                                                                          = waE2E.ButtonsMessage_TEXT
+	ButtonsMessage_DOCUMENT                                                                      = waE2E.ButtonsMessage_DOCUMENT
+	ButtonsMessage_IMAGE                                                                         = waE2E.ButtonsMessage_IMAGE
+	ButtonsMessage_VIDEO                                                                         = waE2E.ButtonsMessage_VIDEO
+	ButtonsMessage_LOCATION                                                                      = waE2E.ButtonsMessage_LOCATION
+	ButtonsMessage_Button_UNKNOWN                                                                = waE2E.ButtonsMessage_Button_UNKNOWN
+	ButtonsMessage_Button_RESPONSE                                                               = waE2E.ButtonsMessage_Button_RESPONSE
+	ButtonsMessage_Button_NATIVE_FLOW                                                            = waE2E.ButtonsMessage_Button_NATIVE_FLOW
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_POSITIVE_GENERIC                                    = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_POSITIVE_GENERIC
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_GENERIC                                    = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_GENERIC
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_HELPFUL                                    = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_HELPFUL
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_INTERESTING                                = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_INTERESTING
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_ACCURATE                                   = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_ACCURATE
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_SAFE                                       = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_SAFE
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_OTHER                                      = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_OTHER
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_REFUSED                                    = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_REFUSED
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_VISUALLY_APPEALING                     = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_VISUALLY_APPEALING
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_RELEVANT_TO_TEXT                       = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_RELEVANT_TO_TEXT
+	BotFeedbackMessage_BOT_FEEDBACK_POSITIVE                                                     = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_POSITIVE
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_GENERIC                                             = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_GENERIC
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_HELPFUL                                             = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_HELPFUL
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_INTERESTING                                         = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_INTERESTING
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_ACCURATE                                            = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_ACCURATE
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_SAFE                                                = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_SAFE
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_OTHER                                               = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_OTHER
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_REFUSED                                             = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_REFUSED
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_NOT_VISUALLY_APPEALING                              = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_NOT_VISUALLY_APPEALING
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_NOT_RELEVANT_TO_TEXT                                = waAICommon.BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_NOT_RELEVANT_TO_TEXT
+	BCallMessage_UNKNOWN                                                                         = waE2E.BCallMessage_UNKNOWN
+	BCallMessage_AUDIO                                                                           = waE2E.BCallMessage_AUDIO
+	BCallMessage_VIDEO                                                                           = waE2E.BCallMessage_VIDEO
+	HydratedTemplateButton_HydratedURLButton_FULL                                                = waE2E.HydratedTemplateButton_HydratedURLButton_FULL
+	HydratedTemplateButton_HydratedURLButton_TALL                                                = waE2E.HydratedTemplateButton_HydratedURLButton_TALL
+	HydratedTemplateButton_HydratedURLButton_COMPACT                                             = waE2E.HydratedTemplateButton_HydratedURLButton_COMPACT
+	DisappearingMode_UNKNOWN                                                                     = waE2E.DisappearingMode_UNKNOWN
+	DisappearingMode_CHAT_SETTING                                                                = waE2E.DisappearingMode_CHAT_SETTING
+	DisappearingMode_ACCOUNT_SETTING                                                             = waE2E.DisappearingMode_ACCOUNT_SETTING
+	DisappearingMode_BULK_CHANGE                                                                 = waE2E.DisappearingMode_BULK_CHANGE
+	DisappearingMode_BIZ_SUPPORTS_FB_HOSTING                                                     = waE2E.DisappearingMode_BIZ_SUPPORTS_FB_HOSTING
+	DisappearingMode_CHANGED_IN_CHAT                                                             = waE2E.DisappearingMode_CHANGED_IN_CHAT
+	DisappearingMode_INITIATED_BY_ME                                                             = waE2E.DisappearingMode_INITIATED_BY_ME
+	DisappearingMode_INITIATED_BY_OTHER                                                          = waE2E.DisappearingMode_INITIATED_BY_OTHER
+	DisappearingMode_BIZ_UPGRADE_FB_HOSTING                                                      = waE2E.DisappearingMode_BIZ_UPGRADE_FB_HOSTING
+	ContextInfo_ExternalAdReplyInfo_NONE                                                         = waE2E.ContextInfo_ExternalAdReplyInfo_NONE
+	ContextInfo_ExternalAdReplyInfo_IMAGE                                                        = waE2E.ContextInfo_ExternalAdReplyInfo_IMAGE
+	ContextInfo_ExternalAdReplyInfo_VIDEO                                                        = waE2E.ContextInfo_ExternalAdReplyInfo_VIDEO
+	ContextInfo_AdReplyInfo_NONE                                                                 = waE2E.ContextInfo_AdReplyInfo_NONE
+	ContextInfo_AdReplyInfo_IMAGE                                                                = waE2E.ContextInfo_AdReplyInfo_IMAGE
+	ContextInfo_AdReplyInfo_VIDEO                                                                = waE2E.ContextInfo_AdReplyInfo_VIDEO
+	ForwardedNewsletterMessageInfo_UPDATE                                                        = waE2E.ContextInfo_ForwardedNewsletterMessageInfo_UPDATE
+	ForwardedNewsletterMessageInfo_UPDATE_CARD                                                   = waE2E.ContextInfo_ForwardedNewsletterMessageInfo_UPDATE_CARD
+	ForwardedNewsletterMessageInfo_LINK_CARD                                                     = waE2E.ContextInfo_ForwardedNewsletterMessageInfo_LINK_CARD
+	BotPluginMetadata_BING                                                                       = waBotMetadata.BotPluginMetadata_BING
+	BotPluginMetadata_GOOGLE                                                                     = waBotMetadata.BotPluginMetadata_GOOGLE
+	BotPluginMetadata_REELS                                                                      = waBotMetadata.BotPluginMetadata_REELS
+	BotPluginMetadata_SEARCH                                                                     = waBotMetadata.BotPluginMetadata_SEARCH
+	PaymentBackground_UNKNOWN                                                                    = waE2E.PaymentBackground_UNKNOWN
+	PaymentBackground_DEFAULT                                                                    = waE2E.PaymentBackground_DEFAULT
+	VideoMessage_NONE                                                                            = waE2E.VideoMessage_NONE
+	VideoMessage_GIPHY                                                                           = waE2E.VideoMessage_GIPHY
+	VideoMessage_TENOR                                                                           = waE2E.VideoMessage_TENOR
+	SecretEncryptedMessage_UNKNOWN                                                               = waE2E.SecretEncryptedMessage_UNKNOWN
+	SecretEncryptedMessage_EVENT_EDIT                                                            = waE2E.SecretEncryptedMessage_EVENT_EDIT
+	ScheduledCallEditMessage_UNKNOWN                                                             = waE2E.ScheduledCallEditMessage_UNKNOWN
+	ScheduledCallEditMessage_CANCEL                                                              = waE2E.ScheduledCallEditMessage_CANCEL
+	ScheduledCallCreationMessage_UNKNOWN                                                         = waE2E.ScheduledCallCreationMessage_UNKNOWN
+	ScheduledCallCreationMessage_VOICE                                                           = waE2E.ScheduledCallCreationMessage_VOICE
+	ScheduledCallCreationMessage_VIDEO                                                           = waE2E.ScheduledCallCreationMessage_VIDEO
+	RequestWelcomeMessageMetadata_EMPTY                                                          = waE2E.RequestWelcomeMessageMetadata_EMPTY
+	RequestWelcomeMessageMetadata_NON_EMPTY                                                      = waE2E.RequestWelcomeMessageMetadata_NON_EMPTY
+	ProtocolMessage_REVOKE                                                                       = waE2E.ProtocolMessage_REVOKE
+	ProtocolMessage_EPHEMERAL_SETTING                                                            = waE2E.ProtocolMessage_EPHEMERAL_SETTING
+	ProtocolMessage_EPHEMERAL_SYNC_RESPONSE                                                      = waE2E.ProtocolMessage_EPHEMERAL_SYNC_RESPONSE
+	ProtocolMessage_HISTORY_SYNC_NOTIFICATION                                                    = waE2E.ProtocolMessage_HISTORY_SYNC_NOTIFICATION
+	ProtocolMessage_APP_STATE_SYNC_KEY_SHARE                                                     = waE2E.ProtocolMessage_APP_STATE_SYNC_KEY_SHARE
+	ProtocolMessage_APP_STATE_SYNC_KEY_REQUEST                                                   = waE2E.ProtocolMessage_APP_STATE_SYNC_KEY_REQUEST
+	ProtocolMessage_MSG_FANOUT_BACKFILL_REQUEST                                                  = waE2E.ProtocolMessage_MSG_FANOUT_BACKFILL_REQUEST
+	ProtocolMessage_INITIAL_SECURITY_NOTIFICATION_SETTING_SYNC                                   = waE2E.ProtocolMessage_INITIAL_SECURITY_NOTIFICATION_SETTING_SYNC
+	ProtocolMessage_APP_STATE_FATAL_EXCEPTION_NOTIFICATION                                       = waE2E.ProtocolMessage_APP_STATE_FATAL_EXCEPTION_NOTIFICATION
+	ProtocolMessage_SHARE_PHONE_NUMBER                                                           = waE2E.ProtocolMessage_SHARE_PHONE_NUMBER
+	ProtocolMessage_MESSAGE_EDIT                                                                 = waE2E.ProtocolMessage_MESSAGE_EDIT
+	ProtocolMessage_PEER_DATA_OPERATION_REQUEST_MESSAGE                                          = waE2E.ProtocolMessage_PEER_DATA_OPERATION_REQUEST_MESSAGE
+	ProtocolMessage_PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE                                 = waE2E.ProtocolMessage_PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE
+	ProtocolMessage_REQUEST_WELCOME_MESSAGE                                                      = waE2E.ProtocolMessage_REQUEST_WELCOME_MESSAGE
+	ProtocolMessage_BOT_FEEDBACK_MESSAGE                                                         = waE2E.ProtocolMessage_BOT_FEEDBACK_MESSAGE
+	ProtocolMessage_MEDIA_NOTIFY_MESSAGE                                                         = waE2E.ProtocolMessage_MEDIA_NOTIFY_MESSAGE
+	PlaceholderMessage_MASK_LINKED_DEVICES                                                       = waE2E.PlaceholderMessage_MASK_LINKED_DEVICES
+	PinInChatMessage_UNKNOWN_TYPE                                                                = waE2E.PinInChatMessage_UNKNOWN_TYPE
+	PinInChatMessage_PIN_FOR_ALL                                                                 = waE2E.PinInChatMessage_PIN_FOR_ALL
+	PinInChatMessage_UNPIN_FOR_ALL                                                               = waE2E.PinInChatMessage_UNPIN_FOR_ALL
+	PaymentInviteMessage_UNKNOWN                                                                 = waE2E.PaymentInviteMessage_UNKNOWN
+	PaymentInviteMessage_FBPAY                                                                   = waE2E.PaymentInviteMessage_FBPAY
+	PaymentInviteMessage_NOVI                                                                    = waE2E.PaymentInviteMessage_NOVI
+	PaymentInviteMessage_UPI                                                                     = waE2E.PaymentInviteMessage_UPI
+	OrderMessage_CATALOG                                                                         = waE2E.OrderMessage_CATALOG
+	OrderMessage_INQUIRY                                                                         = waE2E.OrderMessage_INQUIRY
+	OrderMessage_ACCEPTED                                                                        = waE2E.OrderMessage_ACCEPTED
+	OrderMessage_DECLINED                                                                        = waE2E.OrderMessage_DECLINED
+	ListResponseMessage_UNKNOWN                                                                  = waE2E.ListResponseMessage_UNKNOWN
+	ListResponseMessage_SINGLE_SELECT                                                            = waE2E.ListResponseMessage_SINGLE_SELECT
+	ListMessage_UNKNOWN                                                                          = waE2E.ListMessage_UNKNOWN
+	ListMessage_SINGLE_SELECT                                                                    = waE2E.ListMessage_SINGLE_SELECT
+	ListMessage_PRODUCT_LIST                                                                     = waE2E.ListMessage_PRODUCT_LIST
+	InvoiceMessage_IMAGE                                                                         = waE2E.InvoiceMessage_IMAGE
+	InvoiceMessage_PDF                                                                           = waE2E.InvoiceMessage_PDF
+	InteractiveResponseMessage_Body_DEFAULT                                                      = waE2E.InteractiveResponseMessage_Body_DEFAULT
+	InteractiveResponseMessage_Body_EXTENSIONS_1                                                 = waE2E.InteractiveResponseMessage_Body_EXTENSIONS_1
+	InteractiveMessage_ShopMessage_UNKNOWN_SURFACE                                               = waE2E.InteractiveMessage_ShopMessage_UNKNOWN_SURFACE
+	InteractiveMessage_ShopMessage_FB                                                            = waE2E.InteractiveMessage_ShopMessage_FB
+	InteractiveMessage_ShopMessage_IG                                                            = waE2E.InteractiveMessage_ShopMessage_IG
+	InteractiveMessage_ShopMessage_WA                                                            = waE2E.InteractiveMessage_ShopMessage_WA
+	PastParticipant_LEFT                                                                         = waHistorySync.PastParticipant_LEFT
+	PastParticipant_REMOVED                                                                      = waHistorySync.PastParticipant_REMOVED
+	HistorySync_INITIAL_BOOTSTRAP                                                                = waHistorySync.HistorySync_INITIAL_BOOTSTRAP
+	HistorySync_INITIAL_STATUS_V3                                                                = waHistorySync.HistorySync_INITIAL_STATUS_V3
+	HistorySync_FULL                                                                             = waHistorySync.HistorySync_FULL
+	HistorySync_RECENT                                                                           = waHistorySync.HistorySync_RECENT
+	HistorySync_PUSH_NAME                                                                        = waHistorySync.HistorySync_PUSH_NAME
+	HistorySync_NON_BLOCKING_DATA                                                                = waHistorySync.HistorySync_NON_BLOCKING_DATA
+	HistorySync_ON_DEMAND                                                                        = waHistorySync.HistorySync_ON_DEMAND
+	HistorySync_IN_WAITLIST                                                                      = waHistorySync.HistorySync_IN_WAITLIST
+	HistorySync_AI_AVAILABLE                                                                     = waHistorySync.HistorySync_AI_AVAILABLE
+	GroupParticipant_REGULAR                                                                     = waHistorySync.GroupParticipant_REGULAR
+	GroupParticipant_ADMIN                                                                       = waHistorySync.GroupParticipant_ADMIN
+	GroupParticipant_SUPERADMIN                                                                  = waHistorySync.GroupParticipant_SUPERADMIN
+	Conversation_COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY                                    = waHistorySync.Conversation_COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY
+	Conversation_COMPLETE_AND_NO_MORE_MESSAGE_REMAIN_ON_PRIMARY                                  = waHistorySync.Conversation_COMPLETE_AND_NO_MORE_MESSAGE_REMAIN_ON_PRIMARY
+	Conversation_COMPLETE_ON_DEMAND_SYNC_BUT_MORE_MSG_REMAIN_ON_PRIMARY                          = waHistorySync.Conversation_COMPLETE_ON_DEMAND_SYNC_BUT_MORE_MSG_REMAIN_ON_PRIMARY
+	MediaRetryNotification_GENERAL_ERROR                                                         = waMmsRetry.MediaRetryNotification_GENERAL_ERROR
+	MediaRetryNotification_SUCCESS                                                               = waMmsRetry.MediaRetryNotification_SUCCESS
+	MediaRetryNotification_NOT_FOUND                                                             = waMmsRetry.MediaRetryNotification_NOT_FOUND
+	MediaRetryNotification_DECRYPTION_ERROR                                                      = waMmsRetry.MediaRetryNotification_DECRYPTION_ERROR
+	SyncdMutation_SET                                                                            = waServerSync.SyncdMutation_SET
+	SyncdMutation_REMOVE                                                                         = waServerSync.SyncdMutation_REMOVE
+	StatusPrivacyAction_ALLOW_LIST                                                               = waSyncAction.StatusPrivacyAction_ALLOW_LIST
+	StatusPrivacyAction_DENY_LIST                                                                = waSyncAction.StatusPrivacyAction_DENY_LIST
+	StatusPrivacyAction_CONTACTS                                                                 = waSyncAction.StatusPrivacyAction_CONTACTS
+	MarketingMessageAction_PERSONALIZED                                                          = waSyncAction.MarketingMessageAction_PERSONALIZED
+	PatchDebugData_ANDROID                                                                       = waSyncAction.PatchDebugData_ANDROID
+	PatchDebugData_SMBA                                                                          = waSyncAction.PatchDebugData_SMBA
+	PatchDebugData_IPHONE                                                                        = waSyncAction.PatchDebugData_IPHONE
+	PatchDebugData_SMBI                                                                          = waSyncAction.PatchDebugData_SMBI
+	PatchDebugData_WEB                                                                           = waSyncAction.PatchDebugData_WEB
+	PatchDebugData_UWP                                                                           = waSyncAction.PatchDebugData_UWP
+	PatchDebugData_DARWIN                                                                        = waSyncAction.PatchDebugData_DARWIN
+	CallLogRecord_NONE                                                                           = waSyncAction.CallLogRecord_NONE
+	CallLogRecord_SCHEDULED                                                                      = waSyncAction.CallLogRecord_SCHEDULED
+	CallLogRecord_PRIVACY                                                                        = waSyncAction.CallLogRecord_PRIVACY
+	CallLogRecord_LIGHTWEIGHT                                                                    = waSyncAction.CallLogRecord_LIGHTWEIGHT
+	CallLogRecord_REGULAR                                                                        = waSyncAction.CallLogRecord_REGULAR
+	CallLogRecord_SCHEDULED_CALL                                                                 = waSyncAction.CallLogRecord_SCHEDULED_CALL
+	CallLogRecord_VOICE_CHAT                                                                     = waSyncAction.CallLogRecord_VOICE_CHAT
+	CallLogRecord_CONNECTED                                                                      = waSyncAction.CallLogRecord_CONNECTED
+	CallLogRecord_REJECTED                                                                       = waSyncAction.CallLogRecord_REJECTED
+	CallLogRecord_CANCELLED                                                                      = waSyncAction.CallLogRecord_CANCELLED
+	CallLogRecord_ACCEPTEDELSEWHERE                                                              = waSyncAction.CallLogRecord_ACCEPTEDELSEWHERE
+	CallLogRecord_MISSED                                                                         = waSyncAction.CallLogRecord_MISSED
+	CallLogRecord_INVALID                                                                        = waSyncAction.CallLogRecord_INVALID
+	CallLogRecord_UNAVAILABLE                                                                    = waSyncAction.CallLogRecord_UNAVAILABLE
+	CallLogRecord_UPCOMING                                                                       = waSyncAction.CallLogRecord_UPCOMING
+	CallLogRecord_FAILED                                                                         = waSyncAction.CallLogRecord_FAILED
+	CallLogRecord_ABANDONED                                                                      = waSyncAction.CallLogRecord_ABANDONED
+	CallLogRecord_ONGOING                                                                        = waSyncAction.CallLogRecord_ONGOING
+	BizIdentityInfo_UNKNOWN                                                                      = waVnameCert.BizIdentityInfo_UNKNOWN
+	BizIdentityInfo_LOW                                                                          = waVnameCert.BizIdentityInfo_LOW
+	BizIdentityInfo_HIGH                                                                         = waVnameCert.BizIdentityInfo_HIGH
+	BizIdentityInfo_ON_PREMISE                                                                   = waVnameCert.BizIdentityInfo_ON_PREMISE
+	BizIdentityInfo_FACEBOOK                                                                     = waVnameCert.BizIdentityInfo_FACEBOOK
+	BizIdentityInfo_SELF                                                                         = waVnameCert.BizIdentityInfo_SELF
+	BizIdentityInfo_BSP                                                                          = waVnameCert.BizIdentityInfo_BSP
+	BizAccountLinkInfo_ON_PREMISE                                                                = waVnameCert.BizAccountLinkInfo_ON_PREMISE
+	BizAccountLinkInfo_FACEBOOK                                                                  = waVnameCert.BizAccountLinkInfo_FACEBOOK
+	BizAccountLinkInfo_ENTERPRISE                                                                = waVnameCert.BizAccountLinkInfo_ENTERPRISE
+	ClientPayload_WHATSAPP                                                                       = waWa6.ClientPayload_WHATSAPP
+	ClientPayload_MESSENGER                                                                      = waWa6.ClientPayload_MESSENGER
+	ClientPayload_INTEROP                                                                        = waWa6.ClientPayload_INTEROP
+	ClientPayload_INTEROP_MSGR                                                                   = waWa6.ClientPayload_INTEROP_MSGR
+	ClientPayload_SHARE_EXTENSION                                                                = waWa6.ClientPayload_SHARE_EXTENSION
+	ClientPayload_SERVICE_EXTENSION                                                              = waWa6.ClientPayload_SERVICE_EXTENSION
+	ClientPayload_INTENTS_EXTENSION                                                              = waWa6.ClientPayload_INTENTS_EXTENSION
+	ClientPayload_CELLULAR_UNKNOWN                                                               = waWa6.ClientPayload_CELLULAR_UNKNOWN
+	ClientPayload_WIFI_UNKNOWN                                                                   = waWa6.ClientPayload_WIFI_UNKNOWN
+	ClientPayload_CELLULAR_EDGE                                                                  = waWa6.ClientPayload_CELLULAR_EDGE
+	ClientPayload_CELLULAR_IDEN                                                                  = waWa6.ClientPayload_CELLULAR_IDEN
+	ClientPayload_CELLULAR_UMTS                                                                  = waWa6.ClientPayload_CELLULAR_UMTS
+	ClientPayload_CELLULAR_EVDO                                                                  = waWa6.ClientPayload_CELLULAR_EVDO
+	ClientPayload_CELLULAR_GPRS                                                                  = waWa6.ClientPayload_CELLULAR_GPRS
+	ClientPayload_CELLULAR_HSDPA                                                                 = waWa6.ClientPayload_CELLULAR_HSDPA
+	ClientPayload_CELLULAR_HSUPA                                                                 = waWa6.ClientPayload_CELLULAR_HSUPA
+	ClientPayload_CELLULAR_HSPA                                                                  = waWa6.ClientPayload_CELLULAR_HSPA
+	ClientPayload_CELLULAR_CDMA                                                                  = waWa6.ClientPayload_CELLULAR_CDMA
+	ClientPayload_CELLULAR_1XRTT                                                                 = waWa6.ClientPayload_CELLULAR_1XRTT
+	ClientPayload_CELLULAR_EHRPD                                                                 = waWa6.ClientPayload_CELLULAR_EHRPD
+	ClientPayload_CELLULAR_LTE                                                                   = waWa6.ClientPayload_CELLULAR_LTE
+	ClientPayload_CELLULAR_HSPAP                                                                 = waWa6.ClientPayload_CELLULAR_HSPAP
+	ClientPayload_PUSH                                                                           = waWa6.ClientPayload_PUSH
+	ClientPayload_USER_ACTIVATED                                                                 = waWa6.ClientPayload_USER_ACTIVATED
+	ClientPayload_SCHEDULED                                                                      = waWa6.ClientPayload_SCHEDULED
+	ClientPayload_ERROR_RECONNECT                                                                = waWa6.ClientPayload_ERROR_RECONNECT
+	ClientPayload_NETWORK_SWITCH                                                                 = waWa6.ClientPayload_NETWORK_SWITCH
+	ClientPayload_PING_RECONNECT                                                                 = waWa6.ClientPayload_PING_RECONNECT
+	ClientPayload_UNKNOWN                                                                        = waWa6.ClientPayload_UNKNOWN
+	ClientPayload_WebInfo_WEB_BROWSER                                                            = waWa6.ClientPayload_WebInfo_WEB_BROWSER
+	ClientPayload_WebInfo_APP_STORE                                                              = waWa6.ClientPayload_WebInfo_APP_STORE
+	ClientPayload_WebInfo_WIN_STORE                                                              = waWa6.ClientPayload_WebInfo_WIN_STORE
+	ClientPayload_WebInfo_DARWIN                                                                 = waWa6.ClientPayload_WebInfo_DARWIN
+	ClientPayload_WebInfo_WIN32                                                                  = waWa6.ClientPayload_WebInfo_WIN32
+	ClientPayload_UserAgent_RELEASE                                                              = waWa6.ClientPayload_UserAgent_RELEASE
+	ClientPayload_UserAgent_BETA                                                                 = waWa6.ClientPayload_UserAgent_BETA
+	ClientPayload_UserAgent_ALPHA                                                                = waWa6.ClientPayload_UserAgent_ALPHA
+	ClientPayload_UserAgent_DEBUG                                                                = waWa6.ClientPayload_UserAgent_DEBUG
+	ClientPayload_UserAgent_ANDROID                                                              = waWa6.ClientPayload_UserAgent_ANDROID
+	ClientPayload_UserAgent_IOS                                                                  = waWa6.ClientPayload_UserAgent_IOS
+	ClientPayload_UserAgent_WINDOWS_PHONE                                                        = waWa6.ClientPayload_UserAgent_WINDOWS_PHONE
+	ClientPayload_UserAgent_BLACKBERRY                                                           = waWa6.ClientPayload_UserAgent_BLACKBERRY
+	ClientPayload_UserAgent_BLACKBERRYX                                                          = waWa6.ClientPayload_UserAgent_BLACKBERRYX
+	ClientPayload_UserAgent_S40                                                                  = waWa6.ClientPayload_UserAgent_S40
+	ClientPayload_UserAgent_S60                                                                  = waWa6.ClientPayload_UserAgent_S60
+	ClientPayload_UserAgent_PYTHON_CLIENT                                                        = waWa6.ClientPayload_UserAgent_PYTHON_CLIENT
+	ClientPayload_UserAgent_TIZEN                                                                = waWa6.ClientPayload_UserAgent_TIZEN
+	ClientPayload_UserAgent_ENTERPRISE                                                           = waWa6.ClientPayload_UserAgent_ENTERPRISE
+	ClientPayload_UserAgent_SMB_ANDROID                                                          = waWa6.ClientPayload_UserAgent_SMB_ANDROID
+	ClientPayload_UserAgent_KAIOS                                                                = waWa6.ClientPayload_UserAgent_KAIOS
+	ClientPayload_UserAgent_SMB_IOS                                                              = waWa6.ClientPayload_UserAgent_SMB_IOS
+	ClientPayload_UserAgent_WINDOWS                                                              = waWa6.ClientPayload_UserAgent_WINDOWS
+	ClientPayload_UserAgent_WEB                                                                  = waWa6.ClientPayload_UserAgent_WEB
+	ClientPayload_UserAgent_PORTAL                                                               = waWa6.ClientPayload_UserAgent_PORTAL
+	ClientPayload_UserAgent_GREEN_ANDROID                                                        = waWa6.ClientPayload_UserAgent_GREEN_ANDROID
+	ClientPayload_UserAgent_GREEN_IPHONE                                                         = waWa6.ClientPayload_UserAgent_GREEN_IPHONE
+	ClientPayload_UserAgent_BLUE_ANDROID                                                         = waWa6.ClientPayload_UserAgent_BLUE_ANDROID
+	ClientPayload_UserAgent_BLUE_IPHONE                                                          = waWa6.ClientPayload_UserAgent_BLUE_IPHONE
+	ClientPayload_UserAgent_FBLITE_ANDROID                                                       = waWa6.ClientPayload_UserAgent_FBLITE_ANDROID
+	ClientPayload_UserAgent_MLITE_ANDROID                                                        = waWa6.ClientPayload_UserAgent_MLITE_ANDROID
+	ClientPayload_UserAgent_IGLITE_ANDROID                                                       = waWa6.ClientPayload_UserAgent_IGLITE_ANDROID
+	ClientPayload_UserAgent_PAGE                                                                 = waWa6.ClientPayload_UserAgent_PAGE
+	ClientPayload_UserAgent_MACOS                                                                = waWa6.ClientPayload_UserAgent_MACOS
+	ClientPayload_UserAgent_OCULUS_MSG                                                           = waWa6.ClientPayload_UserAgent_OCULUS_MSG
+	ClientPayload_UserAgent_OCULUS_CALL                                                          = waWa6.ClientPayload_UserAgent_OCULUS_CALL
+	ClientPayload_UserAgent_MILAN                                                                = waWa6.ClientPayload_UserAgent_MILAN
+	ClientPayload_UserAgent_CAPI                                                                 = waWa6.ClientPayload_UserAgent_CAPI
+	ClientPayload_UserAgent_WEAROS                                                               = waWa6.ClientPayload_UserAgent_WEAROS
+	ClientPayload_UserAgent_ARDEVICE                                                             = waWa6.ClientPayload_UserAgent_ARDEVICE
+	ClientPayload_UserAgent_VRDEVICE                                                             = waWa6.ClientPayload_UserAgent_VRDEVICE
+	ClientPayload_UserAgent_BLUE_WEB                                                             = waWa6.ClientPayload_UserAgent_BLUE_WEB
+	ClientPayload_UserAgent_IPAD                                                                 = waWa6.ClientPayload_UserAgent_IPAD
+	ClientPayload_UserAgent_TEST                                                                 = waWa6.ClientPayload_UserAgent_TEST
+	ClientPayload_UserAgent_SMART_GLASSES                                                        = waWa6.ClientPayload_UserAgent_SMART_GLASSES
+	ClientPayload_UserAgent_PHONE                                                                = waWa6.ClientPayload_UserAgent_PHONE
+	ClientPayload_UserAgent_TABLET                                                               = waWa6.ClientPayload_UserAgent_TABLET
+	ClientPayload_UserAgent_DESKTOP                                                              = waWa6.ClientPayload_UserAgent_DESKTOP
+	ClientPayload_UserAgent_WEARABLE                                                             = waWa6.ClientPayload_UserAgent_WEARABLE
+	ClientPayload_UserAgent_VR                                                                   = waWa6.ClientPayload_UserAgent_VR
+	ClientPayload_DNSSource_SYSTEM                                                               = waWa6.ClientPayload_DNSSource_SYSTEM
+	ClientPayload_DNSSource_GOOGLE                                                               = waWa6.ClientPayload_DNSSource_GOOGLE
+	ClientPayload_DNSSource_HARDCODED                                                            = waWa6.ClientPayload_DNSSource_HARDCODED
+	ClientPayload_DNSSource_OVERRIDE                                                             = waWa6.ClientPayload_DNSSource_OVERRIDE
+	ClientPayload_DNSSource_FALLBACK                                                             = waWa6.ClientPayload_DNSSource_FALLBACK
+	WebMessageInfo_UNKNOWN                                                                       = waWeb.WebMessageInfo_UNKNOWN
+	WebMessageInfo_REVOKE                                                                        = waWeb.WebMessageInfo_REVOKE
+	WebMessageInfo_CIPHERTEXT                                                                    = waWeb.WebMessageInfo_CIPHERTEXT
+	WebMessageInfo_FUTUREPROOF                                                                   = waWeb.WebMessageInfo_FUTUREPROOF
+	WebMessageInfo_NON_VERIFIED_TRANSITION                                                       = waWeb.WebMessageInfo_NON_VERIFIED_TRANSITION
+	WebMessageInfo_UNVERIFIED_TRANSITION                                                         = waWeb.WebMessageInfo_UNVERIFIED_TRANSITION
+	WebMessageInfo_VERIFIED_TRANSITION                                                           = waWeb.WebMessageInfo_VERIFIED_TRANSITION
+	WebMessageInfo_VERIFIED_LOW_UNKNOWN                                                          = waWeb.WebMessageInfo_VERIFIED_LOW_UNKNOWN
+	WebMessageInfo_VERIFIED_HIGH                                                                 = waWeb.WebMessageInfo_VERIFIED_HIGH
+	WebMessageInfo_VERIFIED_INITIAL_UNKNOWN                                                      = waWeb.WebMessageInfo_VERIFIED_INITIAL_UNKNOWN
+	WebMessageInfo_VERIFIED_INITIAL_LOW                                                          = waWeb.WebMessageInfo_VERIFIED_INITIAL_LOW
+	WebMessageInfo_VERIFIED_INITIAL_HIGH                                                         = waWeb.WebMessageInfo_VERIFIED_INITIAL_HIGH
+	WebMessageInfo_VERIFIED_TRANSITION_ANY_TO_NONE                                               = waWeb.WebMessageInfo_VERIFIED_TRANSITION_ANY_TO_NONE
+	WebMessageInfo_VERIFIED_TRANSITION_ANY_TO_HIGH                                               = waWeb.WebMessageInfo_VERIFIED_TRANSITION_ANY_TO_HIGH
+	WebMessageInfo_VERIFIED_TRANSITION_HIGH_TO_LOW                                               = waWeb.WebMessageInfo_VERIFIED_TRANSITION_HIGH_TO_LOW
+	WebMessageInfo_VERIFIED_TRANSITION_HIGH_TO_UNKNOWN                                           = waWeb.WebMessageInfo_VERIFIED_TRANSITION_HIGH_TO_UNKNOWN
+	WebMessageInfo_VERIFIED_TRANSITION_UNKNOWN_TO_LOW                                            = waWeb.WebMessageInfo_VERIFIED_TRANSITION_UNKNOWN_TO_LOW
+	WebMessageInfo_VERIFIED_TRANSITION_LOW_TO_UNKNOWN                                            = waWeb.WebMessageInfo_VERIFIED_TRANSITION_LOW_TO_UNKNOWN
+	WebMessageInfo_VERIFIED_TRANSITION_NONE_TO_LOW                                               = waWeb.WebMessageInfo_VERIFIED_TRANSITION_NONE_TO_LOW
+	WebMessageInfo_VERIFIED_TRANSITION_NONE_TO_UNKNOWN                                           = waWeb.WebMessageInfo_VERIFIED_TRANSITION_NONE_TO_UNKNOWN
+	WebMessageInfo_GROUP_CREATE                                                                  = waWeb.WebMessageInfo_GROUP_CREATE
+	WebMessageInfo_GROUP_CHANGE_SUBJECT                                                          = waWeb.WebMessageInfo_GROUP_CHANGE_SUBJECT
+	WebMessageInfo_GROUP_CHANGE_ICON                                                             = waWeb.WebMessageInfo_GROUP_CHANGE_ICON
+	WebMessageInfo_GROUP_CHANGE_INVITE_LINK                                                      = waWeb.WebMessageInfo_GROUP_CHANGE_INVITE_LINK
+	WebMessageInfo_GROUP_CHANGE_DESCRIPTION                                                      = waWeb.WebMessageInfo_GROUP_CHANGE_DESCRIPTION
+	WebMessageInfo_GROUP_CHANGE_RESTRICT                                                         = waWeb.WebMessageInfo_GROUP_CHANGE_RESTRICT
+	WebMessageInfo_GROUP_CHANGE_ANNOUNCE                                                         = waWeb.WebMessageInfo_GROUP_CHANGE_ANNOUNCE
+	WebMessageInfo_GROUP_PARTICIPANT_ADD                                                         = waWeb.WebMessageInfo_GROUP_PARTICIPANT_ADD
+	WebMessageInfo_GROUP_PARTICIPANT_REMOVE                                                      = waWeb.WebMessageInfo_GROUP_PARTICIPANT_REMOVE
+	WebMessageInfo_GROUP_PARTICIPANT_PROMOTE                                                     = waWeb.WebMessageInfo_GROUP_PARTICIPANT_PROMOTE
+	WebMessageInfo_GROUP_PARTICIPANT_DEMOTE                                                      = waWeb.WebMessageInfo_GROUP_PARTICIPANT_DEMOTE
+	WebMessageInfo_GROUP_PARTICIPANT_INVITE                                                      = waWeb.WebMessageInfo_GROUP_PARTICIPANT_INVITE
+	WebMessageInfo_GROUP_PARTICIPANT_LEAVE                                                       = waWeb.WebMessageInfo_GROUP_PARTICIPANT_LEAVE
+	WebMessageInfo_GROUP_PARTICIPANT_CHANGE_NUMBER                                               = waWeb.WebMessageInfo_GROUP_PARTICIPANT_CHANGE_NUMBER
+	WebMessageInfo_BROADCAST_CREATE                                                              = waWeb.WebMessageInfo_BROADCAST_CREATE
+	WebMessageInfo_BROADCAST_ADD                                                                 = waWeb.WebMessageInfo_BROADCAST_ADD
+	WebMessageInfo_BROADCAST_REMOVE                                                              = waWeb.WebMessageInfo_BROADCAST_REMOVE
+	WebMessageInfo_GENERIC_NOTIFICATION                                                          = waWeb.WebMessageInfo_GENERIC_NOTIFICATION
+	WebMessageInfo_E2E_IDENTITY_CHANGED                                                          = waWeb.WebMessageInfo_E2E_IDENTITY_CHANGED
+	WebMessageInfo_E2E_ENCRYPTED                                                                 = waWeb.WebMessageInfo_E2E_ENCRYPTED
+	WebMessageInfo_CALL_MISSED_VOICE                                                             = waWeb.WebMessageInfo_CALL_MISSED_VOICE
+	WebMessageInfo_CALL_MISSED_VIDEO                                                             = waWeb.WebMessageInfo_CALL_MISSED_VIDEO
+	WebMessageInfo_INDIVIDUAL_CHANGE_NUMBER                                                      = waWeb.WebMessageInfo_INDIVIDUAL_CHANGE_NUMBER
+	WebMessageInfo_GROUP_DELETE                                                                  = waWeb.WebMessageInfo_GROUP_DELETE
+	WebMessageInfo_GROUP_ANNOUNCE_MODE_MESSAGE_BOUNCE                                            = waWeb.WebMessageInfo_GROUP_ANNOUNCE_MODE_MESSAGE_BOUNCE
+	WebMessageInfo_CALL_MISSED_GROUP_VOICE                                                       = waWeb.WebMessageInfo_CALL_MISSED_GROUP_VOICE
+	WebMessageInfo_CALL_MISSED_GROUP_VIDEO                                                       = waWeb.WebMessageInfo_CALL_MISSED_GROUP_VIDEO
+	WebMessageInfo_PAYMENT_CIPHERTEXT                                                            = waWeb.WebMessageInfo_PAYMENT_CIPHERTEXT
+	WebMessageInfo_PAYMENT_FUTUREPROOF                                                           = waWeb.WebMessageInfo_PAYMENT_FUTUREPROOF
+	WebMessageInfo_PAYMENT_TRANSACTION_STATUS_UPDATE_FAILED                                      = waWeb.WebMessageInfo_PAYMENT_TRANSACTION_STATUS_UPDATE_FAILED
+	WebMessageInfo_PAYMENT_TRANSACTION_STATUS_UPDATE_REFUNDED                                    = waWeb.WebMessageInfo_PAYMENT_TRANSACTION_STATUS_UPDATE_REFUNDED
+	WebMessageInfo_PAYMENT_TRANSACTION_STATUS_UPDATE_REFUND_FAILED                               = waWeb.WebMessageInfo_PAYMENT_TRANSACTION_STATUS_UPDATE_REFUND_FAILED
+	WebMessageInfo_PAYMENT_TRANSACTION_STATUS_RECEIVER_PENDING_SETUP                             = waWeb.WebMessageInfo_PAYMENT_TRANSACTION_STATUS_RECEIVER_PENDING_SETUP
+	WebMessageInfo_PAYMENT_TRANSACTION_STATUS_RECEIVER_SUCCESS_AFTER_HICCUP                      = waWeb.WebMessageInfo_PAYMENT_TRANSACTION_STATUS_RECEIVER_SUCCESS_AFTER_HICCUP
+	WebMessageInfo_PAYMENT_ACTION_ACCOUNT_SETUP_REMINDER                                         = waWeb.WebMessageInfo_PAYMENT_ACTION_ACCOUNT_SETUP_REMINDER
+	WebMessageInfo_PAYMENT_ACTION_SEND_PAYMENT_REMINDER                                          = waWeb.WebMessageInfo_PAYMENT_ACTION_SEND_PAYMENT_REMINDER
+	WebMessageInfo_PAYMENT_ACTION_SEND_PAYMENT_INVITATION                                        = waWeb.WebMessageInfo_PAYMENT_ACTION_SEND_PAYMENT_INVITATION
+	WebMessageInfo_PAYMENT_ACTION_REQUEST_DECLINED                                               = waWeb.WebMessageInfo_PAYMENT_ACTION_REQUEST_DECLINED
+	WebMessageInfo_PAYMENT_ACTION_REQUEST_EXPIRED                                                = waWeb.WebMessageInfo_PAYMENT_ACTION_REQUEST_EXPIRED
+	WebMessageInfo_PAYMENT_ACTION_REQUEST_CANCELLED                                              = waWeb.WebMessageInfo_PAYMENT_ACTION_REQUEST_CANCELLED
+	WebMessageInfo_BIZ_VERIFIED_TRANSITION_TOP_TO_BOTTOM                                         = waWeb.WebMessageInfo_BIZ_VERIFIED_TRANSITION_TOP_TO_BOTTOM
+	WebMessageInfo_BIZ_VERIFIED_TRANSITION_BOTTOM_TO_TOP                                         = waWeb.WebMessageInfo_BIZ_VERIFIED_TRANSITION_BOTTOM_TO_TOP
+	WebMessageInfo_BIZ_INTRO_TOP                                                                 = waWeb.WebMessageInfo_BIZ_INTRO_TOP
+	WebMessageInfo_BIZ_INTRO_BOTTOM                                                              = waWeb.WebMessageInfo_BIZ_INTRO_BOTTOM
+	WebMessageInfo_BIZ_NAME_CHANGE                                                               = waWeb.WebMessageInfo_BIZ_NAME_CHANGE
+	WebMessageInfo_BIZ_MOVE_TO_CONSUMER_APP                                                      = waWeb.WebMessageInfo_BIZ_MOVE_TO_CONSUMER_APP
+	WebMessageInfo_BIZ_TWO_TIER_MIGRATION_TOP                                                    = waWeb.WebMessageInfo_BIZ_TWO_TIER_MIGRATION_TOP
+	WebMessageInfo_BIZ_TWO_TIER_MIGRATION_BOTTOM                                                 = waWeb.WebMessageInfo_BIZ_TWO_TIER_MIGRATION_BOTTOM
+	WebMessageInfo_OVERSIZED                                                                     = waWeb.WebMessageInfo_OVERSIZED
+	WebMessageInfo_GROUP_CHANGE_NO_FREQUENTLY_FORWARDED                                          = waWeb.WebMessageInfo_GROUP_CHANGE_NO_FREQUENTLY_FORWARDED
+	WebMessageInfo_GROUP_V4_ADD_INVITE_SENT                                                      = waWeb.WebMessageInfo_GROUP_V4_ADD_INVITE_SENT
+	WebMessageInfo_GROUP_PARTICIPANT_ADD_REQUEST_JOIN                                            = waWeb.WebMessageInfo_GROUP_PARTICIPANT_ADD_REQUEST_JOIN
+	WebMessageInfo_CHANGE_EPHEMERAL_SETTING                                                      = waWeb.WebMessageInfo_CHANGE_EPHEMERAL_SETTING
+	WebMessageInfo_E2E_DEVICE_CHANGED                                                            = waWeb.WebMessageInfo_E2E_DEVICE_CHANGED
+	WebMessageInfo_VIEWED_ONCE                                                                   = waWeb.WebMessageInfo_VIEWED_ONCE
+	WebMessageInfo_E2E_ENCRYPTED_NOW                                                             = waWeb.WebMessageInfo_E2E_ENCRYPTED_NOW
+	WebMessageInfo_BLUE_MSG_BSP_FB_TO_BSP_PREMISE                                                = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_TO_BSP_PREMISE
+	WebMessageInfo_BLUE_MSG_BSP_FB_TO_SELF_FB                                                    = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_TO_SELF_FB
+	WebMessageInfo_BLUE_MSG_BSP_FB_TO_SELF_PREMISE                                               = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_TO_SELF_PREMISE
+	WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED                                                    = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED_TO_SELF_PREMISE_VERIFIED                           = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED_TO_SELF_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED                                                      = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED_TO_SELF_PREMISE_UNVERIFIED                           = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED_TO_SELF_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_PREMISE_TO_SELF_PREMISE                                          = waWeb.WebMessageInfo_BLUE_MSG_BSP_PREMISE_TO_SELF_PREMISE
+	WebMessageInfo_BLUE_MSG_BSP_PREMISE_UNVERIFIED                                               = waWeb.WebMessageInfo_BLUE_MSG_BSP_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_PREMISE_UNVERIFIED_TO_SELF_PREMISE_VERIFIED                      = waWeb.WebMessageInfo_BLUE_MSG_BSP_PREMISE_UNVERIFIED_TO_SELF_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_PREMISE_VERIFIED                                                 = waWeb.WebMessageInfo_BLUE_MSG_BSP_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_PREMISE_VERIFIED_TO_SELF_PREMISE_UNVERIFIED                      = waWeb.WebMessageInfo_BLUE_MSG_BSP_PREMISE_VERIFIED_TO_SELF_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_CONSUMER_TO_BSP_FB_UNVERIFIED                                        = waWeb.WebMessageInfo_BLUE_MSG_CONSUMER_TO_BSP_FB_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_CONSUMER_TO_BSP_PREMISE_UNVERIFIED                                   = waWeb.WebMessageInfo_BLUE_MSG_CONSUMER_TO_BSP_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_CONSUMER_TO_SELF_FB_UNVERIFIED                                       = waWeb.WebMessageInfo_BLUE_MSG_CONSUMER_TO_SELF_FB_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_CONSUMER_TO_SELF_PREMISE_UNVERIFIED                                  = waWeb.WebMessageInfo_BLUE_MSG_CONSUMER_TO_SELF_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_FB_TO_BSP_PREMISE                                               = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_TO_BSP_PREMISE
+	WebMessageInfo_BLUE_MSG_SELF_FB_TO_SELF_PREMISE                                              = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_TO_SELF_PREMISE
+	WebMessageInfo_BLUE_MSG_SELF_FB_UNVERIFIED                                                   = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_FB_UNVERIFIED_TO_SELF_PREMISE_VERIFIED                          = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_UNVERIFIED_TO_SELF_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_FB_VERIFIED                                                     = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_VERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_FB_VERIFIED_TO_SELF_PREMISE_UNVERIFIED                          = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_VERIFIED_TO_SELF_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_PREMISE_TO_BSP_PREMISE                                          = waWeb.WebMessageInfo_BLUE_MSG_SELF_PREMISE_TO_BSP_PREMISE
+	WebMessageInfo_BLUE_MSG_SELF_PREMISE_UNVERIFIED                                              = waWeb.WebMessageInfo_BLUE_MSG_SELF_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_PREMISE_VERIFIED                                                = waWeb.WebMessageInfo_BLUE_MSG_SELF_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_TO_BSP_FB                                                            = waWeb.WebMessageInfo_BLUE_MSG_TO_BSP_FB
+	WebMessageInfo_BLUE_MSG_TO_CONSUMER                                                          = waWeb.WebMessageInfo_BLUE_MSG_TO_CONSUMER
+	WebMessageInfo_BLUE_MSG_TO_SELF_FB                                                           = waWeb.WebMessageInfo_BLUE_MSG_TO_SELF_FB
+	WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_BSP_FB_VERIFIED                                        = waWeb.WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_BSP_FB_VERIFIED
+	WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_BSP_PREMISE_VERIFIED                                   = waWeb.WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_BSP_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_SELF_FB_VERIFIED                                       = waWeb.WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_SELF_FB_VERIFIED
+	WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_VERIFIED                                               = waWeb.WebMessageInfo_BLUE_MSG_UNVERIFIED_TO_VERIFIED
+	WebMessageInfo_BLUE_MSG_VERIFIED_TO_BSP_FB_UNVERIFIED                                        = waWeb.WebMessageInfo_BLUE_MSG_VERIFIED_TO_BSP_FB_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_VERIFIED_TO_BSP_PREMISE_UNVERIFIED                                   = waWeb.WebMessageInfo_BLUE_MSG_VERIFIED_TO_BSP_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_VERIFIED_TO_SELF_FB_UNVERIFIED                                       = waWeb.WebMessageInfo_BLUE_MSG_VERIFIED_TO_SELF_FB_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_VERIFIED_TO_UNVERIFIED                                               = waWeb.WebMessageInfo_BLUE_MSG_VERIFIED_TO_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED_TO_BSP_PREMISE_VERIFIED                            = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED_TO_BSP_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED_TO_SELF_FB_VERIFIED                                = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_UNVERIFIED_TO_SELF_FB_VERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED_TO_BSP_PREMISE_UNVERIFIED                            = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED_TO_BSP_PREMISE_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED_TO_SELF_FB_UNVERIFIED                                = waWeb.WebMessageInfo_BLUE_MSG_BSP_FB_VERIFIED_TO_SELF_FB_UNVERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_FB_UNVERIFIED_TO_BSP_PREMISE_VERIFIED                           = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_UNVERIFIED_TO_BSP_PREMISE_VERIFIED
+	WebMessageInfo_BLUE_MSG_SELF_FB_VERIFIED_TO_BSP_PREMISE_UNVERIFIED                           = waWeb.WebMessageInfo_BLUE_MSG_SELF_FB_VERIFIED_TO_BSP_PREMISE_UNVERIFIED
+	WebMessageInfo_E2E_IDENTITY_UNAVAILABLE                                                      = waWeb.WebMessageInfo_E2E_IDENTITY_UNAVAILABLE
+	WebMessageInfo_GROUP_CREATING                                                                = waWeb.WebMessageInfo_GROUP_CREATING
+	WebMessageInfo_GROUP_CREATE_FAILED                                                           = waWeb.WebMessageInfo_GROUP_CREATE_FAILED
+	WebMessageInfo_GROUP_BOUNCED                                                                 = waWeb.WebMessageInfo_GROUP_BOUNCED
+	WebMessageInfo_BLOCK_CONTACT                                                                 = waWeb.WebMessageInfo_BLOCK_CONTACT
+	WebMessageInfo_EPHEMERAL_SETTING_NOT_APPLIED                                                 = waWeb.WebMessageInfo_EPHEMERAL_SETTING_NOT_APPLIED
+	WebMessageInfo_SYNC_FAILED                                                                   = waWeb.WebMessageInfo_SYNC_FAILED
+	WebMessageInfo_SYNCING                                                                       = waWeb.WebMessageInfo_SYNCING
+	WebMessageInfo_BIZ_PRIVACY_MODE_INIT_FB                                                      = waWeb.WebMessageInfo_BIZ_PRIVACY_MODE_INIT_FB
+	WebMessageInfo_BIZ_PRIVACY_MODE_INIT_BSP                                                     = waWeb.WebMessageInfo_BIZ_PRIVACY_MODE_INIT_BSP
+	WebMessageInfo_BIZ_PRIVACY_MODE_TO_FB                                                        = waWeb.WebMessageInfo_BIZ_PRIVACY_MODE_TO_FB
+	WebMessageInfo_BIZ_PRIVACY_MODE_TO_BSP                                                       = waWeb.WebMessageInfo_BIZ_PRIVACY_MODE_TO_BSP
+	WebMessageInfo_DISAPPEARING_MODE                                                             = waWeb.WebMessageInfo_DISAPPEARING_MODE
+	WebMessageInfo_E2E_DEVICE_FETCH_FAILED                                                       = waWeb.WebMessageInfo_E2E_DEVICE_FETCH_FAILED
+	WebMessageInfo_ADMIN_REVOKE                                                                  = waWeb.WebMessageInfo_ADMIN_REVOKE
+	WebMessageInfo_GROUP_INVITE_LINK_GROWTH_LOCKED                                               = waWeb.WebMessageInfo_GROUP_INVITE_LINK_GROWTH_LOCKED
+	WebMessageInfo_COMMUNITY_LINK_PARENT_GROUP                                                   = waWeb.WebMessageInfo_COMMUNITY_LINK_PARENT_GROUP
+	WebMessageInfo_COMMUNITY_LINK_SIBLING_GROUP                                                  = waWeb.WebMessageInfo_COMMUNITY_LINK_SIBLING_GROUP
+	WebMessageInfo_COMMUNITY_LINK_SUB_GROUP                                                      = waWeb.WebMessageInfo_COMMUNITY_LINK_SUB_GROUP
+	WebMessageInfo_COMMUNITY_UNLINK_PARENT_GROUP                                                 = waWeb.WebMessageInfo_COMMUNITY_UNLINK_PARENT_GROUP
+	WebMessageInfo_COMMUNITY_UNLINK_SIBLING_GROUP                                                = waWeb.WebMessageInfo_COMMUNITY_UNLINK_SIBLING_GROUP
+	WebMessageInfo_COMMUNITY_UNLINK_SUB_GROUP                                                    = waWeb.WebMessageInfo_COMMUNITY_UNLINK_SUB_GROUP
+	WebMessageInfo_GROUP_PARTICIPANT_ACCEPT                                                      = waWeb.WebMessageInfo_GROUP_PARTICIPANT_ACCEPT
+	WebMessageInfo_GROUP_PARTICIPANT_LINKED_GROUP_JOIN                                           = waWeb.WebMessageInfo_GROUP_PARTICIPANT_LINKED_GROUP_JOIN
+	WebMessageInfo_COMMUNITY_CREATE                                                              = waWeb.WebMessageInfo_COMMUNITY_CREATE
+	WebMessageInfo_EPHEMERAL_KEEP_IN_CHAT                                                        = waWeb.WebMessageInfo_EPHEMERAL_KEEP_IN_CHAT
+	WebMessageInfo_GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST                                        = waWeb.WebMessageInfo_GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST
+	WebMessageInfo_GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE                                           = waWeb.WebMessageInfo_GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE
+	WebMessageInfo_INTEGRITY_UNLINK_PARENT_GROUP                                                 = waWeb.WebMessageInfo_INTEGRITY_UNLINK_PARENT_GROUP
+	WebMessageInfo_COMMUNITY_PARTICIPANT_PROMOTE                                                 = waWeb.WebMessageInfo_COMMUNITY_PARTICIPANT_PROMOTE
+	WebMessageInfo_COMMUNITY_PARTICIPANT_DEMOTE                                                  = waWeb.WebMessageInfo_COMMUNITY_PARTICIPANT_DEMOTE
+	WebMessageInfo_COMMUNITY_PARENT_GROUP_DELETED                                                = waWeb.WebMessageInfo_COMMUNITY_PARENT_GROUP_DELETED
+	WebMessageInfo_COMMUNITY_LINK_PARENT_GROUP_MEMBERSHIP_APPROVAL                               = waWeb.WebMessageInfo_COMMUNITY_LINK_PARENT_GROUP_MEMBERSHIP_APPROVAL
+	WebMessageInfo_GROUP_PARTICIPANT_JOINED_GROUP_AND_PARENT_GROUP                               = waWeb.WebMessageInfo_GROUP_PARTICIPANT_JOINED_GROUP_AND_PARENT_GROUP
+	WebMessageInfo_MASKED_THREAD_CREATED                                                         = waWeb.WebMessageInfo_MASKED_THREAD_CREATED
+	WebMessageInfo_MASKED_THREAD_UNMASKED                                                        = waWeb.WebMessageInfo_MASKED_THREAD_UNMASKED
+	WebMessageInfo_BIZ_CHAT_ASSIGNMENT                                                           = waWeb.WebMessageInfo_BIZ_CHAT_ASSIGNMENT
+	WebMessageInfo_CHAT_PSA                                                                      = waWeb.WebMessageInfo_CHAT_PSA
+	WebMessageInfo_CHAT_POLL_CREATION_MESSAGE                                                    = waWeb.WebMessageInfo_CHAT_POLL_CREATION_MESSAGE
+	WebMessageInfo_CAG_MASKED_THREAD_CREATED                                                     = waWeb.WebMessageInfo_CAG_MASKED_THREAD_CREATED
+	WebMessageInfo_COMMUNITY_PARENT_GROUP_SUBJECT_CHANGED                                        = waWeb.WebMessageInfo_COMMUNITY_PARENT_GROUP_SUBJECT_CHANGED
+	WebMessageInfo_CAG_INVITE_AUTO_ADD                                                           = waWeb.WebMessageInfo_CAG_INVITE_AUTO_ADD
+	WebMessageInfo_BIZ_CHAT_ASSIGNMENT_UNASSIGN                                                  = waWeb.WebMessageInfo_BIZ_CHAT_ASSIGNMENT_UNASSIGN
+	WebMessageInfo_CAG_INVITE_AUTO_JOINED                                                        = waWeb.WebMessageInfo_CAG_INVITE_AUTO_JOINED
+	WebMessageInfo_SCHEDULED_CALL_START_MESSAGE                                                  = waWeb.WebMessageInfo_SCHEDULED_CALL_START_MESSAGE
+	WebMessageInfo_COMMUNITY_INVITE_RICH                                                         = waWeb.WebMessageInfo_COMMUNITY_INVITE_RICH
+	WebMessageInfo_COMMUNITY_INVITE_AUTO_ADD_RICH                                                = waWeb.WebMessageInfo_COMMUNITY_INVITE_AUTO_ADD_RICH
+	WebMessageInfo_SUB_GROUP_INVITE_RICH                                                         = waWeb.WebMessageInfo_SUB_GROUP_INVITE_RICH
+	WebMessageInfo_SUB_GROUP_PARTICIPANT_ADD_RICH                                                = waWeb.WebMessageInfo_SUB_GROUP_PARTICIPANT_ADD_RICH
+	WebMessageInfo_COMMUNITY_LINK_PARENT_GROUP_RICH                                              = waWeb.WebMessageInfo_COMMUNITY_LINK_PARENT_GROUP_RICH
+	WebMessageInfo_COMMUNITY_PARTICIPANT_ADD_RICH                                                = waWeb.WebMessageInfo_COMMUNITY_PARTICIPANT_ADD_RICH
+	WebMessageInfo_SILENCED_UNKNOWN_CALLER_AUDIO                                                 = waWeb.WebMessageInfo_SILENCED_UNKNOWN_CALLER_AUDIO
+	WebMessageInfo_SILENCED_UNKNOWN_CALLER_VIDEO                                                 = waWeb.WebMessageInfo_SILENCED_UNKNOWN_CALLER_VIDEO
+	WebMessageInfo_GROUP_MEMBER_ADD_MODE                                                         = waWeb.WebMessageInfo_GROUP_MEMBER_ADD_MODE
+	WebMessageInfo_GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD                          = waWeb.WebMessageInfo_GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD
+	WebMessageInfo_COMMUNITY_CHANGE_DESCRIPTION                                                  = waWeb.WebMessageInfo_COMMUNITY_CHANGE_DESCRIPTION
+	WebMessageInfo_SENDER_INVITE                                                                 = waWeb.WebMessageInfo_SENDER_INVITE
+	WebMessageInfo_RECEIVER_INVITE                                                               = waWeb.WebMessageInfo_RECEIVER_INVITE
+	WebMessageInfo_COMMUNITY_ALLOW_MEMBER_ADDED_GROUPS                                           = waWeb.WebMessageInfo_COMMUNITY_ALLOW_MEMBER_ADDED_GROUPS
+	WebMessageInfo_PINNED_MESSAGE_IN_CHAT                                                        = waWeb.WebMessageInfo_PINNED_MESSAGE_IN_CHAT
+	WebMessageInfo_PAYMENT_INVITE_SETUP_INVITER                                                  = waWeb.WebMessageInfo_PAYMENT_INVITE_SETUP_INVITER
+	WebMessageInfo_PAYMENT_INVITE_SETUP_INVITEE_RECEIVE_ONLY                                     = waWeb.WebMessageInfo_PAYMENT_INVITE_SETUP_INVITEE_RECEIVE_ONLY
+	WebMessageInfo_PAYMENT_INVITE_SETUP_INVITEE_SEND_AND_RECEIVE                                 = waWeb.WebMessageInfo_PAYMENT_INVITE_SETUP_INVITEE_SEND_AND_RECEIVE
+	WebMessageInfo_LINKED_GROUP_CALL_START                                                       = waWeb.WebMessageInfo_LINKED_GROUP_CALL_START
+	WebMessageInfo_REPORT_TO_ADMIN_ENABLED_STATUS                                                = waWeb.WebMessageInfo_REPORT_TO_ADMIN_ENABLED_STATUS
+	WebMessageInfo_EMPTY_SUBGROUP_CREATE                                                         = waWeb.WebMessageInfo_EMPTY_SUBGROUP_CREATE
+	WebMessageInfo_SCHEDULED_CALL_CANCEL                                                         = waWeb.WebMessageInfo_SCHEDULED_CALL_CANCEL
+	WebMessageInfo_SUBGROUP_ADMIN_TRIGGERED_AUTO_ADD_RICH                                        = waWeb.WebMessageInfo_SUBGROUP_ADMIN_TRIGGERED_AUTO_ADD_RICH
+	WebMessageInfo_GROUP_CHANGE_RECENT_HISTORY_SHARING                                           = waWeb.WebMessageInfo_GROUP_CHANGE_RECENT_HISTORY_SHARING
+	WebMessageInfo_PAID_MESSAGE_SERVER_CAMPAIGN_ID                                               = waWeb.WebMessageInfo_PAID_MESSAGE_SERVER_CAMPAIGN_ID
+	WebMessageInfo_GENERAL_CHAT_CREATE                                                           = waWeb.WebMessageInfo_GENERAL_CHAT_CREATE
+	WebMessageInfo_GENERAL_CHAT_ADD                                                              = waWeb.WebMessageInfo_GENERAL_CHAT_ADD
+	WebMessageInfo_GENERAL_CHAT_AUTO_ADD_DISABLED                                                = waWeb.WebMessageInfo_GENERAL_CHAT_AUTO_ADD_DISABLED
+	WebMessageInfo_SUGGESTED_SUBGROUP_ANNOUNCE                                                   = waWeb.WebMessageInfo_SUGGESTED_SUBGROUP_ANNOUNCE
+	WebMessageInfo_BIZ_BOT_1P_MESSAGING_ENABLED                                                  = waWeb.WebMessageInfo_BIZ_BOT_1P_MESSAGING_ENABLED
+	WebMessageInfo_CHANGE_USERNAME                                                               = waWeb.WebMessageInfo_CHANGE_USERNAME
+	WebMessageInfo_BIZ_COEX_PRIVACY_INIT_SELF                                                    = waWeb.WebMessageInfo_BIZ_COEX_PRIVACY_INIT_SELF
+	WebMessageInfo_BIZ_COEX_PRIVACY_TRANSITION_SELF                                              = waWeb.WebMessageInfo_BIZ_COEX_PRIVACY_TRANSITION_SELF
+	WebMessageInfo_SUPPORT_AI_EDUCATION                                                          = waWeb.WebMessageInfo_SUPPORT_AI_EDUCATION
+	WebMessageInfo_BIZ_BOT_3P_MESSAGING_ENABLED                                                  = waWeb.WebMessageInfo_BIZ_BOT_3P_MESSAGING_ENABLED
+	WebMessageInfo_REMINDER_SETUP_MESSAGE                                                        = waWeb.WebMessageInfo_REMINDER_SETUP_MESSAGE
+	WebMessageInfo_REMINDER_SENT_MESSAGE                                                         = waWeb.WebMessageInfo_REMINDER_SENT_MESSAGE
+	WebMessageInfo_REMINDER_CANCEL_MESSAGE                                                       = waWeb.WebMessageInfo_REMINDER_CANCEL_MESSAGE
+	WebMessageInfo_BIZ_COEX_PRIVACY_INIT                                                         = waWeb.WebMessageInfo_BIZ_COEX_PRIVACY_INIT
+	WebMessageInfo_BIZ_COEX_PRIVACY_TRANSITION                                                   = waWeb.WebMessageInfo_BIZ_COEX_PRIVACY_TRANSITION
+	WebMessageInfo_GROUP_DEACTIVATED                                                             = waWeb.WebMessageInfo_GROUP_DEACTIVATED
+	WebMessageInfo_COMMUNITY_DEACTIVATE_SIBLING_GROUP                                            = waWeb.WebMessageInfo_COMMUNITY_DEACTIVATE_SIBLING_GROUP
+	WebMessageInfo_ERROR                                                                         = waWeb.WebMessageInfo_ERROR
+	WebMessageInfo_PENDING                                                                       = waWeb.WebMessageInfo_PENDING
+	WebMessageInfo_SERVER_ACK                                                                    = waWeb.WebMessageInfo_SERVER_ACK
+	WebMessageInfo_DELIVERY_ACK                                                                  = waWeb.WebMessageInfo_DELIVERY_ACK
+	WebMessageInfo_READ                                                                          = waWeb.WebMessageInfo_READ
+	WebMessageInfo_PLAYED                                                                        = waWeb.WebMessageInfo_PLAYED
+	WebMessageInfo_E2EE                                                                          = waWeb.WebMessageInfo_E2EE
+	WebMessageInfo_FB                                                                            = waWeb.WebMessageInfo_FB
+	WebMessageInfo_BSP                                                                           = waWeb.WebMessageInfo_BSP
+	WebMessageInfo_BSP_AND_FB                                                                    = waWeb.WebMessageInfo_BSP_AND_FB
+	WebFeatures_NOT_STARTED                                                                      = waWeb.WebFeatures_NOT_STARTED
+	WebFeatures_FORCE_UPGRADE                                                                    = waWeb.WebFeatures_FORCE_UPGRADE
+	WebFeatures_DEVELOPMENT                                                                      = waWeb.WebFeatures_DEVELOPMENT
+	WebFeatures_PRODUCTION                                                                       = waWeb.WebFeatures_PRODUCTION
+	PinInChat_UNKNOWN_TYPE                                                                       = waWeb.PinInChat_UNKNOWN_TYPE
+	PinInChat_PIN_FOR_ALL                                                                        = waWeb.PinInChat_PIN_FOR_ALL
+	PinInChat_UNPIN_FOR_ALL                                                                      = waWeb.PinInChat_UNPIN_FOR_ALL
+	PaymentInfo_UNKNOWN                                                                          = waWeb.PaymentInfo_UNKNOWN
+	PaymentInfo_PENDING_SETUP                                                                    = waWeb.PaymentInfo_PENDING_SETUP
+	PaymentInfo_PENDING_RECEIVER_SETUP                                                           = waWeb.PaymentInfo_PENDING_RECEIVER_SETUP
+	PaymentInfo_INIT                                                                             = waWeb.PaymentInfo_INIT
+	PaymentInfo_SUCCESS                                                                          = waWeb.PaymentInfo_SUCCESS
+	PaymentInfo_COMPLETED                                                                        = waWeb.PaymentInfo_COMPLETED
+	PaymentInfo_FAILED                                                                           = waWeb.PaymentInfo_FAILED
+	PaymentInfo_FAILED_RISK                                                                      = waWeb.PaymentInfo_FAILED_RISK
+	PaymentInfo_FAILED_PROCESSING                                                                = waWeb.PaymentInfo_FAILED_PROCESSING
+	PaymentInfo_FAILED_RECEIVER_PROCESSING                                                       = waWeb.PaymentInfo_FAILED_RECEIVER_PROCESSING
+	PaymentInfo_FAILED_DA                                                                        = waWeb.PaymentInfo_FAILED_DA
+	PaymentInfo_FAILED_DA_FINAL                                                                  = waWeb.PaymentInfo_FAILED_DA_FINAL
+	PaymentInfo_REFUNDED_TXN                                                                     = waWeb.PaymentInfo_REFUNDED_TXN
+	PaymentInfo_REFUND_FAILED                                                                    = waWeb.PaymentInfo_REFUND_FAILED
+	PaymentInfo_REFUND_FAILED_PROCESSING                                                         = waWeb.PaymentInfo_REFUND_FAILED_PROCESSING
+	PaymentInfo_REFUND_FAILED_DA                                                                 = waWeb.PaymentInfo_REFUND_FAILED_DA
+	PaymentInfo_EXPIRED_TXN                                                                      = waWeb.PaymentInfo_EXPIRED_TXN
+	PaymentInfo_AUTH_CANCELED                                                                    = waWeb.PaymentInfo_AUTH_CANCELED
+	PaymentInfo_AUTH_CANCEL_FAILED_PROCESSING                                                    = waWeb.PaymentInfo_AUTH_CANCEL_FAILED_PROCESSING
+	PaymentInfo_AUTH_CANCEL_FAILED                                                               = waWeb.PaymentInfo_AUTH_CANCEL_FAILED
+	PaymentInfo_COLLECT_INIT                                                                     = waWeb.PaymentInfo_COLLECT_INIT
+	PaymentInfo_COLLECT_SUCCESS                                                                  = waWeb.PaymentInfo_COLLECT_SUCCESS
+	PaymentInfo_COLLECT_FAILED                                                                   = waWeb.PaymentInfo_COLLECT_FAILED
+	PaymentInfo_COLLECT_FAILED_RISK                                                              = waWeb.PaymentInfo_COLLECT_FAILED_RISK
+	PaymentInfo_COLLECT_REJECTED                                                                 = waWeb.PaymentInfo_COLLECT_REJECTED
+	PaymentInfo_COLLECT_EXPIRED                                                                  = waWeb.PaymentInfo_COLLECT_EXPIRED
+	PaymentInfo_COLLECT_CANCELED                                                                 = waWeb.PaymentInfo_COLLECT_CANCELED
+	PaymentInfo_COLLECT_CANCELLING                                                               = waWeb.PaymentInfo_COLLECT_CANCELLING
+	PaymentInfo_IN_REVIEW                                                                        = waWeb.PaymentInfo_IN_REVIEW
+	PaymentInfo_REVERSAL_SUCCESS                                                                 = waWeb.PaymentInfo_REVERSAL_SUCCESS
+	PaymentInfo_REVERSAL_PENDING                                                                 = waWeb.PaymentInfo_REVERSAL_PENDING
+	PaymentInfo_REFUND_PENDING                                                                   = waWeb.PaymentInfo_REFUND_PENDING
+	PaymentInfo_UNKNOWN_STATUS                                                                   = waWeb.PaymentInfo_UNKNOWN_STATUS
+	PaymentInfo_PROCESSING                                                                       = waWeb.PaymentInfo_PROCESSING
+	PaymentInfo_SENT                                                                             = waWeb.PaymentInfo_SENT
+	PaymentInfo_NEED_TO_ACCEPT                                                                   = waWeb.PaymentInfo_NEED_TO_ACCEPT
+	PaymentInfo_COMPLETE                                                                         = waWeb.PaymentInfo_COMPLETE
+	PaymentInfo_COULD_NOT_COMPLETE                                                               = waWeb.PaymentInfo_COULD_NOT_COMPLETE
+	PaymentInfo_REFUNDED                                                                         = waWeb.PaymentInfo_REFUNDED
+	PaymentInfo_EXPIRED                                                                          = waWeb.PaymentInfo_EXPIRED
+	PaymentInfo_REJECTED                                                                         = waWeb.PaymentInfo_REJECTED
+	PaymentInfo_CANCELLED                                                                        = waWeb.PaymentInfo_CANCELLED
+	PaymentInfo_WAITING_FOR_PAYER                                                                = waWeb.PaymentInfo_WAITING_FOR_PAYER
+	PaymentInfo_WAITING                                                                          = waWeb.PaymentInfo_WAITING
+	PaymentInfo_UNKNOWN_CURRENCY                                                                 = waWeb.PaymentInfo_UNKNOWN_CURRENCY
+	PaymentInfo_INR                                                                              = waWeb.PaymentInfo_INR
+	QP_TRUE                                                                                      = waQuickPromotionSurfaces.QP_TRUE
+	QP_FALSE                                                                                     = waQuickPromotionSurfaces.QP_FALSE
+	QP_UNKNOWN                                                                                   = waQuickPromotionSurfaces.QP_UNKNOWN
+	QP_PASS_BY_DEFAULT                                                                           = waQuickPromotionSurfaces.QP_PASS_BY_DEFAULT
+	QP_FAIL_BY_DEFAULT                                                                           = waQuickPromotionSurfaces.QP_FAIL_BY_DEFAULT
+	QP_AND                                                                                       = waQuickPromotionSurfaces.QP_AND
+	QP_OR                                                                                        = waQuickPromotionSurfaces.QP_OR
+	QP_NOR                                                                                       = waQuickPromotionSurfaces.QP_NOR
+	DeviceCapabilities_NONE                                                                      = waDeviceCapabilities.DeviceCapabilities_NONE
+	DeviceCapabilities_MINIMAL                                                                   = waDeviceCapabilities.DeviceCapabilities_MINIMAL
+	DeviceCapabilities_FULL                                                                      = waDeviceCapabilities.DeviceCapabilities_FULL
+	UserPassword_NONE                                                                            = waUserPassword.UserPassword_NONE
+	UserPassword_PBKDF2_HMAC_SHA512                                                              = waUserPassword.UserPassword_PBKDF2_HMAC_SHA512
+	UserPassword_PBKDF2_HMAC_SHA384                                                              = waUserPassword.UserPassword_PBKDF2_HMAC_SHA384
+	UserPassword_UTF8                                                                            = waUserPassword.UserPassword_UTF8
+)

File diff suppressed because it is too large
+ 8 - 0
binary/token/token.go


+ 31 - 0
binary/unpack.go

@@ -0,0 +1,31 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package binary
+
+import (
+	"bytes"
+	"compress/zlib"
+	"fmt"
+	"io"
+)
+
+// Unpack unpacks the given decrypted data from the WhatsApp web API.
+//
+// It checks the first byte to decide whether to uncompress the data with zlib or just return as-is
+// (without the first byte). There's currently no corresponding Pack function because Marshal
+// already returns the data with a leading zero (i.e. not compressed).
+func Unpack(data []byte) ([]byte, error) {
+	dataType, data := data[0], data[1:]
+	if 2&dataType > 0 {
+		if decompressor, err := zlib.NewReader(bytes.NewReader(data)); err != nil {
+			return nil, fmt.Errorf("failed to create zlib reader: %w", err)
+		} else if data, err = io.ReadAll(decompressor); err != nil {
+			return nil, err
+		}
+	}
+	return data, nil
+}

+ 108 - 0
binary/xml.go

@@ -0,0 +1,108 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package binary
+
+import (
+	"encoding/hex"
+	"fmt"
+	"sort"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+// Options to control how Node.XMLString behaves.
+var (
+	IndentXML            = false
+	MaxBytesToPrintAsHex = 128
+)
+
+// XMLString converts the Node to its XML representation
+func (n *Node) XMLString() string {
+	content := n.contentString()
+	if len(content) == 0 {
+		return fmt.Sprintf("<%[1]s%[2]s/>", n.Tag, n.attributeString())
+	}
+	newline := "\n"
+	if len(content) == 1 || !IndentXML {
+		newline = ""
+	}
+	return fmt.Sprintf("<%[1]s%[2]s>%[4]s%[3]s%[4]s</%[1]s>", n.Tag, n.attributeString(), strings.Join(content, newline), newline)
+}
+
+func (n *Node) attributeString() string {
+	if len(n.Attrs) == 0 {
+		return ""
+	}
+	stringAttrs := make([]string, len(n.Attrs)+1)
+	i := 1
+	for key, value := range n.Attrs {
+		stringAttrs[i] = fmt.Sprintf(`%s="%v"`, key, value)
+		i++
+	}
+	sort.Strings(stringAttrs)
+	return strings.Join(stringAttrs, " ")
+}
+
+func printable(data []byte) string {
+	if !utf8.Valid(data) {
+		return ""
+	}
+	str := string(data)
+	for _, c := range str {
+		if !unicode.IsPrint(c) {
+			return ""
+		}
+	}
+	return str
+}
+
+func (n *Node) contentString() []string {
+	split := make([]string, 0)
+	switch content := n.Content.(type) {
+	case []Node:
+		for _, item := range content {
+			split = append(split, strings.Split(item.XMLString(), "\n")...)
+		}
+	case []byte:
+		if strContent := printable(content); len(strContent) > 0 {
+			if IndentXML {
+				split = append(split, strings.Split(string(content), "\n")...)
+			} else {
+				split = append(split, strings.ReplaceAll(string(content), "\n", "\\n"))
+			}
+		} else if len(content) > MaxBytesToPrintAsHex {
+			split = append(split, fmt.Sprintf("<!-- %d bytes -->", len(content)))
+		} else if !IndentXML {
+			split = append(split, hex.EncodeToString(content))
+		} else {
+			hexData := hex.EncodeToString(content)
+			for i := 0; i < len(hexData); i += 80 {
+				if len(hexData) < i+80 {
+					split = append(split, hexData[i:])
+				} else {
+					split = append(split, hexData[i:i+80])
+				}
+			}
+		}
+	case nil:
+		// don't append anything
+	default:
+		strContent := fmt.Sprintf("%s", content)
+		if IndentXML {
+			split = append(split, strings.Split(strContent, "\n")...)
+		} else {
+			split = append(split, strings.ReplaceAll(strContent, "\n", "\\n"))
+		}
+	}
+	if len(split) > 1 && IndentXML {
+		for i, line := range split {
+			split[i] = "  " + line
+		}
+	}
+	return split
+}

+ 143 - 0
broadcast.go

@@ -0,0 +1,143 @@
+// Copyright (c) 2022 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/types"
+)
+
+func (cli *Client) getBroadcastListParticipants(ctx context.Context, jid types.JID) ([]types.JID, error) {
+	var list []types.JID
+	var err error
+	if jid == types.StatusBroadcastJID {
+		list, err = cli.getStatusBroadcastRecipients(ctx)
+	} else {
+		return nil, ErrBroadcastListUnsupported
+	}
+	if err != nil {
+		return nil, err
+	}
+	ownID := cli.getOwnID().ToNonAD()
+	if ownID.IsEmpty() {
+		return nil, ErrNotLoggedIn
+	}
+
+	selfIndex := -1
+	for i, participant := range list {
+		if participant.User == ownID.User {
+			selfIndex = i
+			break
+		}
+	}
+	if selfIndex < 0 {
+		list = append(list, ownID)
+	}
+	return list, nil
+}
+
+func (cli *Client) getStatusBroadcastRecipients(ctx context.Context) ([]types.JID, error) {
+	statusPrivacyOptions, err := cli.GetStatusPrivacy(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get status privacy: %w", err)
+	}
+	statusPrivacy := statusPrivacyOptions[0]
+	if statusPrivacy.Type == types.StatusPrivacyTypeWhitelist {
+		// Whitelist mode, just return the list
+		return statusPrivacy.List, nil
+	}
+
+	// Blacklist or all contacts mode. Find all contacts from database, then filter them appropriately.
+	contacts, err := cli.Store.Contacts.GetAllContacts(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get contact list from db: %w", err)
+	}
+
+	blacklist := make(map[types.JID]struct{})
+	if statusPrivacy.Type == types.StatusPrivacyTypeBlacklist {
+		for _, jid := range statusPrivacy.List {
+			blacklist[jid] = struct{}{}
+		}
+	}
+
+	var contactsArray []types.JID
+	for jid, contact := range contacts {
+		_, isBlacklisted := blacklist[jid]
+		if isBlacklisted {
+			continue
+		}
+		// TODO should there be a better way to separate contacts and found push names in the db?
+		if len(contact.FullName) > 0 {
+			contactsArray = append(contactsArray, jid)
+		}
+	}
+	return contactsArray, nil
+}
+
+var DefaultStatusPrivacy = []types.StatusPrivacy{{
+	Type:      types.StatusPrivacyTypeContacts,
+	IsDefault: true,
+}}
+
+// GetStatusPrivacy gets the user's status privacy settings (who to send status broadcasts to).
+//
+// There can be multiple different stored settings, the first one is always the default.
+func (cli *Client) GetStatusPrivacy(ctx context.Context) ([]types.StatusPrivacy, error) {
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "status",
+		Type:      iqGet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "privacy",
+		}},
+	})
+	if err != nil {
+		if errors.Is(err, ErrIQNotFound) {
+			return DefaultStatusPrivacy, nil
+		}
+		return nil, err
+	}
+	privacyLists := resp.GetChildByTag("privacy")
+	var outputs []types.StatusPrivacy
+	for _, list := range privacyLists.GetChildren() {
+		if list.Tag != "list" {
+			continue
+		}
+
+		ag := list.AttrGetter()
+		var out types.StatusPrivacy
+		out.IsDefault = ag.OptionalBool("default")
+		out.Type = types.StatusPrivacyType(ag.String("type"))
+		children := list.GetChildren()
+		if len(children) > 0 {
+			out.List = make([]types.JID, 0, len(children))
+			for _, child := range children {
+				jid, ok := child.Attrs["jid"].(types.JID)
+				if child.Tag == "user" && ok {
+					out.List = append(out.List, jid)
+				}
+			}
+		}
+		outputs = append(outputs, out)
+		if out.IsDefault {
+			// Move default to always be first in the list
+			outputs[len(outputs)-1] = outputs[0]
+			outputs[0] = out
+		}
+		if len(ag.Errors) > 0 {
+			return nil, ag.Error()
+		}
+	}
+	if len(outputs) == 0 {
+		return DefaultStatusPrivacy, nil
+	}
+	return outputs, nil
+}

+ 121 - 0
call.go

@@ -0,0 +1,121 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+func (cli *Client) handleCallEvent(ctx context.Context, node *waBinary.Node) {
+	defer cli.maybeDeferredAck(ctx, node)()
+
+	if len(node.GetChildren()) != 1 {
+		cli.dispatchEvent(&events.UnknownCallEvent{Node: node})
+		return
+	}
+	ag := node.AttrGetter()
+	child := node.GetChildren()[0]
+	cag := child.AttrGetter()
+	basicMeta := types.BasicCallMeta{
+		From:        ag.JID("from"),
+		Timestamp:   ag.UnixTime("t"),
+		CallCreator: cag.JID("call-creator"),
+		CallID:      cag.String("call-id"),
+		GroupJID:    cag.OptionalJIDOrEmpty("group-jid"),
+	}
+	if basicMeta.CallCreator.Server == types.HiddenUserServer {
+		basicMeta.CallCreatorAlt = cag.OptionalJIDOrEmpty("caller_pn")
+	} else {
+		// This may not actually exist
+		basicMeta.CallCreatorAlt = cag.OptionalJIDOrEmpty("caller_lid")
+	}
+	switch child.Tag {
+	case "offer":
+		cli.dispatchEvent(&events.CallOffer{
+			BasicCallMeta: basicMeta,
+			CallRemoteMeta: types.CallRemoteMeta{
+				RemotePlatform: ag.String("platform"),
+				RemoteVersion:  ag.String("version"),
+			},
+			Data: &child,
+		})
+	case "offer_notice":
+		cli.dispatchEvent(&events.CallOfferNotice{
+			BasicCallMeta: basicMeta,
+			Media:         cag.String("media"),
+			Type:          cag.String("type"),
+			Data:          &child,
+		})
+	case "relaylatency":
+		cli.dispatchEvent(&events.CallRelayLatency{
+			BasicCallMeta: basicMeta,
+			Data:          &child,
+		})
+	case "accept":
+		cli.dispatchEvent(&events.CallAccept{
+			BasicCallMeta: basicMeta,
+			CallRemoteMeta: types.CallRemoteMeta{
+				RemotePlatform: ag.String("platform"),
+				RemoteVersion:  ag.String("version"),
+			},
+			Data: &child,
+		})
+	case "preaccept":
+		cli.dispatchEvent(&events.CallPreAccept{
+			BasicCallMeta: basicMeta,
+			CallRemoteMeta: types.CallRemoteMeta{
+				RemotePlatform: ag.String("platform"),
+				RemoteVersion:  ag.String("version"),
+			},
+			Data: &child,
+		})
+	case "transport":
+		cli.dispatchEvent(&events.CallTransport{
+			BasicCallMeta: basicMeta,
+			CallRemoteMeta: types.CallRemoteMeta{
+				RemotePlatform: ag.String("platform"),
+				RemoteVersion:  ag.String("version"),
+			},
+			Data: &child,
+		})
+	case "terminate":
+		cli.dispatchEvent(&events.CallTerminate{
+			BasicCallMeta: basicMeta,
+			Reason:        cag.String("reason"),
+			Data:          &child,
+		})
+	case "reject":
+		cli.dispatchEvent(&events.CallReject{
+			BasicCallMeta: basicMeta,
+			Data:          &child,
+		})
+	default:
+		cli.dispatchEvent(&events.UnknownCallEvent{Node: node})
+	}
+}
+
+// RejectCall reject an incoming call.
+func (cli *Client) RejectCall(ctx context.Context, callFrom types.JID, callID string) error {
+	ownID := cli.getOwnID()
+	if ownID.IsEmpty() {
+		return ErrNotLoggedIn
+	}
+	ownID, callFrom = ownID.ToNonAD(), callFrom.ToNonAD()
+	return cli.sendNode(ctx, waBinary.Node{
+		Tag:   "call",
+		Attrs: waBinary.Attrs{"id": cli.GenerateMessageID(), "from": ownID, "to": callFrom},
+		Content: []waBinary.Node{{
+			Tag:     "reject",
+			Attrs:   waBinary.Attrs{"call-id": callID, "call-creator": callFrom, "count": "0"},
+			Content: nil,
+		}},
+	})
+}

+ 1047 - 0
client.go

@@ -0,0 +1,1047 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Package whatsmeow implements a client for interacting with the WhatsApp web multidevice API.
+package whatsmeow
+
+import (
+	"context"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"go.mau.fi/whatsmeow/app"
+	"net"
+	"net/http"
+	"net/url"
+	"runtime/debug"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"go.mau.fi/util/exhttp"
+	"go.mau.fi/util/exsync"
+	"go.mau.fi/util/ptr"
+	"go.mau.fi/util/random"
+	"golang.org/x/net/proxy"
+
+	"go.mau.fi/whatsmeow/appstate"
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/proto/waWa6"
+	"go.mau.fi/whatsmeow/proto/waWeb"
+	"go.mau.fi/whatsmeow/socket"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+	"go.mau.fi/whatsmeow/util/keys"
+	waLog "go.mau.fi/whatsmeow/util/log"
+)
+
+// EventHandler is a function that can handle events from WhatsApp.
+type EventHandler func(evt any)
+type EventHandlerWithSuccessStatus func(evt any) bool
+type nodeHandler func(ctx context.Context, node *waBinary.Node)
+
+var nextHandlerID uint32
+
+type wrappedEventHandler struct {
+	fn EventHandlerWithSuccessStatus
+	id uint32
+}
+
+type deviceCache struct {
+	devices []types.JID
+	dhash   string
+}
+
+// Client contains everything necessary to connect to and interact with the WhatsApp web API.
+type Client struct {
+	Store   *store.Device
+	Log     waLog.Logger
+	recvLog waLog.Logger
+	sendLog waLog.Logger
+
+	socket     *socket.NoiseSocket
+	socketLock sync.RWMutex
+	socketWait chan struct{}
+
+	isLoggedIn            atomic.Bool
+	expectedDisconnect    *exsync.Event
+	EnableAutoReconnect   bool
+	InitialAutoReconnect  bool
+	LastSuccessfulConnect time.Time
+	AutoReconnectErrors   int
+	// AutoReconnectHook is called when auto-reconnection fails. If the function returns false,
+	// the client will not attempt to reconnect. The number of retries can be read from AutoReconnectErrors.
+	AutoReconnectHook func(error) bool
+	// If SynchronousAck is set, acks for messages will only be sent after all event handlers return.
+	SynchronousAck             bool
+	EnableDecryptedEventBuffer bool
+	lastDecryptedBufferClear   time.Time
+
+	DisableLoginAutoReconnect bool
+
+	sendActiveReceipts atomic.Uint32
+
+	// EmitAppStateEventsOnFullSync can be set to true if you want to get app state events emitted
+	// even when re-syncing the whole state.
+	EmitAppStateEventsOnFullSync bool
+
+	AutomaticMessageRerequestFromPhone bool
+	pendingPhoneRerequests             map[types.MessageID]context.CancelFunc
+	pendingPhoneRerequestsLock         sync.RWMutex
+
+	appStateProc     *appstate.Processor
+	appStateSyncLock sync.Mutex
+
+	historySyncNotifications  chan *waE2E.HistorySyncNotification
+	historySyncHandlerStarted atomic.Bool
+	ManualHistorySyncDownload bool
+
+	uploadPreKeysLock sync.Mutex
+	lastPreKeyUpload  time.Time
+
+	mediaConnCache *MediaConn
+	mediaConnLock  sync.Mutex
+
+	responseWaiters     map[string]chan<- *waBinary.Node
+	responseWaitersLock sync.Mutex
+
+	nodeHandlers      map[string]nodeHandler
+	handlerQueue      chan *waBinary.Node
+	eventHandlers     []wrappedEventHandler
+	eventHandlersLock sync.RWMutex
+
+	messageRetries     map[string]int
+	messageRetriesLock sync.Mutex
+
+	incomingRetryRequestCounter     map[incomingRetryKey]int
+	incomingRetryRequestCounterLock sync.Mutex
+
+	appStateKeyRequests     map[string]time.Time
+	appStateKeyRequestsLock sync.RWMutex
+
+	messageSendLock sync.Mutex
+
+	privacySettingsCache atomic.Value
+
+	groupCache           map[types.JID]*groupMetaCache
+	groupCacheLock       sync.Mutex
+	userDevicesCache     map[types.JID]deviceCache
+	userDevicesCacheLock sync.Mutex
+
+	recentMessagesMap  map[recentMessageKey]RecentMessage
+	recentMessagesList [recentMessagesSize]recentMessageKey
+	recentMessagesPtr  int
+	recentMessagesLock sync.RWMutex
+
+	sessionRecreateHistory     map[types.JID]time.Time
+	sessionRecreateHistoryLock sync.Mutex
+	// GetMessageForRetry is used to find the source message for handling retry receipts
+	// when the message is not found in the recently sent message cache.
+	GetMessageForRetry func(requester, to types.JID, id types.MessageID) *waE2E.Message
+	// PreRetryCallback is called before a retry receipt is accepted.
+	// If it returns false, the accepting will be cancelled and the retry receipt will be ignored.
+	PreRetryCallback func(receipt *events.Receipt, id types.MessageID, retryCount int, msg *waE2E.Message) bool
+
+	// PrePairCallback is called before pairing is completed. If it returns false, the pairing will be cancelled and
+	// the client will disconnect.
+	PrePairCallback func(jid types.JID, platform, businessName string) bool
+
+	// GetClientPayload is called to get the client payload for connecting to the server.
+	// This should NOT be used for WhatsApp (to change the OS name, update fields in store.BaseClientPayload directly).
+	GetClientPayload func() *waWa6.ClientPayload
+
+	// Should untrusted identity errors be handled automatically? If true, the stored identity and existing signal
+	// sessions will be removed on untrusted identity errors, and an events.IdentityChange will be dispatched.
+	// If false, decrypting a message from untrusted devices will fail.
+	AutoTrustIdentity bool
+
+	// Should SubscribePresence return an error if no privacy token is stored for the user?
+	ErrorOnSubscribePresenceWithoutToken bool
+
+	SendReportingTokens bool
+
+	BackgroundEventCtx context.Context
+
+	phoneLinkingCache *phoneLinkingCache
+
+	uniqueID  string
+	idCounter atomic.Uint64
+
+	mediaHTTP     *http.Client
+	websocketHTTP *http.Client
+	preLoginHTTP  *http.Client
+
+	// This field changes the client to act like a Messenger client instead of a WhatsApp one.
+	//
+	// Note that you cannot use a Messenger account just by setting this field, you must use a
+	// separate library for all the non-e2ee-related stuff like logging in.
+	// The library is currently embedded in mautrix-meta (https://github.com/mautrix/meta), but may be separated later.
+	MessengerConfig *MessengerConfig
+	RefreshCAT      func(context.Context) error
+}
+
+type groupMetaCache struct {
+	AddressingMode             types.AddressingMode
+	CommunityAnnouncementGroup bool
+	Members                    []types.JID
+}
+
+type MessengerConfig struct {
+	UserAgent    string
+	BaseURL      string
+	WebsocketURL string
+}
+
+// Size of buffer for the channel that all incoming XML nodes go through.
+// In general it shouldn't go past a few buffered messages, but the channel is big to be safe.
+const handlerQueueSize = 2048
+
+// NewClient initializes a new WhatsApp web client.
+//
+// The logger can be nil, it will default to a no-op logger.
+//
+// The device store must be set. A default SQL-backed implementation is available in the store/sqlstore package.
+//
+//	container, err := sqlstore.New("sqlite3", "file:yoursqlitefile.db?_foreign_keys=on", nil)
+//	if err != nil {
+//		panic(err)
+//	}
+//	// If you want multiple sessions, remember their JIDs and use .GetDevice(jid) or .GetAllDevices() instead.
+//	deviceStore, err := container.GetFirstDevice()
+//	if err != nil {
+//		panic(err)
+//	}
+//	client := whatsmeow.NewClient(deviceStore, nil)
+func NewClient(deviceStore *store.Device, log waLog.Logger) *Client {
+	if log == nil {
+		log = waLog.Noop
+	}
+	uniqueIDPrefix := random.Bytes(2)
+	baseHTTPClient := &http.Client{
+		Transport: (http.DefaultTransport.(*http.Transport)).Clone(),
+	}
+	cli := &Client{
+		mediaHTTP:          ptr.Clone(baseHTTPClient),
+		websocketHTTP:      ptr.Clone(baseHTTPClient),
+		preLoginHTTP:       ptr.Clone(baseHTTPClient),
+		Store:              deviceStore,
+		Log:                log,
+		recvLog:            log.Sub("Recv"),
+		sendLog:            log.Sub("Send"),
+		uniqueID:           fmt.Sprintf("%d.%d-", uniqueIDPrefix[0], uniqueIDPrefix[1]),
+		responseWaiters:    make(map[string]chan<- *waBinary.Node),
+		eventHandlers:      make([]wrappedEventHandler, 0, 1),
+		messageRetries:     make(map[string]int),
+		handlerQueue:       make(chan *waBinary.Node, handlerQueueSize),
+		appStateProc:       appstate.NewProcessor(deviceStore, log.Sub("AppState")),
+		socketWait:         make(chan struct{}),
+		expectedDisconnect: exsync.NewEvent(),
+
+		incomingRetryRequestCounter: make(map[incomingRetryKey]int),
+
+		historySyncNotifications: make(chan *waE2E.HistorySyncNotification, 32),
+
+		groupCache:       make(map[types.JID]*groupMetaCache),
+		userDevicesCache: make(map[types.JID]deviceCache),
+
+		recentMessagesMap:      make(map[recentMessageKey]RecentMessage, recentMessagesSize),
+		sessionRecreateHistory: make(map[types.JID]time.Time),
+		GetMessageForRetry:     func(requester, to types.JID, id types.MessageID) *waE2E.Message { return nil },
+		appStateKeyRequests:    make(map[string]time.Time),
+
+		pendingPhoneRerequests: make(map[types.MessageID]context.CancelFunc),
+
+		EnableAutoReconnect: true,
+		AutoTrustIdentity:   true,
+
+		BackgroundEventCtx: context.Background(),
+	}
+	cli.nodeHandlers = map[string]nodeHandler{
+		"message":      cli.handleEncryptedMessage,
+		"appdata":      cli.handleEncryptedMessage,
+		"receipt":      cli.handleReceipt,
+		"call":         cli.handleCallEvent,
+		"chatstate":    cli.handleChatState,
+		"presence":     cli.handlePresence,
+		"notification": cli.handleNotification,
+		"success":      cli.handleConnectSuccess,
+		"failure":      cli.handleConnectFailure,
+		"stream:error": cli.handleStreamError,
+		"iq":           cli.handleIQ,
+		"ib":           cli.handleIB,
+		// Apparently there's also an <error> node which can have a code=479 and means "Invalid stanza sent (smax-invalid)"
+	}
+	return cli
+}
+
+// SetProxyAddress is a helper method that parses a URL string and calls SetProxy or SetSOCKSProxy based on the URL scheme.
+//
+// Returns an error if url.Parse fails to parse the given address.
+func (cli *Client) SetProxyAddress(addr string, opts ...SetProxyOptions) error {
+	if addr == "" {
+		cli.SetProxy(nil, opts...)
+		return nil
+	}
+	parsed, err := url.Parse(addr)
+	if err != nil {
+		return err
+	}
+	if parsed.Scheme == "http" || parsed.Scheme == "https" {
+		cli.SetProxy(http.ProxyURL(parsed), opts...)
+	} else if parsed.Scheme == "socks5" {
+		px, err := proxy.FromURL(parsed, &net.Dialer{
+			Timeout:   30 * time.Second,
+			KeepAlive: 30 * time.Second,
+		})
+		if err != nil {
+			return err
+		}
+		cli.SetSOCKSProxy(px, opts...)
+	} else {
+		return fmt.Errorf("unsupported proxy scheme %q", parsed.Scheme)
+	}
+	return nil
+}
+
+type Proxy = func(*http.Request) (*url.URL, error)
+
+// SetProxy sets a HTTP proxy to use for WhatsApp web websocket connections and media uploads/downloads.
+//
+// Must be called before Connect() to take effect in the websocket connection.
+// If you want to change the proxy after connecting, you must call Disconnect() and then Connect() again manually.
+//
+// By default, the client will find the proxy from the https_proxy environment variable like Go's net/http does.
+//
+// To disable reading proxy info from environment variables, explicitly set the proxy to nil:
+//
+//	cli.SetProxy(nil)
+//
+// To use a different proxy for the websocket and media, pass a function that checks the request path or headers:
+//
+//	cli.SetProxy(func(r *http.Request) (*url.URL, error) {
+//		if r.URL.Host == "web.whatsapp.com" && r.URL.Path == "/ws/chat" {
+//			return websocketProxyURL, nil
+//		} else {
+//			return mediaProxyURL, nil
+//		}
+//	})
+func (cli *Client) SetProxy(proxy Proxy, opts ...SetProxyOptions) {
+	var opt SetProxyOptions
+	if len(opts) > 0 {
+		opt = opts[0]
+	}
+	transport := (http.DefaultTransport.(*http.Transport)).Clone()
+	transport.Proxy = proxy
+	cli.setTransport(transport, opt)
+}
+
+type SetProxyOptions struct {
+	// If NoWebsocket is true, the proxy won't be used for the websocket
+	NoWebsocket bool
+	// If OnlyLogin is true, the proxy will be used for the pre-login websocket, but not the post-login one
+	OnlyLogin bool
+	// If NoMedia is true, the proxy won't be used for media uploads/downloads
+	NoMedia bool
+}
+
+// SetSOCKSProxy sets a SOCKS5 proxy to use for WhatsApp web websocket connections and media uploads/downloads.
+//
+// Same details as SetProxy apply, but using a different proxy for the websocket and media is not currently supported.
+func (cli *Client) SetSOCKSProxy(px proxy.Dialer, opts ...SetProxyOptions) {
+	var opt SetProxyOptions
+	if len(opts) > 0 {
+		opt = opts[0]
+	}
+	transport := (http.DefaultTransport.(*http.Transport)).Clone()
+	pxc := px.(proxy.ContextDialer)
+	transport.DialContext = pxc.DialContext
+	cli.setTransport(transport, opt)
+}
+
+func (cli *Client) setTransport(transport *http.Transport, opt SetProxyOptions) {
+	if !opt.NoWebsocket {
+		cli.preLoginHTTP.Transport = transport
+		if !opt.OnlyLogin {
+			cli.websocketHTTP.Transport = transport
+		}
+	}
+	if !opt.NoMedia {
+		cli.mediaHTTP.Transport = transport
+	}
+}
+
+// SetMediaHTTPClient sets the HTTP client used to download media.
+// This will overwrite any set proxy calls.
+func (cli *Client) SetMediaHTTPClient(h *http.Client) {
+	cli.mediaHTTP = h
+}
+
+// SetWebsocketHTTPClient sets the HTTP client used to establish the websocket connection for logged-in sessions.
+// This will overwrite any set proxy calls.
+func (cli *Client) SetWebsocketHTTPClient(h *http.Client) {
+	cli.websocketHTTP = h
+}
+
+// SetPreLoginHTTPClient sets the HTTP client used to establish the websocket connection before login.
+// This will overwrite any set proxy calls.
+func (cli *Client) SetPreLoginHTTPClient(h *http.Client) {
+	cli.preLoginHTTP = h
+}
+
+func (cli *Client) getSocketWaitChan() <-chan struct{} {
+	cli.socketLock.RLock()
+	ch := cli.socketWait
+	cli.socketLock.RUnlock()
+	return ch
+}
+
+func (cli *Client) closeSocketWaitChan() {
+	cli.socketLock.Lock()
+	close(cli.socketWait)
+	cli.socketWait = make(chan struct{})
+	cli.socketLock.Unlock()
+}
+
+func (cli *Client) getOwnID() types.JID {
+	if cli == nil {
+		return types.EmptyJID
+	}
+	return cli.Store.GetJID()
+}
+
+func (cli *Client) getOwnLID() types.JID {
+	if cli == nil {
+		return types.EmptyJID
+	}
+	return cli.Store.GetLID()
+}
+func (cli *Client) MobileLogin(loginDto *app.LoginDto) error {
+	cli.Log.Debugf("client MobileLogin")
+	cli.Disconnect()
+
+	//loginDto := &app.LoginDto{}
+	/*	err := json.Unmarshal([]byte(jsonStr), &loginDto)
+		if err != nil {
+			return fmt.Errorf("JSON unmarshal error:", err)
+		}*/
+
+	// loginDto.Init()
+
+	if loginDto.ClientStaticKeypair != "" {
+		piarKey, _ := base64.StdEncoding.DecodeString(loginDto.ClientStaticKeypair)
+		loginDto.StaticPriKey = base64.StdEncoding.EncodeToString(piarKey[:32])
+		loginDto.StaticPubKey = base64.StdEncoding.EncodeToString(piarKey[32:])
+	}
+	if loginDto.StaticPriKey == "" || loginDto.StaticPubKey == "" {
+		return fmt.Errorf("IncompleteParametersCode StaticPriKey StaticPubKey")
+	}
+	info := app.EmptyAccountInfo()
+	if loginDto.AuthBody == nil && app.IsEmpty(loginDto.AuthHexData) {
+		return fmt.Errorf("IncompleteParametersCode AuthBody AuthHexData")
+	} else if loginDto.AuthBody != nil {
+		err := app.GenAuthDataService(loginDto.AuthBodyActual.ClientPayload)
+		if err != nil {
+			return fmt.Errorf("IncompleteParametersCode AuthBody AuthHexData")
+		}
+
+		info.SetCliPayload(loginDto.AuthBodyActual.ClientPayload)
+	} else if !app.IsEmpty(loginDto.AuthHexData) {
+		// decode hex
+		authData, err := hex.DecodeString(loginDto.AuthHexData)
+		if err != nil {
+			return fmt.Errorf("ParameterError AuthHexData")
+		}
+		// set client payload Data pb
+		err = info.SetCliPayloadData(authData)
+		if err != nil {
+			return fmt.Errorf("ParameterError AuthHexData")
+		}
+	}
+	if loginDto.EdgeRouting != "" {
+		routingInfo, _ := base64.StdEncoding.DecodeString(loginDto.EdgeRouting)
+		info.SetRoutingInfo(routingInfo)
+	}
+	if loginDto.IdentityPriKey != "" {
+		_ = info.SetStaticPriKey(loginDto.IdentityPriKey)
+	}
+	if loginDto.IdentityPubKey != "" {
+		_ = info.SetStaticPubKey(loginDto.IdentityPubKey)
+	}
+	// set client static secret key
+	err := info.SetStaticHdBase64Keys(loginDto.StaticPriKey, loginDto.StaticPubKey)
+	if err != nil {
+		return fmt.Errorf("StaticPriKey or StaticPubKey")
+	}
+
+	//是否需要var deviceIdentityContainer waProto.ADVSignedDeviceIdentityHMAC ?
+	cli.Store.Mobile = true
+	cli.Store.Uuid = loginDto.UUID
+	cli.Store.ID = &types.JID{User: info.GetUserName(), Server: types.DefaultUserServer}
+
+	clientPayload := info.GetClientPayload()
+	cli.Store.MobileInfo, err = json.Marshal(clientPayload)
+	if err != nil {
+		return fmt.Errorf("Marshal clientPayload failed: %w", err)
+	}
+	cli.Store.ClientPayload = clientPayload
+
+	cli.Store.Platform = clientPayload.UserAgent.GetPlatform().String()
+	cli.Store.PushName = *clientPayload.PushName
+	cli.Store.NoiseKey.Pub = (*[32]byte)(info.GetStaticKeys().Public[:])
+	pri := *(*[32]byte)(info.GetStaticKeys().Private)
+	cli.Store.NoiseKey.Priv = (*[32]byte)(pri[:])
+
+	cli.Store.IdentityKey = &keys.KeyPair{Priv: info.GetStaticPriKey(), Pub: info.GetStaticPubKey()}
+	cli.Store.SignedPreKey = cli.Store.IdentityKey.CreateSignedPreKey(1)
+	return cli.Connect()
+}
+func (cli *Client) WaitForConnection(timeout time.Duration) bool {
+	if cli == nil {
+		return false
+	}
+	timeoutChan := time.After(timeout)
+	cli.socketLock.RLock()
+	for cli.socket == nil || !cli.socket.IsConnected() || !cli.IsLoggedIn() {
+		ch := cli.socketWait
+		cli.socketLock.RUnlock()
+		select {
+		case <-ch:
+		case <-timeoutChan:
+			return false
+		case <-cli.expectedDisconnect.GetChan():
+			return false
+		}
+		cli.socketLock.RLock()
+	}
+	cli.socketLock.RUnlock()
+	return true
+}
+
+// Connect connects the client to the WhatsApp web websocket. After connection, it will either
+// authenticate if there's data in the device store, or emit a QREvent to set up a new link.
+func (cli *Client) Connect() error {
+	return cli.ConnectContext(cli.BackgroundEventCtx)
+}
+
+func isRetryableConnectError(err error) bool {
+	if exhttp.IsNetworkError(err) {
+		return true
+	}
+
+	var statusErr socket.ErrWithStatusCode
+	if errors.As(err, &statusErr) {
+		switch statusErr.StatusCode {
+		case 408, 500, 501, 502, 503, 504:
+			return true
+		}
+	}
+
+	return false
+}
+
+func (cli *Client) ConnectContext(ctx context.Context) error {
+	if cli == nil {
+		return ErrClientIsNil
+	}
+
+	cli.socketLock.Lock()
+	defer cli.socketLock.Unlock()
+
+	err := cli.unlockedConnect(ctx)
+	if isRetryableConnectError(err) && cli.InitialAutoReconnect && cli.EnableAutoReconnect {
+		cli.Log.Errorf("Initial connection failed but reconnecting in background (%v)", err)
+		go cli.dispatchEvent(&events.Disconnected{})
+		go cli.autoReconnect(ctx)
+		return nil
+	}
+	return err
+}
+
+func (cli *Client) connect(ctx context.Context) error {
+	cli.socketLock.Lock()
+	defer cli.socketLock.Unlock()
+
+	return cli.unlockedConnect(ctx)
+}
+
+func (cli *Client) unlockedConnect(ctx context.Context) error {
+	if cli.socket != nil {
+		if !cli.socket.IsConnected() {
+			cli.unlockedDisconnect()
+		} else {
+			return ErrAlreadyConnected
+		}
+	}
+
+	cli.resetExpectedDisconnect()
+	client := cli.websocketHTTP
+	if cli.Store.ID == nil {
+		client = cli.preLoginHTTP
+	}
+	fs := socket.NewFrameSocket(cli.Log.Sub("Socket"), client)
+	if cli.MessengerConfig != nil {
+		fs.URL = cli.MessengerConfig.WebsocketURL
+		fs.HTTPHeaders.Set("Origin", cli.MessengerConfig.BaseURL)
+		fs.HTTPHeaders.Set("User-Agent", cli.MessengerConfig.UserAgent)
+		fs.HTTPHeaders.Set("Cache-Control", "no-cache")
+		fs.HTTPHeaders.Set("Pragma", "no-cache")
+		//fs.HTTPHeaders.Set("Sec-Fetch-Dest", "empty")
+		//fs.HTTPHeaders.Set("Sec-Fetch-Mode", "websocket")
+		//fs.HTTPHeaders.Set("Sec-Fetch-Site", "cross-site")
+	}
+	if err := fs.Connect(ctx); err != nil {
+		fs.Close(0)
+		return err
+	} else if err = cli.doHandshake(ctx, fs, *keys.NewKeyPair()); err != nil {
+		fs.Close(0)
+		return fmt.Errorf("noise handshake failed: %w", err)
+	}
+	go cli.keepAliveLoop(ctx, fs.Context())
+	go cli.handlerQueueLoop(ctx, fs.Context())
+	return nil
+}
+
+// IsLoggedIn returns true after the client is successfully connected and authenticated on WhatsApp.
+func (cli *Client) IsLoggedIn() bool {
+	return cli != nil && cli.isLoggedIn.Load()
+}
+
+func (cli *Client) onDisconnect(ctx context.Context, ns *socket.NoiseSocket, remote bool) {
+	ns.Stop(false)
+	cli.socketLock.Lock()
+	defer cli.socketLock.Unlock()
+	if cli.socket == ns {
+		cli.socket = nil
+		cli.clearResponseWaiters(xmlStreamEndNode)
+		if !cli.isExpectedDisconnect() && remote {
+			cli.Log.Debugf("Emitting Disconnected event")
+			go cli.dispatchEvent(&events.Disconnected{})
+			go cli.autoReconnect(ctx)
+		} else if remote {
+			cli.Log.Debugf("OnDisconnect() called, but it was expected, so not emitting event")
+		} else {
+			cli.Log.Debugf("OnDisconnect() called after manual disconnection")
+		}
+	} else {
+		cli.Log.Debugf("Ignoring OnDisconnect on different socket")
+	}
+}
+
+func (cli *Client) expectDisconnect() {
+	cli.expectedDisconnect.Set()
+}
+
+func (cli *Client) resetExpectedDisconnect() {
+	cli.expectedDisconnect.Clear()
+}
+
+func (cli *Client) isExpectedDisconnect() bool {
+	return cli.expectedDisconnect.IsSet()
+}
+
+func (cli *Client) autoReconnect(ctx context.Context) {
+	if !cli.EnableAutoReconnect || cli.Store.ID == nil {
+		return
+	}
+	for {
+		autoReconnectDelay := time.Duration(cli.AutoReconnectErrors) * 2 * time.Second
+		cli.Log.Debugf("Automatically reconnecting after %v", autoReconnectDelay)
+		cli.AutoReconnectErrors++
+		if cli.expectedDisconnect.WaitTimeoutCtx(ctx, autoReconnectDelay) == nil {
+			cli.Log.Debugf("Cancelling automatic reconnect due to expected disconnect")
+			return
+		} else if ctx.Err() != nil {
+			cli.Log.Debugf("Cancelling automatic reconnect due to context cancellation")
+			return
+		}
+		err := cli.connect(ctx)
+		if errors.Is(err, ErrAlreadyConnected) {
+			cli.Log.Debugf("Connect() said we're already connected after autoreconnect sleep")
+			return
+		} else if err != nil {
+			if cli.expectedDisconnect.IsSet() {
+				cli.Log.Debugf("Autoreconnect failed, but disconnect was expected, not reconnecting")
+				return
+			}
+			cli.Log.Errorf("Error reconnecting after autoreconnect sleep: %v", err)
+			if cli.AutoReconnectHook != nil && !cli.AutoReconnectHook(err) {
+				cli.Log.Debugf("AutoReconnectHook returned false, not reconnecting")
+				return
+			}
+		} else {
+			return
+		}
+	}
+}
+
+// IsConnected checks if the client is connected to the WhatsApp web websocket.
+// Note that this doesn't check if the client is authenticated. See the IsLoggedIn field for that.
+func (cli *Client) IsConnected() bool {
+	if cli == nil {
+		return false
+	}
+	cli.socketLock.RLock()
+	connected := cli.socket != nil && cli.socket.IsConnected()
+	cli.socketLock.RUnlock()
+	return connected
+}
+
+// Disconnect disconnects from the WhatsApp web websocket.
+//
+// This will not emit any events, the Disconnected event is only used when the
+// connection is closed by the server or a network error.
+func (cli *Client) Disconnect() {
+	if cli == nil {
+		return
+	}
+	cli.socketLock.Lock()
+	cli.expectDisconnect()
+	cli.unlockedDisconnect()
+	cli.socketLock.Unlock()
+	cli.clearDelayedMessageRequests()
+}
+
+// Disconnect closes the websocket connection.
+func (cli *Client) unlockedDisconnect() {
+	if cli.socket != nil {
+		cli.socket.Stop(true)
+		cli.socket = nil
+		cli.clearResponseWaiters(xmlStreamEndNode)
+	}
+}
+
+// Logout sends a request to unlink the device, then disconnects from the websocket and deletes the local device store.
+//
+// If the logout request fails, the disconnection and local data deletion will not happen either.
+// If an error is returned, but you want to force disconnect/clear data, call Client.Disconnect() and Client.Store.Delete() manually.
+//
+// Note that this will not emit any events. The LoggedOut event is only used for external logouts
+// (triggered by the user from the main device or by WhatsApp servers).
+func (cli *Client) Logout(ctx context.Context) error {
+	if cli == nil {
+		return ErrClientIsNil
+	} else if cli.MessengerConfig != nil {
+		return errors.New("can't logout with Messenger credentials")
+	}
+	ownID := cli.getOwnID()
+	if ownID.IsEmpty() {
+		return ErrNotLoggedIn
+	}
+	if cli.Store.Mobile {
+		cli.Disconnect()
+		err := cli.Store.Delete(ctx)
+		if err != nil {
+			return fmt.Errorf("error deleting data from store: %w", err)
+		}
+		return nil
+	}
+	_, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "md",
+		Type:      "set",
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "remove-companion-device",
+			Attrs: waBinary.Attrs{
+				"jid":    ownID,
+				"reason": "user_initiated",
+			},
+		}},
+	})
+	if err != nil {
+		return fmt.Errorf("error sending logout request: %w", err)
+	}
+	cli.Disconnect()
+	err = cli.Store.Delete(ctx)
+	if err != nil {
+		return fmt.Errorf("error deleting data from store: %w", err)
+	}
+	return nil
+}
+
+// AddEventHandler registers a new function to receive all events emitted by this client.
+//
+// The returned integer is the event handler ID, which can be passed to RemoveEventHandler to remove it.
+//
+// All registered event handlers will receive all events. You should use a type switch statement to
+// filter the events you want:
+//
+//	func myEventHandler(evt interface{}) {
+//		switch v := evt.(type) {
+//		case *events.Message:
+//			fmt.Println("Received a message!")
+//		case *events.Receipt:
+//			fmt.Println("Received a receipt!")
+//		}
+//	}
+//
+// If you want to access the Client instance inside the event handler, the recommended way is to
+// wrap the whole handler in another struct:
+//
+//	type MyClient struct {
+//		WAClient *whatsmeow.Client
+//		eventHandlerID uint32
+//	}
+//
+//	func (mycli *MyClient) register() {
+//		mycli.eventHandlerID = mycli.WAClient.AddEventHandler(mycli.myEventHandler)
+//	}
+//
+//	func (mycli *MyClient) myEventHandler(evt interface{}) {
+//		// Handle event and access mycli.WAClient
+//	}
+func (cli *Client) AddEventHandler(handler EventHandler) uint32 {
+	return cli.AddEventHandlerWithSuccessStatus(func(evt any) bool {
+		handler(evt)
+		return true
+	})
+}
+
+func (cli *Client) AddEventHandlerWithSuccessStatus(handler EventHandlerWithSuccessStatus) uint32 {
+	nextID := atomic.AddUint32(&nextHandlerID, 1)
+	cli.eventHandlersLock.Lock()
+	cli.eventHandlers = append(cli.eventHandlers, wrappedEventHandler{handler, nextID})
+	cli.eventHandlersLock.Unlock()
+	return nextID
+}
+
+// RemoveEventHandler removes a previously registered event handler function.
+// If the function with the given ID is found, this returns true.
+//
+// N.B. Do not run this directly from an event handler. That would cause a deadlock because the
+// event dispatcher holds a read lock on the event handler list, and this method wants a write lock
+// on the same list. Instead run it in a goroutine:
+//
+//	func (mycli *MyClient) myEventHandler(evt interface{}) {
+//		if noLongerWantEvents {
+//			go mycli.WAClient.RemoveEventHandler(mycli.eventHandlerID)
+//		}
+//	}
+func (cli *Client) RemoveEventHandler(id uint32) bool {
+	cli.eventHandlersLock.Lock()
+	defer cli.eventHandlersLock.Unlock()
+	for index := range cli.eventHandlers {
+		if cli.eventHandlers[index].id == id {
+			if index == 0 {
+				cli.eventHandlers[0].fn = nil
+				cli.eventHandlers = cli.eventHandlers[1:]
+				return true
+			} else if index < len(cli.eventHandlers)-1 {
+				copy(cli.eventHandlers[index:], cli.eventHandlers[index+1:])
+			}
+			cli.eventHandlers[len(cli.eventHandlers)-1].fn = nil
+			cli.eventHandlers = cli.eventHandlers[:len(cli.eventHandlers)-1]
+			return true
+		}
+	}
+	return false
+}
+
+// RemoveEventHandlers removes all event handlers that have been registered with AddEventHandler
+func (cli *Client) RemoveEventHandlers() {
+	cli.eventHandlersLock.Lock()
+	cli.eventHandlers = make([]wrappedEventHandler, 0, 1)
+	cli.eventHandlersLock.Unlock()
+}
+
+func (cli *Client) handleFrame(ctx context.Context, data []byte) {
+	decompressed, err := waBinary.Unpack(data)
+	if err != nil {
+		cli.Log.Warnf("Failed to decompress frame: %v", err)
+		cli.Log.Debugf("Errored frame hex: %s", hex.EncodeToString(data))
+		return
+	}
+	node, err := waBinary.Unmarshal(decompressed)
+	if err != nil {
+		cli.Log.Warnf("Failed to decode node in frame: %v", err)
+		cli.Log.Debugf("Errored frame hex: %s", hex.EncodeToString(decompressed))
+		return
+	}
+	cli.recvLog.Debugf("%s", node.XMLString())
+	if node.Tag == "xmlstreamend" {
+		if !cli.isExpectedDisconnect() {
+			cli.Log.Warnf("Received stream end frame")
+		}
+		// TODO should we do something else?
+	} else if cli.receiveResponse(ctx, node) {
+		// handled
+	} else if _, ok := cli.nodeHandlers[node.Tag]; ok {
+		select {
+		case cli.handlerQueue <- node:
+		case <-ctx.Done():
+		default:
+			cli.Log.Warnf("Handler queue is full, message ordering is no longer guaranteed")
+			go func() {
+				select {
+				case cli.handlerQueue <- node:
+				case <-ctx.Done():
+				}
+			}()
+		}
+	} else if node.Tag != "ack" {
+		cli.Log.Debugf("Didn't handle WhatsApp node %s", node.Tag)
+	}
+}
+
+func (cli *Client) handlerQueueLoop(evtCtx, connCtx context.Context) {
+	ticker := time.NewTicker(30 * time.Second)
+	ticker.Stop()
+	cli.Log.Debugf("Starting handler queue loop")
+Loop:
+	for {
+		select {
+		case node := <-cli.handlerQueue:
+			doneChan := make(chan struct{}, 1)
+			start := time.Now()
+			go func() {
+				cli.nodeHandlers[node.Tag](evtCtx, node)
+				duration := time.Since(start)
+				doneChan <- struct{}{}
+				if duration > 5*time.Second {
+					cli.Log.Warnf("Node handling took %s for %s", duration, node.XMLString())
+				}
+			}()
+			ticker.Reset(30 * time.Second)
+			for i := 0; i < 10; i++ {
+				select {
+				case <-doneChan:
+					ticker.Stop()
+					continue Loop
+				case <-ticker.C:
+					cli.Log.Warnf("Node handling is taking long for %s (started %s ago)", node.XMLString(), time.Since(start))
+				}
+			}
+			cli.Log.Warnf("Continuing handling of %s in background as it's taking too long", node.XMLString())
+			ticker.Stop()
+		case <-connCtx.Done():
+			cli.Log.Debugf("Closing handler queue loop")
+			return
+		}
+	}
+}
+
+func (cli *Client) sendNodeAndGetData(ctx context.Context, node waBinary.Node) ([]byte, error) {
+	if cli == nil {
+		return nil, ErrClientIsNil
+	}
+	cli.socketLock.RLock()
+	sock := cli.socket
+	cli.socketLock.RUnlock()
+	if sock == nil {
+		return nil, ErrNotConnected
+	}
+
+	payload, err := waBinary.Marshal(node)
+	if err != nil {
+		return nil, fmt.Errorf("failed to marshal node: %w", err)
+	}
+
+	cli.sendLog.Debugf("%s", node.XMLString())
+	return payload, sock.SendFrame(ctx, payload)
+}
+
+func (cli *Client) sendNode(ctx context.Context, node waBinary.Node) error {
+	_, err := cli.sendNodeAndGetData(ctx, node)
+	return err
+}
+
+func (cli *Client) dispatchEvent(evt any) (handlerFailed bool) {
+	cli.eventHandlersLock.RLock()
+	defer func() {
+		cli.eventHandlersLock.RUnlock()
+		err := recover()
+		if err != nil {
+			cli.Log.Errorf("Event handler panicked while handling a %T: %v\n%s", evt, err, debug.Stack())
+		}
+	}()
+	for _, handler := range cli.eventHandlers {
+		if !handler.fn(evt) {
+			return true
+		}
+	}
+	return false
+}
+
+// ParseWebMessage parses a WebMessageInfo object into *events.Message to match what real-time messages have.
+//
+// The chat JID can be found in the Conversation data:
+//
+//	chatJID, err := types.ParseJID(conv.GetId())
+//	for _, historyMsg := range conv.GetMessages() {
+//		evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
+//		yourNormalEventHandler(evt)
+//	}
+func (cli *Client) ParseWebMessage(chatJID types.JID, webMsg *waWeb.WebMessageInfo) (*events.Message, error) {
+	var err error
+	if chatJID.IsEmpty() {
+		chatJID, err = types.ParseJID(webMsg.GetKey().GetRemoteJID())
+		if err != nil {
+			return nil, fmt.Errorf("no chat JID provided and failed to parse remote JID: %w", err)
+		}
+	}
+	info := types.MessageInfo{
+		MessageSource: types.MessageSource{
+			Chat:     chatJID,
+			IsFromMe: webMsg.GetKey().GetFromMe(),
+			IsGroup:  chatJID.Server == types.GroupServer,
+		},
+		ID:        webMsg.GetKey().GetID(),
+		PushName:  webMsg.GetPushName(),
+		Timestamp: time.Unix(int64(webMsg.GetMessageTimestamp()), 0),
+	}
+	if info.IsFromMe {
+		info.Sender = cli.getOwnID().ToNonAD()
+		if info.Sender.IsEmpty() {
+			return nil, ErrNotLoggedIn
+		}
+	} else if chatJID.Server == types.DefaultUserServer || chatJID.Server == types.HiddenUserServer || chatJID.Server == types.NewsletterServer {
+		info.Sender = chatJID
+	} else if webMsg.GetParticipant() != "" {
+		info.Sender, err = types.ParseJID(webMsg.GetParticipant())
+	} else if webMsg.GetKey().GetParticipant() != "" {
+		info.Sender, err = types.ParseJID(webMsg.GetKey().GetParticipant())
+	} else {
+		return nil, fmt.Errorf("couldn't find sender of message %s", info.ID)
+	}
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse sender of message %s: %v", info.ID, err)
+	}
+	if pk := webMsg.GetCommentMetadata().GetCommentParentKey(); pk != nil {
+		info.MsgMetaInfo.ThreadMessageID = pk.GetID()
+		info.MsgMetaInfo.ThreadMessageSenderJID, _ = types.ParseJID(pk.GetParticipant())
+	}
+	evt := &events.Message{
+		RawMessage:   webMsg.GetMessage(),
+		SourceWebMsg: webMsg,
+		Info:         info,
+	}
+	evt.UnwrapRaw()
+	if evt.Message.GetProtocolMessage().GetType() == waE2E.ProtocolMessage_MESSAGE_EDIT {
+		evt.Info.ID = evt.Message.GetProtocolMessage().GetKey().GetID()
+		evt.Message = evt.Message.GetProtocolMessage().GetEditedMessage()
+	}
+	return evt, nil
+}
+
+func (cli *Client) StoreLIDPNMapping(ctx context.Context, first, second types.JID) {
+	var lid, pn types.JID
+	if first.Server == types.HiddenUserServer && second.Server == types.DefaultUserServer {
+		lid = first
+		pn = second
+	} else if first.Server == types.DefaultUserServer && second.Server == types.HiddenUserServer {
+		lid = second
+		pn = first
+	} else {
+		return
+	}
+	err := cli.Store.LIDs.PutLIDMapping(ctx, lid, pn)
+	if err != nil {
+		cli.Log.Errorf("Failed to store LID-PN mapping for %s -> %s: %v", lid, pn, err)
+	}
+}

+ 80 - 0
client_test.go

@@ -0,0 +1,80 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow_test
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"os/signal"
+	"syscall"
+
+	"go.mau.fi/whatsmeow"
+	"go.mau.fi/whatsmeow/store/sqlstore"
+	"go.mau.fi/whatsmeow/types/events"
+	waLog "go.mau.fi/whatsmeow/util/log"
+)
+
+func eventHandler(evt interface{}) {
+	switch v := evt.(type) {
+	case *events.Message:
+		fmt.Println("Received a message!", v.Message.GetConversation())
+	}
+}
+
+func Example() {
+	// |------------------------------------------------------------------------------------------------------|
+	// | NOTE: You must also import the appropriate DB connector, e.g. github.com/mattn/go-sqlite3 for SQLite |
+	// |------------------------------------------------------------------------------------------------------|
+
+	dbLog := waLog.Stdout("Database", "DEBUG", true)
+	ctx := context.Background()
+	container, err := sqlstore.New(ctx, "sqlite3", "file:examplestore.db?_foreign_keys=on", dbLog)
+	if err != nil {
+		panic(err)
+	}
+	// If you want multiple sessions, remember their JIDs and use .GetDevice(jid) or .GetAllDevices() instead.
+	deviceStore, err := container.GetFirstDevice(ctx)
+	if err != nil {
+		panic(err)
+	}
+	clientLog := waLog.Stdout("Client", "DEBUG", true)
+	client := whatsmeow.NewClient(deviceStore, clientLog)
+	client.AddEventHandler(eventHandler)
+
+	if client.Store.ID == nil {
+		// No ID stored, new login
+		qrChan, _ := client.GetQRChannel(context.Background())
+		err = client.Connect()
+		if err != nil {
+			panic(err)
+		}
+		for evt := range qrChan {
+			if evt.Event == "code" {
+				// Render the QR code here
+				// e.g. qrterminal.GenerateHalfBlock(evt.Code, qrterminal.L, os.Stdout)
+				// or just manually `echo 2@... | qrencode -t ansiutf8` in a terminal
+				fmt.Println("QR code:", evt.Code)
+			} else {
+				fmt.Println("Login event:", evt.Event)
+			}
+		}
+	} else {
+		// Already logged in, just connect
+		err = client.Connect()
+		if err != nil {
+			panic(err)
+		}
+	}
+
+	// Listen to Ctrl+C (you can also do something else that prevents the program from exiting)
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+	<-c
+
+	client.Disconnect()
+}

+ 229 - 0
connectionevents.go

@@ -0,0 +1,229 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"time"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+func (cli *Client) handleStreamError(ctx context.Context, node *waBinary.Node) {
+	cli.isLoggedIn.Store(false)
+	cli.clearResponseWaiters(node)
+	code, _ := node.Attrs["code"].(string)
+	conflict, _ := node.GetOptionalChildByTag("conflict")
+	conflictType := conflict.AttrGetter().OptionalString("type")
+	switch {
+	case code == "515":
+		if cli.DisableLoginAutoReconnect {
+			cli.Log.Infof("Got 515 code, but login autoreconnect is disabled, not reconnecting")
+			cli.dispatchEvent(&events.ManualLoginReconnect{})
+			return
+		}
+		cli.Log.Infof("Got 515 code, reconnecting...")
+		go func() {
+			cli.Disconnect()
+			err := cli.connect(ctx)
+			if err != nil {
+				cli.Log.Errorf("Failed to reconnect after 515 code: %v", err)
+			}
+		}()
+	case code == "401" && conflictType == "device_removed":
+		cli.expectDisconnect()
+		cli.Log.Infof("Got device removed stream error, sending LoggedOut event and deleting session")
+		go cli.dispatchEvent(&events.LoggedOut{OnConnect: false, Reason: events.ConnectFailureLoggedOut})
+		err := cli.Store.Delete(ctx)
+		if err != nil {
+			cli.Log.Warnf("Failed to delete store after device_removed error: %v", err)
+		}
+	case conflictType == "replaced":
+		cli.expectDisconnect()
+		cli.Log.Infof("Got replaced stream error, sending StreamReplaced event")
+		go cli.dispatchEvent(&events.StreamReplaced{})
+	case code == "503":
+		// This seems to happen when the server wants to restart or something.
+		// The disconnection will be emitted as an events.Disconnected and then the auto-reconnect will do its thing.
+		cli.Log.Warnf("Got 503 stream error, assuming automatic reconnect will handle it")
+	case cli.RefreshCAT != nil && (code == events.ConnectFailureCATInvalid.NumberString() || code == events.ConnectFailureCATExpired.NumberString()):
+		cli.Log.Infof("Got %s stream error, refreshing CAT before reconnecting...", code)
+		cli.socketLock.RLock()
+		defer cli.socketLock.RUnlock()
+		err := cli.RefreshCAT(ctx)
+		if err != nil {
+			cli.Log.Errorf("Failed to refresh CAT: %v", err)
+			cli.expectDisconnect()
+			go cli.dispatchEvent(&events.CATRefreshError{Error: err})
+		}
+	default:
+		cli.Log.Errorf("Unknown stream error: %s", node.XMLString())
+		go cli.dispatchEvent(&events.StreamError{Code: code, Raw: node})
+	}
+}
+
+func (cli *Client) handleIB(ctx context.Context, node *waBinary.Node) {
+	children := node.GetChildren()
+	for _, child := range children {
+		ag := child.AttrGetter()
+		switch child.Tag {
+		case "downgrade_webclient":
+			go cli.dispatchEvent(&events.QRScannedWithoutMultidevice{})
+		case "offline_preview":
+			cli.dispatchEvent(&events.OfflineSyncPreview{
+				Total:          ag.Int("count"),
+				AppDataChanges: ag.Int("appdata"),
+				Messages:       ag.Int("message"),
+				Notifications:  ag.Int("notification"),
+				Receipts:       ag.Int("receipt"),
+			})
+		case "offline":
+			cli.dispatchEvent(&events.OfflineSyncCompleted{
+				Count: ag.Int("count"),
+			})
+		case "dirty":
+			//ts := ag.UnixTime("timestamp")
+			//typ := ag.String("type") // account_sync
+			//go func() {
+			//	err := cli.MarkNotDirty(ctx, typ, ts)
+			//	zerolog.Ctx(ctx).Debug().Err(err).Msg("Marked dirty item as clean")
+			//}()
+		}
+	}
+}
+
+func (cli *Client) handleConnectFailure(ctx context.Context, node *waBinary.Node) {
+	ag := node.AttrGetter()
+	reason := events.ConnectFailureReason(ag.Int("reason"))
+	message := ag.OptionalString("message")
+	willAutoReconnect := true
+	switch {
+	default:
+		// By default, expect a disconnect (i.e. prevent auto-reconnect)
+		cli.expectDisconnect()
+		willAutoReconnect = false
+	case reason == events.ConnectFailureServiceUnavailable || reason == events.ConnectFailureInternalServerError:
+		// Auto-reconnect for 503s
+	case reason == events.ConnectFailureCATInvalid || reason == events.ConnectFailureCATExpired:
+		// Auto-reconnect when rotating CAT, lock socket to ensure refresh goes through before reconnect
+		cli.socketLock.RLock()
+		defer cli.socketLock.RUnlock()
+	}
+	if reason == 403 {
+		cli.Log.Debugf(
+			"Message for 403 connect failure: %s / %s",
+			ag.OptionalString("logout_message_header"),
+			ag.OptionalString("logout_message_subtext"),
+		)
+	}
+	if reason.IsLoggedOut() {
+		cli.Log.Infof("Got %s connect failure, sending LoggedOut event and deleting session", reason)
+		go cli.dispatchEvent(&events.LoggedOut{OnConnect: true, Reason: reason})
+		err := cli.Store.Delete(ctx)
+		if err != nil {
+			cli.Log.Warnf("Failed to delete store after %d failure: %v", int(reason), err)
+		}
+	} else if reason == events.ConnectFailureTempBanned {
+		cli.Log.Warnf("Temporary ban connect failure: %s", node.XMLString())
+		go cli.dispatchEvent(&events.TemporaryBan{
+			Code:   events.TempBanReason(ag.Int("code")),
+			Expire: time.Duration(ag.Int("expire")) * time.Second,
+		})
+	} else if reason == events.ConnectFailureClientOutdated {
+		cli.Log.Errorf("Client outdated (405) connect failure (client version: %s)", store.GetWAVersion().String())
+		go cli.dispatchEvent(&events.ClientOutdated{})
+	} else if reason == events.ConnectFailureCATInvalid || reason == events.ConnectFailureCATExpired {
+		cli.Log.Infof("Got %d/%s connect failure, refreshing CAT before reconnecting...", int(reason), message)
+		err := cli.RefreshCAT(ctx)
+		if err != nil {
+			cli.Log.Errorf("Failed to refresh CAT: %v", err)
+			cli.expectDisconnect()
+			go cli.dispatchEvent(&events.CATRefreshError{Error: err})
+		}
+	} else if willAutoReconnect {
+		cli.Log.Warnf("Got %d/%s connect failure, assuming automatic reconnect will handle it", int(reason), message)
+	} else {
+		cli.Log.Warnf("Unknown connect failure: %s", node.XMLString())
+		go cli.dispatchEvent(&events.ConnectFailure{Reason: reason, Message: message, Raw: node})
+	}
+}
+
+func (cli *Client) handleConnectSuccess(ctx context.Context, node *waBinary.Node) {
+	cli.Log.Infof("Successfully authenticated")
+	cli.LastSuccessfulConnect = time.Now()
+	cli.AutoReconnectErrors = 0
+	cli.isLoggedIn.Store(true)
+	nodeLID := node.AttrGetter().JID("lid")
+	if cli.Store.Mobile {
+		if err := cli.Store.Save(ctx); err != nil {
+			cli.Log.Infof("Successfully authenticated")
+			cli.Log.Errorf("Failed to save device store: %v", err)
+			return
+		}
+	}
+	if !cli.Store.LID.IsEmpty() && !nodeLID.IsEmpty() && cli.Store.LID != nodeLID {
+		// This should probably never happen, but check just in case.
+		cli.Log.Warnf("Stored LID doesn't match one in connect success: %s != %s", cli.Store.LID, nodeLID)
+		cli.Store.LID = types.EmptyJID
+	}
+	if cli.Store.LID.IsEmpty() && !nodeLID.IsEmpty() {
+		cli.Store.LID = nodeLID
+		err := cli.Store.Save(ctx)
+		if err != nil {
+			cli.Log.Warnf("Failed to save device after updating LID: %v", err)
+		} else {
+			cli.Log.Infof("Updated LID to %s", cli.Store.LID)
+		}
+	}
+	// Some users are missing their own LID-PN mapping even though it's already in the device table,
+	// so do this unconditionally for a few months to ensure everyone gets the row.
+	cli.StoreLIDPNMapping(ctx, cli.Store.GetLID(), cli.Store.GetJID())
+	go func() {
+		if dbCount, err := cli.Store.PreKeys.UploadedPreKeyCount(ctx); err != nil {
+			cli.Log.Errorf("Failed to get number of prekeys in database: %v", err)
+		} else if serverCount, err := cli.getServerPreKeyCount(ctx); err != nil {
+			cli.Log.Warnf("Failed to get number of prekeys on server: %v", err)
+		} else {
+			cli.Log.Debugf("Database has %d prekeys, server says we have %d", dbCount, serverCount)
+			if serverCount < MinPreKeyCount || dbCount < MinPreKeyCount {
+				cli.uploadPreKeys(ctx, dbCount == 0 && serverCount == 0)
+				sc, _ := cli.getServerPreKeyCount(ctx)
+				cli.Log.Debugf("Prekey count after upload: %d", sc)
+			}
+		}
+		err := cli.SetPassive(ctx, false)
+		if err != nil {
+			cli.Log.Warnf("Failed to send post-connect passive IQ: %v", err)
+		}
+		cli.dispatchEvent(&events.Connected{})
+		cli.closeSocketWaitChan()
+	}()
+}
+
+// SetPassive tells the WhatsApp server whether this device is passive or not.
+//
+// This seems to mostly affect whether the device receives certain events.
+// By default, whatsmeow will automatically do SetPassive(false) after connecting.
+func (cli *Client) SetPassive(ctx context.Context, passive bool) error {
+	tag := "active"
+	if passive {
+		tag = "passive"
+	}
+	_, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "passive",
+		Type:      "set",
+		To:        types.ServerJID,
+		Content:   []waBinary.Node{{Tag: tag}},
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}

+ 234 - 0
download-to-file.go

@@ -0,0 +1,234 @@
+// Copyright (c) 2024 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"time"
+
+	"go.mau.fi/util/fallocate"
+	"go.mau.fi/util/retryafter"
+
+	"go.mau.fi/whatsmeow/proto/waMediaTransport"
+	"go.mau.fi/whatsmeow/util/cbcutil"
+)
+
+type File interface {
+	io.Reader
+	io.Writer
+	io.Seeker
+	io.ReaderAt
+	io.WriterAt
+	Truncate(size int64) error
+	Stat() (os.FileInfo, error)
+}
+
+// DownloadToFile downloads the attachment from the given protobuf message.
+//
+// This is otherwise identical to [Download], but writes the attachment to a file instead of returning it as a byte slice.
+func (cli *Client) DownloadToFile(ctx context.Context, msg DownloadableMessage, file File) error {
+	if cli == nil {
+		return ErrClientIsNil
+	}
+	mediaType := GetMediaType(msg)
+	if mediaType == "" {
+		return fmt.Errorf("%w %T", ErrUnknownMediaType, msg)
+	}
+	urlable, ok := msg.(downloadableMessageWithURL)
+	var url string
+	var isWebWhatsappNetURL bool
+	if ok {
+		url = urlable.GetURL()
+		isWebWhatsappNetURL = strings.HasPrefix(url, "https://web.whatsapp.net")
+	}
+	if len(url) > 0 && !isWebWhatsappNetURL {
+		return cli.downloadAndDecryptToFile(ctx, url, msg.GetMediaKey(), mediaType, getSize(msg), msg.GetFileEncSHA256(), msg.GetFileSHA256(), file)
+	} else if len(msg.GetDirectPath()) > 0 {
+		return cli.DownloadMediaWithPathToFile(ctx, msg.GetDirectPath(), msg.GetFileEncSHA256(), msg.GetFileSHA256(), msg.GetMediaKey(), getSize(msg), mediaType, mediaTypeToMMSType[mediaType], file)
+	} else {
+		if isWebWhatsappNetURL {
+			cli.Log.Warnf("Got a media message with a web.whatsapp.net URL (%s) and no direct path", url)
+		}
+		return ErrNoURLPresent
+	}
+}
+
+func (cli *Client) DownloadFBToFile(
+	ctx context.Context,
+	transport *waMediaTransport.WAMediaTransport_Integral,
+	mediaType MediaType,
+	file File,
+) error {
+	return cli.DownloadMediaWithPathToFile(ctx, transport.GetDirectPath(), transport.GetFileEncSHA256(), transport.GetFileSHA256(), transport.GetMediaKey(), -1, mediaType, mediaTypeToMMSType[mediaType], file)
+}
+
+func (cli *Client) DownloadMediaWithPathToFile(
+	ctx context.Context,
+	directPath string,
+	encFileHash, fileHash, mediaKey []byte,
+	fileLength int,
+	mediaType MediaType,
+	mmsType string,
+	file File,
+) error {
+	mediaConn, err := cli.refreshMediaConn(ctx, false)
+	if err != nil {
+		return fmt.Errorf("failed to refresh media connections: %w", err)
+	}
+	if len(mmsType) == 0 {
+		mmsType = mediaTypeToMMSType[mediaType]
+	}
+	for i, host := range mediaConn.Hosts {
+		// TODO omit hash for unencrypted media?
+		mediaURL := fmt.Sprintf("https://%s%s&hash=%s&mms-type=%s&__wa-mms=", host.Hostname, directPath, base64.URLEncoding.EncodeToString(encFileHash), mmsType)
+		err = cli.downloadAndDecryptToFile(ctx, mediaURL, mediaKey, mediaType, fileLength, encFileHash, fileHash, file)
+		if err == nil ||
+			errors.Is(err, ErrFileLengthMismatch) ||
+			errors.Is(err, ErrInvalidMediaSHA256) ||
+			errors.Is(err, ErrMediaDownloadFailedWith403) ||
+			errors.Is(err, ErrMediaDownloadFailedWith404) ||
+			errors.Is(err, ErrMediaDownloadFailedWith410) ||
+			errors.Is(err, context.Canceled) {
+			return err
+		} else if i >= len(mediaConn.Hosts)-1 {
+			return fmt.Errorf("failed to download media from last host: %w", err)
+		}
+		cli.Log.Warnf("Failed to download media: %s, trying with next host...", err)
+	}
+	return err
+}
+
+func (cli *Client) downloadAndDecryptToFile(
+	ctx context.Context,
+	url string,
+	mediaKey []byte,
+	appInfo MediaType,
+	fileLength int,
+	fileEncSHA256, fileSHA256 []byte,
+	file File,
+) error {
+	iv, cipherKey, macKey, _ := getMediaKeys(mediaKey, appInfo)
+	hasher := sha256.New()
+	if mac, err := cli.downloadPossiblyEncryptedMediaWithRetriesToFile(ctx, url, fileEncSHA256, file); err != nil {
+		return err
+	} else if mediaKey == nil && fileEncSHA256 == nil && mac == nil {
+		// Unencrypted media, just return the downloaded data
+		return nil
+	} else if err = validateMediaFile(file, iv, macKey, mac); err != nil {
+		return err
+	} else if _, err = file.Seek(0, io.SeekStart); err != nil {
+		return fmt.Errorf("failed to seek to start of file after validating mac: %w", err)
+	} else if err = cbcutil.DecryptFile(cipherKey, iv, file); err != nil {
+		return fmt.Errorf("failed to decrypt file: %w", err)
+	} else if ReturnDownloadWarnings {
+		if info, err := file.Stat(); err != nil {
+			return fmt.Errorf("failed to stat file: %w", err)
+		} else if fileLength >= 0 && info.Size() != int64(fileLength) {
+			return fmt.Errorf("%w: expected %d, got %d", ErrFileLengthMismatch, fileLength, info.Size())
+		} else if _, err = file.Seek(0, io.SeekStart); err != nil {
+			return fmt.Errorf("failed to seek to start of file after decrypting: %w", err)
+		} else if _, err = io.Copy(hasher, file); err != nil {
+			return fmt.Errorf("failed to hash file: %w", err)
+		} else if !hmac.Equal(fileSHA256, hasher.Sum(nil)) {
+			return ErrInvalidMediaSHA256
+		}
+	}
+	return nil
+}
+
+func (cli *Client) downloadPossiblyEncryptedMediaWithRetriesToFile(ctx context.Context, url string, checksum []byte, file File) (mac []byte, err error) {
+	for retryNum := 0; retryNum < 5; retryNum++ {
+		if checksum == nil {
+			_, _, err = cli.downloadMediaToFile(ctx, url, file)
+		} else {
+			mac, err = cli.downloadEncryptedMediaToFile(ctx, url, checksum, file)
+		}
+		if err == nil || !shouldRetryMediaDownload(err) {
+			return
+		}
+		retryDuration := time.Duration(retryNum+1) * time.Second
+		var httpErr DownloadHTTPError
+		if errors.As(err, &httpErr) {
+			retryDuration = retryafter.Parse(httpErr.Response.Header.Get("Retry-After"), retryDuration)
+		}
+		cli.Log.Warnf("Failed to download media due to network error: %v, retrying in %s...", err, retryDuration)
+		_, err = file.Seek(0, io.SeekStart)
+		if err != nil {
+			return nil, fmt.Errorf("failed to seek to start of file to retry download: %w", err)
+		}
+		select {
+		case <-ctx.Done():
+			return nil, ctx.Err()
+		case <-time.After(retryDuration):
+		}
+	}
+	return
+}
+
+func (cli *Client) downloadMediaToFile(ctx context.Context, url string, file io.Writer) (int64, []byte, error) {
+	resp, err := cli.doMediaDownloadRequest(ctx, url)
+	if err != nil {
+		return 0, nil, err
+	}
+	defer resp.Body.Close()
+	osFile, ok := file.(*os.File)
+	if ok && resp.ContentLength > 0 {
+		err = fallocate.Fallocate(osFile, int(resp.ContentLength))
+		if err != nil {
+			return 0, nil, fmt.Errorf("failed to preallocate file: %w", err)
+		}
+	}
+	hasher := sha256.New()
+	n, err := io.Copy(file, io.TeeReader(resp.Body, hasher))
+	return n, hasher.Sum(nil), err
+}
+
+func (cli *Client) downloadEncryptedMediaToFile(ctx context.Context, url string, checksum []byte, file File) ([]byte, error) {
+	size, hash, err := cli.downloadMediaToFile(ctx, url, file)
+	if err != nil {
+		return nil, err
+	} else if size <= mediaHMACLength {
+		return nil, ErrTooShortFile
+	} else if len(checksum) == 32 && !hmac.Equal(checksum, hash) {
+		return nil, ErrInvalidMediaEncSHA256
+	}
+	mac := make([]byte, mediaHMACLength)
+	_, err = file.ReadAt(mac, size-mediaHMACLength)
+	if err != nil {
+		return nil, fmt.Errorf("failed to read MAC from file: %w", err)
+	}
+	err = file.Truncate(size - mediaHMACLength)
+	if err != nil {
+		return nil, fmt.Errorf("failed to truncate file to remove MAC: %w", err)
+	}
+	return mac, nil
+}
+
+func validateMediaFile(file io.ReadSeeker, iv, macKey, mac []byte) error {
+	h := hmac.New(sha256.New, macKey)
+	h.Write(iv)
+	_, err := file.Seek(0, io.SeekStart)
+	if err != nil {
+		return fmt.Errorf("failed to seek to start of file: %w", err)
+	}
+	_, err = io.Copy(h, file)
+	if err != nil {
+		return fmt.Errorf("failed to hash file: %w", err)
+	}
+	if !hmac.Equal(h.Sum(nil)[:mediaHMACLength], mac) {
+		return ErrInvalidMediaHMAC
+	}
+	return nil
+}

+ 417 - 0
download.go

@@ -0,0 +1,417 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"net/http"
+	"strings"
+	"time"
+
+	"go.mau.fi/util/retryafter"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/reflect/protoreflect"
+
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/proto/waHistorySync"
+	"go.mau.fi/whatsmeow/proto/waMediaTransport"
+	"go.mau.fi/whatsmeow/proto/waServerSync"
+	"go.mau.fi/whatsmeow/socket"
+	"go.mau.fi/whatsmeow/util/cbcutil"
+	"go.mau.fi/whatsmeow/util/hkdfutil"
+)
+
+// MediaType represents a type of uploaded file on WhatsApp.
+// The value is the key which is used as a part of generating the encryption keys.
+type MediaType string
+
+// The known media types
+const (
+	MediaImage    MediaType = "WhatsApp Image Keys"
+	MediaVideo    MediaType = "WhatsApp Video Keys"
+	MediaAudio    MediaType = "WhatsApp Audio Keys"
+	MediaDocument MediaType = "WhatsApp Document Keys"
+	MediaHistory  MediaType = "WhatsApp History Keys"
+	MediaAppState MediaType = "WhatsApp App State Keys"
+
+	MediaStickerPack   MediaType = "WhatsApp Sticker Pack Keys"
+	MediaLinkThumbnail MediaType = "WhatsApp Link Thumbnail Keys"
+)
+
+// DownloadableMessage represents a protobuf message that contains attachment info.
+//
+// All of the downloadable messages inside a Message struct implement this interface
+// (ImageMessage, VideoMessage, AudioMessage, DocumentMessage, StickerMessage).
+type DownloadableMessage interface {
+	GetDirectPath() string
+	GetMediaKey() []byte
+	GetFileSHA256() []byte
+	GetFileEncSHA256() []byte
+}
+
+type MediaTypeable interface {
+	GetMediaType() MediaType
+}
+
+// DownloadableThumbnail represents a protobuf message that contains a thumbnail attachment.
+//
+// This is primarily meant for link preview thumbnails in ExtendedTextMessage.
+type DownloadableThumbnail interface {
+	proto.Message
+	GetThumbnailDirectPath() string
+	GetThumbnailSHA256() []byte
+	GetThumbnailEncSHA256() []byte
+	GetMediaKey() []byte
+}
+
+// All the message types that are intended to be downloadable
+var (
+	_ DownloadableMessage   = (*waE2E.ImageMessage)(nil)
+	_ DownloadableMessage   = (*waE2E.AudioMessage)(nil)
+	_ DownloadableMessage   = (*waE2E.VideoMessage)(nil)
+	_ DownloadableMessage   = (*waE2E.DocumentMessage)(nil)
+	_ DownloadableMessage   = (*waE2E.StickerMessage)(nil)
+	_ DownloadableMessage   = (*waE2E.StickerPackMessage)(nil)
+	_ DownloadableMessage   = (*waHistorySync.StickerMetadata)(nil)
+	_ DownloadableMessage   = (*waE2E.HistorySyncNotification)(nil)
+	_ DownloadableMessage   = (*waServerSync.ExternalBlobReference)(nil)
+	_ DownloadableThumbnail = (*waE2E.ExtendedTextMessage)(nil)
+)
+
+type downloadableMessageWithLength interface {
+	DownloadableMessage
+	GetFileLength() uint64
+}
+
+type downloadableMessageWithSizeBytes interface {
+	DownloadableMessage
+	GetFileSizeBytes() uint64
+}
+
+type downloadableMessageWithURL interface {
+	DownloadableMessage
+	GetURL() string
+}
+
+var classToMediaType = map[protoreflect.Name]MediaType{
+	"ImageMessage":    MediaImage,
+	"AudioMessage":    MediaAudio,
+	"VideoMessage":    MediaVideo,
+	"DocumentMessage": MediaDocument,
+	"StickerMessage":  MediaImage,
+	"StickerMetadata": MediaImage,
+
+	"StickerPackMessage":      MediaStickerPack,
+	"HistorySyncNotification": MediaHistory,
+	"ExternalBlobReference":   MediaAppState,
+}
+
+var classToThumbnailMediaType = map[protoreflect.Name]MediaType{
+	"ExtendedTextMessage": MediaLinkThumbnail,
+}
+
+var mediaTypeToMMSType = map[MediaType]string{
+	MediaImage:    "image",
+	MediaAudio:    "audio",
+	MediaVideo:    "video",
+	MediaDocument: "document",
+	MediaHistory:  "md-msg-hist",
+	MediaAppState: "md-app-state",
+
+	MediaStickerPack:   "sticker-pack",
+	MediaLinkThumbnail: "thumbnail-link",
+}
+
+// DownloadAny loops through the downloadable parts of the given message and downloads the first non-nil item.
+//
+// Deprecated: it's recommended to find the specific message type you want to download manually and use the Download method instead.
+func (cli *Client) DownloadAny(ctx context.Context, msg *waE2E.Message) (data []byte, err error) {
+	if msg == nil {
+		return nil, ErrNothingDownloadableFound
+	}
+	switch {
+	case msg.ImageMessage != nil:
+		return cli.Download(ctx, msg.ImageMessage)
+	case msg.VideoMessage != nil:
+		return cli.Download(ctx, msg.VideoMessage)
+	case msg.AudioMessage != nil:
+		return cli.Download(ctx, msg.AudioMessage)
+	case msg.DocumentMessage != nil:
+		return cli.Download(ctx, msg.DocumentMessage)
+	case msg.StickerMessage != nil:
+		return cli.Download(ctx, msg.StickerMessage)
+	default:
+		return nil, ErrNothingDownloadableFound
+	}
+}
+
+func getSize(msg DownloadableMessage) int {
+	switch sized := msg.(type) {
+	case downloadableMessageWithLength:
+		return int(sized.GetFileLength())
+	case downloadableMessageWithSizeBytes:
+		return int(sized.GetFileSizeBytes())
+	default:
+		return -1
+	}
+}
+
+// ReturnDownloadWarnings controls whether the Download function returns non-fatal validation warnings.
+// Currently, these include [ErrFileLengthMismatch] and [ErrInvalidMediaSHA256].
+var ReturnDownloadWarnings = true
+
+// DownloadThumbnail downloads a thumbnail from a message.
+//
+// This is primarily intended for downloading link preview thumbnails, which are in ExtendedTextMessage:
+//
+//	var msg *waE2E.Message
+//	...
+//	thumbnailImageBytes, err := cli.DownloadThumbnail(msg.GetExtendedTextMessage())
+func (cli *Client) DownloadThumbnail(ctx context.Context, msg DownloadableThumbnail) ([]byte, error) {
+	mediaType, ok := classToThumbnailMediaType[msg.ProtoReflect().Descriptor().Name()]
+	if !ok {
+		return nil, fmt.Errorf("%w '%s'", ErrUnknownMediaType, string(msg.ProtoReflect().Descriptor().Name()))
+	} else if len(msg.GetThumbnailDirectPath()) > 0 {
+		return cli.DownloadMediaWithPath(ctx, msg.GetThumbnailDirectPath(), msg.GetThumbnailEncSHA256(), msg.GetThumbnailSHA256(), msg.GetMediaKey(), -1, mediaType, mediaTypeToMMSType[mediaType])
+	} else {
+		return nil, ErrNoURLPresent
+	}
+}
+
+// GetMediaType returns the MediaType value corresponding to the given protobuf message.
+func GetMediaType(msg DownloadableMessage) MediaType {
+	protoReflecter, ok := msg.(proto.Message)
+	if !ok {
+		mediaTypeable, ok := msg.(MediaTypeable)
+		if !ok {
+			return ""
+		}
+		return mediaTypeable.GetMediaType()
+	}
+	return classToMediaType[protoReflecter.ProtoReflect().Descriptor().Name()]
+}
+
+// Download downloads the attachment from the given protobuf message.
+//
+// The attachment is a specific part of a Message protobuf struct, not the message itself, e.g.
+//
+//	var msg *waE2E.Message
+//	...
+//	imageData, err := cli.Download(msg.GetImageMessage())
+//
+// You can also use DownloadAny to download the first non-nil sub-message.
+func (cli *Client) Download(ctx context.Context, msg DownloadableMessage) ([]byte, error) {
+	if cli == nil {
+		return nil, ErrClientIsNil
+	}
+	mediaType := GetMediaType(msg)
+	if mediaType == "" {
+		return nil, fmt.Errorf("%w %T", ErrUnknownMediaType, msg)
+	}
+	urlable, ok := msg.(downloadableMessageWithURL)
+	var url string
+	var isWebWhatsappNetURL bool
+	if ok {
+		url = urlable.GetURL()
+		isWebWhatsappNetURL = strings.HasPrefix(url, "https://web.whatsapp.net")
+	}
+	if len(url) > 0 && !isWebWhatsappNetURL {
+		return cli.downloadAndDecrypt(ctx, url, msg.GetMediaKey(), mediaType, getSize(msg), msg.GetFileEncSHA256(), msg.GetFileSHA256())
+	} else if len(msg.GetDirectPath()) > 0 {
+		return cli.DownloadMediaWithPath(ctx, msg.GetDirectPath(), msg.GetFileEncSHA256(), msg.GetFileSHA256(), msg.GetMediaKey(), getSize(msg), mediaType, mediaTypeToMMSType[mediaType])
+	} else {
+		if isWebWhatsappNetURL {
+			cli.Log.Warnf("Got a media message with a web.whatsapp.net URL (%s) and no direct path", url)
+		}
+		return nil, ErrNoURLPresent
+	}
+}
+
+func (cli *Client) DownloadFB(
+	ctx context.Context,
+	transport *waMediaTransport.WAMediaTransport_Integral,
+	mediaType MediaType,
+) ([]byte, error) {
+	return cli.DownloadMediaWithPath(ctx, transport.GetDirectPath(), transport.GetFileEncSHA256(), transport.GetFileSHA256(), transport.GetMediaKey(), -1, mediaType, mediaTypeToMMSType[mediaType])
+}
+
+// DownloadMediaWithPath downloads an attachment by manually specifying the path and encryption details.
+func (cli *Client) DownloadMediaWithPath(
+	ctx context.Context,
+	directPath string,
+	encFileHash, fileHash, mediaKey []byte,
+	fileLength int,
+	mediaType MediaType,
+	mmsType string,
+) (data []byte, err error) {
+	if !strings.HasPrefix(directPath, "/") {
+		return nil, fmt.Errorf("media download path does not start with slash: %s", directPath)
+	}
+	var mediaConn *MediaConn
+	mediaConn, err = cli.refreshMediaConn(ctx, false)
+	if err != nil {
+		return nil, fmt.Errorf("failed to refresh media connections: %w", err)
+	}
+	if len(mmsType) == 0 {
+		mmsType = mediaTypeToMMSType[mediaType]
+	}
+	for i, host := range mediaConn.Hosts {
+		// TODO omit hash for unencrypted media?
+		mediaURL := fmt.Sprintf("https://%s%s&hash=%s&mms-type=%s&__wa-mms=", host.Hostname, directPath, base64.URLEncoding.EncodeToString(encFileHash), mmsType)
+		data, err = cli.downloadAndDecrypt(ctx, mediaURL, mediaKey, mediaType, fileLength, encFileHash, fileHash)
+		if err == nil ||
+			errors.Is(err, ErrFileLengthMismatch) ||
+			errors.Is(err, ErrInvalidMediaSHA256) ||
+			errors.Is(err, ErrMediaDownloadFailedWith403) ||
+			errors.Is(err, ErrMediaDownloadFailedWith404) ||
+			errors.Is(err, ErrMediaDownloadFailedWith410) ||
+			errors.Is(err, context.Canceled) {
+			return
+		} else if i >= len(mediaConn.Hosts)-1 {
+			return nil, fmt.Errorf("failed to download media from last host: %w", err)
+		}
+		cli.Log.Warnf("Failed to download media: %s, trying with next host...", err)
+	}
+	return
+}
+
+func (cli *Client) downloadAndDecrypt(
+	ctx context.Context,
+	url string,
+	mediaKey []byte,
+	appInfo MediaType,
+	fileLength int,
+	fileEncSHA256,
+	fileSHA256 []byte,
+) (data []byte, err error) {
+	iv, cipherKey, macKey, _ := getMediaKeys(mediaKey, appInfo)
+	var ciphertext, mac []byte
+	if ciphertext, mac, err = cli.downloadPossiblyEncryptedMediaWithRetries(ctx, url, fileEncSHA256); err != nil {
+
+	} else if mediaKey == nil && fileEncSHA256 == nil && mac == nil {
+		// Unencrypted media, just return the downloaded data
+		data = ciphertext
+	} else if err = validateMedia(iv, ciphertext, macKey, mac); err != nil {
+
+	} else if data, err = cbcutil.Decrypt(cipherKey, iv, ciphertext); err != nil {
+		err = fmt.Errorf("failed to decrypt file: %w", err)
+	} else if ReturnDownloadWarnings {
+		if fileLength >= 0 && len(data) != fileLength {
+			err = fmt.Errorf("%w: expected %d, got %d", ErrFileLengthMismatch, fileLength, len(data))
+		} else if len(fileSHA256) == 32 && sha256.Sum256(data) != *(*[32]byte)(fileSHA256) {
+			err = ErrInvalidMediaSHA256
+		}
+	}
+	return
+}
+
+func getMediaKeys(mediaKey []byte, appInfo MediaType) (iv, cipherKey, macKey, refKey []byte) {
+	mediaKeyExpanded := hkdfutil.SHA256(mediaKey, nil, []byte(appInfo), 112)
+	return mediaKeyExpanded[:16], mediaKeyExpanded[16:48], mediaKeyExpanded[48:80], mediaKeyExpanded[80:]
+}
+
+func shouldRetryMediaDownload(err error) bool {
+	if errors.Is(err, context.Canceled) {
+		return false
+	}
+	var netErr net.Error
+	var httpErr DownloadHTTPError
+	return errors.As(err, &netErr) ||
+		strings.HasPrefix(err.Error(), "stream error:") || // hacky check for http2 errors
+		(errors.As(err, &httpErr) && retryafter.Should(httpErr.StatusCode, true))
+}
+
+func (cli *Client) downloadPossiblyEncryptedMediaWithRetries(ctx context.Context, url string, checksum []byte) (file, mac []byte, err error) {
+	for retryNum := 0; retryNum < 5; retryNum++ {
+		if checksum == nil {
+			file, err = cli.downloadMedia(ctx, url)
+		} else {
+			file, mac, err = cli.downloadEncryptedMedia(ctx, url, checksum)
+		}
+		if err == nil || !shouldRetryMediaDownload(err) {
+			return
+		}
+		retryDuration := time.Duration(retryNum+1) * time.Second
+		var httpErr DownloadHTTPError
+		if errors.As(err, &httpErr) {
+			retryDuration = retryafter.Parse(httpErr.Response.Header.Get("Retry-After"), retryDuration)
+		}
+		cli.Log.Warnf("Failed to download media due to network error: %v, retrying in %s...", err, retryDuration)
+		select {
+		case <-ctx.Done():
+			return nil, nil, ctx.Err()
+		case <-time.After(retryDuration):
+		}
+	}
+	return
+}
+
+func (cli *Client) doMediaDownloadRequest(ctx context.Context, url string) (*http.Response, error) {
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
+	if err != nil {
+		return nil, fmt.Errorf("failed to prepare request: %w", err)
+	}
+	req.Header.Set("Origin", socket.Origin)
+	req.Header.Set("Referer", socket.Origin+"/")
+	if cli.MessengerConfig != nil {
+		req.Header.Set("User-Agent", cli.MessengerConfig.UserAgent)
+	}
+	// TODO user agent for whatsapp downloads?
+	resp, err := cli.mediaHTTP.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	if resp.StatusCode != http.StatusOK {
+		_ = resp.Body.Close()
+		return nil, DownloadHTTPError{Response: resp}
+	}
+	return resp, nil
+}
+
+func (cli *Client) downloadMedia(ctx context.Context, url string) ([]byte, error) {
+	resp, err := cli.doMediaDownloadRequest(ctx, url)
+	if err != nil {
+		return nil, err
+	}
+	data, err := io.ReadAll(resp.Body)
+	_ = resp.Body.Close()
+	return data, err
+}
+
+const mediaHMACLength = 10
+
+func (cli *Client) downloadEncryptedMedia(ctx context.Context, url string, checksum []byte) (file, mac []byte, err error) {
+	data, err := cli.downloadMedia(ctx, url)
+	if err != nil {
+		return
+	} else if len(data) <= mediaHMACLength {
+		err = ErrTooShortFile
+		return
+	}
+	file, mac = data[:len(data)-mediaHMACLength], data[len(data)-mediaHMACLength:]
+	if len(checksum) == 32 && sha256.Sum256(data) != *(*[32]byte)(checksum) {
+		err = ErrInvalidMediaEncSHA256
+	}
+	return
+}
+
+func validateMedia(iv, file, macKey, mac []byte) error {
+	h := hmac.New(sha256.New, macKey)
+	h.Write(iv)
+	h.Write(file)
+	if !hmac.Equal(h.Sum(nil)[:mediaHMACLength], mac) {
+		return ErrInvalidMediaHMAC
+	}
+	return nil
+}

+ 265 - 0
errors.go

@@ -0,0 +1,265 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+)
+
+// Miscellaneous errors
+var (
+	ErrClientIsNil     = errors.New("client is nil")
+	ErrNoSession       = errors.New("can't encrypt message for device: no signal session established")
+	ErrIQTimedOut      = errors.New("info query timed out")
+	ErrNotConnected    = errors.New("websocket not connected")
+	ErrNotLoggedIn     = errors.New("the store doesn't contain a device JID")
+	ErrMessageTimedOut = errors.New("timed out waiting for message send response")
+
+	ErrAlreadyConnected = errors.New("websocket is already connected")
+
+	ErrPhoneNumberTooShort           = errors.New("phone number too short")
+	ErrPhoneNumberIsNotInternational = errors.New("international phone number required (must not start with 0)")
+
+	ErrQRAlreadyConnected = errors.New("GetQRChannel must be called before connecting")
+	ErrQRStoreContainsID  = errors.New("GetQRChannel can only be called when there's no user ID in the client's Store")
+
+	ErrNoPushName = errors.New("can't send presence without PushName set")
+
+	ErrNoPrivacyToken = errors.New("no privacy token stored")
+
+	ErrAppStateUpdate = errors.New("server returned error updating app state")
+)
+
+// Errors that happen while confirming device pairing
+var (
+	ErrPairInvalidDeviceIdentityHMAC = errors.New("invalid device identity HMAC in pair success message")
+	ErrPairInvalidDeviceSignature    = errors.New("invalid device signature in pair success message")
+	ErrPairRejectedLocally           = errors.New("local PrePairCallback rejected pairing")
+)
+
+// PairProtoError is included in an events.PairError if the pairing failed due to a protobuf error.
+type PairProtoError struct {
+	Message  string
+	ProtoErr error
+}
+
+func (err *PairProtoError) Error() string {
+	return fmt.Sprintf("%s: %v", err.Message, err.ProtoErr)
+}
+
+func (err *PairProtoError) Unwrap() error {
+	return err.ProtoErr
+}
+
+// PairDatabaseError is included in an events.PairError if the pairing failed due to being unable to save the credentials to the device store.
+type PairDatabaseError struct {
+	Message string
+	DBErr   error
+}
+
+func (err *PairDatabaseError) Error() string {
+	return fmt.Sprintf("%s: %v", err.Message, err.DBErr)
+}
+
+func (err *PairDatabaseError) Unwrap() error {
+	return err.DBErr
+}
+
+var (
+	// ErrProfilePictureUnauthorized is returned by GetProfilePictureInfo when trying to get the profile picture of a user
+	// whose privacy settings prevent you from seeing their profile picture (status code 401).
+	ErrProfilePictureUnauthorized = errors.New("the user has hidden their profile picture from you")
+	// ErrProfilePictureNotSet is returned by GetProfilePictureInfo when the given user or group doesn't have a profile
+	// picture (status code 404).
+	ErrProfilePictureNotSet = errors.New("that user or group does not have a profile picture")
+	// ErrGroupInviteLinkUnauthorized is returned by GetGroupInviteLink if you don't have the permission to get the link (status code 401).
+	ErrGroupInviteLinkUnauthorized = errors.New("you don't have the permission to get the group's invite link")
+	// ErrNotInGroup is returned by group info getting methods if you're not in the group (status code 403).
+	ErrNotInGroup = errors.New("you're not participating in that group")
+	// ErrGroupNotFound is returned by group info getting methods if the group doesn't exist (status code 404).
+	ErrGroupNotFound = errors.New("that group does not exist")
+	// ErrInviteLinkInvalid is returned by methods that use group invite links if the invite link is malformed.
+	ErrInviteLinkInvalid = errors.New("that group invite link is not valid")
+	// ErrInviteLinkRevoked is returned by methods that use group invite links if the invite link was valid, but has been revoked and can no longer be used.
+	ErrInviteLinkRevoked = errors.New("that group invite link has been revoked")
+	// ErrBusinessMessageLinkNotFound is returned by ResolveBusinessMessageLink if the link doesn't exist or has been revoked.
+	ErrBusinessMessageLinkNotFound = errors.New("that business message link does not exist or has been revoked")
+	// ErrContactQRLinkNotFound is returned by ResolveContactQRLink if the link doesn't exist or has been revoked.
+	ErrContactQRLinkNotFound = errors.New("that contact QR link does not exist or has been revoked")
+	// ErrInvalidImageFormat is returned by SetGroupPhoto if the given photo is not in the correct format.
+	ErrInvalidImageFormat = errors.New("the given data is not a valid image")
+	// ErrMediaNotAvailableOnPhone is returned by DecryptMediaRetryNotification if the given event contains error code 2.
+	ErrMediaNotAvailableOnPhone = errors.New("media no longer available on phone")
+	// ErrUnknownMediaRetryError is returned by DecryptMediaRetryNotification if the given event contains an unknown error code.
+	ErrUnknownMediaRetryError = errors.New("unknown media retry error")
+	// ErrInvalidDisappearingTimer is returned by SetDisappearingTimer if the given timer is not one of the allowed values.
+	ErrInvalidDisappearingTimer = errors.New("invalid disappearing timer provided")
+)
+
+// Some errors that Client.SendMessage can return
+var (
+	ErrBroadcastListUnsupported = errors.New("sending to non-status broadcast lists is not yet supported")
+	ErrUnknownServer            = errors.New("can't send message to unknown server")
+	ErrRecipientADJID           = errors.New("message recipient must be a user JID with no device part")
+	ErrServerReturnedError      = errors.New("server returned error")
+	ErrInvalidInlineBotID       = errors.New("invalid inline bot ID")
+)
+
+type DownloadHTTPError struct {
+	*http.Response
+}
+
+func (dhe DownloadHTTPError) Error() string {
+	return fmt.Sprintf("download failed with status code %d", dhe.StatusCode)
+}
+
+func (dhe DownloadHTTPError) Is(other error) bool {
+	var otherDHE DownloadHTTPError
+	return errors.As(other, &otherDHE) && dhe.StatusCode == otherDHE.StatusCode
+}
+
+// Some errors that Client.Download can return
+var (
+	ErrMediaDownloadFailedWith403 = DownloadHTTPError{Response: &http.Response{StatusCode: 403}}
+	ErrMediaDownloadFailedWith404 = DownloadHTTPError{Response: &http.Response{StatusCode: 404}}
+	ErrMediaDownloadFailedWith410 = DownloadHTTPError{Response: &http.Response{StatusCode: 410}}
+	ErrNoURLPresent               = errors.New("no url present")
+	ErrFileLengthMismatch         = errors.New("file length does not match")
+	ErrTooShortFile               = errors.New("file too short")
+	ErrInvalidMediaHMAC           = errors.New("invalid media hmac")
+	ErrInvalidMediaEncSHA256      = errors.New("hash of media ciphertext doesn't match")
+	ErrInvalidMediaSHA256         = errors.New("hash of media plaintext doesn't match")
+	ErrUnknownMediaType           = errors.New("unknown media type")
+	ErrNothingDownloadableFound   = errors.New("didn't find any attachments in message")
+)
+
+var (
+	ErrOriginalMessageSecretNotFound = errors.New("original message secret key not found")
+	ErrNotEncryptedReactionMessage   = errors.New("given message isn't an encrypted reaction message")
+	ErrNotEncryptedCommentMessage    = errors.New("given message isn't an encrypted comment message")
+	ErrNotSecretEncryptedMessage     = errors.New("given message isn't a secret encrypted message")
+	ErrNotPollUpdateMessage          = errors.New("given message isn't a poll update message")
+)
+
+type wrappedIQError struct {
+	HumanError error
+	IQError    error
+}
+
+func (err *wrappedIQError) Error() string {
+	return err.HumanError.Error()
+}
+
+func (err *wrappedIQError) Is(other error) bool {
+	return errors.Is(other, err.HumanError)
+}
+
+func (err *wrappedIQError) Unwrap() error {
+	return err.IQError
+}
+
+func wrapIQError(human, iq error) error {
+	return &wrappedIQError{human, iq}
+}
+
+// IQError is a generic error container for info queries
+type IQError struct {
+	Code      int
+	Text      string
+	ErrorNode *waBinary.Node
+	RawNode   *waBinary.Node
+}
+
+// Common errors returned by info queries for use with errors.Is
+var (
+	ErrIQBadRequest          error = &IQError{Code: 400, Text: "bad-request"}
+	ErrIQNotAuthorized       error = &IQError{Code: 401, Text: "not-authorized"}
+	ErrIQForbidden           error = &IQError{Code: 403, Text: "forbidden"}
+	ErrIQNotFound            error = &IQError{Code: 404, Text: "item-not-found"}
+	ErrIQNotAllowed          error = &IQError{Code: 405, Text: "not-allowed"}
+	ErrIQNotAcceptable       error = &IQError{Code: 406, Text: "not-acceptable"}
+	ErrIQGone                error = &IQError{Code: 410, Text: "gone"}
+	ErrIQResourceLimit       error = &IQError{Code: 419, Text: "resource-limit"}
+	ErrIQLocked              error = &IQError{Code: 423, Text: "locked"}
+	ErrIQRateOverLimit       error = &IQError{Code: 429, Text: "rate-overlimit"}
+	ErrIQInternalServerError error = &IQError{Code: 500, Text: "internal-server-error"}
+	ErrIQServiceUnavailable  error = &IQError{Code: 503, Text: "service-unavailable"}
+	ErrIQPartialServerError  error = &IQError{Code: 530, Text: "partial-server-error"}
+)
+
+func parseIQError(node *waBinary.Node) error {
+	var err IQError
+	err.RawNode = node
+	val, ok := node.GetOptionalChildByTag("error")
+	if ok {
+		err.ErrorNode = &val
+		ag := val.AttrGetter()
+		err.Code = ag.OptionalInt("code")
+		err.Text = ag.OptionalString("text")
+	}
+	return &err
+}
+
+func (iqe *IQError) Error() string {
+	if iqe.Code == 0 {
+		if iqe.ErrorNode != nil {
+			return fmt.Sprintf("info query returned unknown error: %s", iqe.ErrorNode.XMLString())
+		} else if iqe.RawNode != nil {
+			return fmt.Sprintf("info query returned unexpected response: %s", iqe.RawNode.XMLString())
+		} else {
+			return "unknown info query error"
+		}
+	}
+	return fmt.Sprintf("info query returned status %d: %s", iqe.Code, iqe.Text)
+}
+
+func (iqe *IQError) Is(other error) bool {
+	otherIQE, ok := other.(*IQError)
+	if !ok {
+		return false
+	} else if iqe.Code != 0 && otherIQE.Code != 0 {
+		return otherIQE.Code == iqe.Code && otherIQE.Text == iqe.Text
+	} else if iqe.ErrorNode != nil && otherIQE.ErrorNode != nil {
+		return iqe.ErrorNode.XMLString() == otherIQE.ErrorNode.XMLString()
+	} else {
+		return false
+	}
+}
+
+// ElementMissingError is returned by various functions that parse XML elements when a required element is missing.
+type ElementMissingError struct {
+	Tag string
+	In  string
+}
+
+func (eme *ElementMissingError) Error() string {
+	return fmt.Sprintf("missing <%s> element in %s", eme.Tag, eme.In)
+}
+
+var ErrIQDisconnected = &DisconnectedError{Action: "info query"}
+
+// DisconnectedError is returned if the websocket disconnects before an info query or other request gets a response.
+type DisconnectedError struct {
+	Action string
+	Node   *waBinary.Node
+}
+
+func (err *DisconnectedError) Error() string {
+	return fmt.Sprintf("websocket disconnected before %s returned response", err.Action)
+}
+
+func (err *DisconnectedError) Is(other error) bool {
+	otherDisc, ok := other.(*DisconnectedError)
+	if !ok {
+		return false
+	}
+	return otherDisc.Action == err.Action
+}

+ 33 - 0
go.mod

@@ -0,0 +1,33 @@
+module go.mau.fi/whatsmeow
+
+go 1.24.0
+
+toolchain go1.25.4
+
+require (
+	git.bobomao.top/joey/whatsmeow v0.0.0-20251206075006-439e905b5732
+	github.com/beeper/argo-go v1.1.2
+	github.com/coder/websocket v1.8.14
+	github.com/gogf/gf v1.16.9
+	github.com/golang/protobuf v1.5.0
+	github.com/google/uuid v1.6.0
+	github.com/rs/zerolog v1.34.0
+	github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6
+	go.mau.fi/libsignal v0.2.1
+	go.mau.fi/util v0.9.3
+	golang.org/x/crypto v0.44.0
+	golang.org/x/net v0.47.0
+	google.golang.org/protobuf v1.36.10
+)
+
+require (
+	filippo.io/edwards25519 v1.1.0 // indirect
+	github.com/elliotchance/orderedmap/v3 v3.1.0 // indirect
+	github.com/mattn/go-colorable v0.1.14 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 // indirect
+	github.com/vektah/gqlparser/v2 v2.5.27 // indirect
+	golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
+	golang.org/x/sys v0.38.0 // indirect
+	golang.org/x/text v0.31.0 // indirect
+)

+ 121 - 0
go.sum

@@ -0,0 +1,121 @@
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+git.bobomao.top/joey/whatsmeow v0.0.0-20251206075006-439e905b5732 h1:Bm9QAUbozZn9ttI5uzEnpgjk9YsYVrBmfQpezvV0714=
+git.bobomao.top/joey/whatsmeow v0.0.0-20251206075006-439e905b5732/go.mod h1:VQZxIyWuKSb2XqWDfrfO3rrUQsY6Jqe/g3EiByZhaJY=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
+github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
+github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
+github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
+github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
+github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
+github.com/beeper/argo-go v1.1.2 h1:UQI2G8F+NLfGTOmTUI0254pGKx/HUU/etbUGTJv91Fs=
+github.com/beeper/argo-go v1.1.2/go.mod h1:M+LJAnyowKVQ6Rdj6XYGEn+qcVFkb3R/MUpqkGR0hM4=
+github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
+github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
+github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/elliotchance/orderedmap/v3 v3.1.0 h1:j4DJ5ObEmMBt/lcwIecKcoRxIQUEnw0L804lXYDt/pg=
+github.com/elliotchance/orderedmap/v3 v3.1.0/go.mod h1:G+Hc2RwaZvJMcS4JpGCOyViCnGeKf0bTYCGTO4uhjSo=
+github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
+github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk=
+github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk=
+github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
+github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
+github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
+github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 h1:QTvNkZ5ylY0PGgA+Lih+GdboMLY/G9SEGLMEGVjTVA4=
+github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
+github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
+github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
+github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
+github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA=
+github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs=
+github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s=
+github.com/vektah/gqlparser/v2 v2.5.27/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
+go.mau.fi/libsignal v0.2.1 h1:vRZG4EzTn70XY6Oh/pVKrQGuMHBkAWlGRC22/85m9L0=
+go.mau.fi/libsignal v0.2.1/go.mod h1:iVvjrHyfQqWajOUaMEsIfo3IqgVMrhWcPiiEzk7NgoU=
+go.mau.fi/util v0.9.3 h1:aqNF8KDIN8bFpFbybSk+mEBil7IHeBwlujfyTnvP0uU=
+go.mau.fi/util v0.9.3/go.mod h1:krWWfBM1jWTb5f8NCa2TLqWMQuM81X7TGQjhMjBeXmQ=
+go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
+go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
+go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
+go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
+golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
+golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
+golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
+golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
+golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
+golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
+golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
+google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 1067 - 0
group.go

@@ -0,0 +1,1067 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"strings"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+const InviteLinkPrefix = "https://chat.whatsapp.com/"
+
+func (cli *Client) sendGroupIQ(ctx context.Context, iqType infoQueryType, jid types.JID, content waBinary.Node) (*waBinary.Node, error) {
+	return cli.sendIQ(ctx, infoQuery{
+		Namespace: "w:g2",
+		Type:      iqType,
+		To:        jid,
+		Content:   []waBinary.Node{content},
+	})
+}
+
+// ReqCreateGroup contains the request data for CreateGroup.
+type ReqCreateGroup struct {
+	// Group names are limited to 25 characters. A longer group name will cause a 406 not acceptable error.
+	Name string
+	// You don't need to include your own JID in the participants array, the WhatsApp servers will add it implicitly.
+	Participants []types.JID
+	// A create key can be provided to deduplicate the group create notification that will be triggered
+	// when the group is created. If provided, the JoinedGroup event will contain the same key.
+	CreateKey types.MessageID
+
+	types.GroupEphemeral
+	types.GroupAnnounce
+	types.GroupLocked
+	types.GroupMembershipApprovalMode
+	// Set IsParent to true to create a community instead of a normal group.
+	// When creating a community, the linked announcement group will be created automatically by the server.
+	types.GroupParent
+	// Set LinkedParentJID to create a group inside a community.
+	types.GroupLinkedParent
+}
+
+// CreateGroup creates a group on WhatsApp with the given name and participants.
+//
+// See ReqCreateGroup for parameters.
+func (cli *Client) CreateGroup(ctx context.Context, req ReqCreateGroup) (*types.GroupInfo, error) {
+	participantNodes := make([]waBinary.Node, len(req.Participants), len(req.Participants)+1)
+	for i, participant := range req.Participants {
+		participantNodes[i] = waBinary.Node{
+			Tag:   "participant",
+			Attrs: waBinary.Attrs{"jid": participant},
+		}
+		pt, err := cli.Store.PrivacyTokens.GetPrivacyToken(ctx, participant)
+		if err != nil {
+			return nil, fmt.Errorf("failed to get privacy token for participant %s: %v", participant, err)
+		} else if pt != nil {
+			participantNodes[i].Content = []waBinary.Node{{
+				Tag:     "privacy",
+				Content: pt.Token,
+			}}
+		}
+	}
+	if req.CreateKey == "" {
+		req.CreateKey = cli.GenerateMessageID()
+	}
+	if req.IsParent {
+		if req.DefaultMembershipApprovalMode == "" {
+			req.DefaultMembershipApprovalMode = "request_required"
+		}
+		participantNodes = append(participantNodes, waBinary.Node{
+			Tag: "parent",
+			Attrs: waBinary.Attrs{
+				"default_membership_approval_mode": req.DefaultMembershipApprovalMode,
+			},
+		})
+	} else if !req.LinkedParentJID.IsEmpty() {
+		participantNodes = append(participantNodes, waBinary.Node{
+			Tag:   "linked_parent",
+			Attrs: waBinary.Attrs{"jid": req.LinkedParentJID},
+		})
+	}
+	if req.IsLocked {
+		participantNodes = append(participantNodes, waBinary.Node{Tag: "locked"})
+	}
+	if req.IsAnnounce {
+		participantNodes = append(participantNodes, waBinary.Node{Tag: "announcement"})
+	}
+	if req.IsEphemeral {
+		participantNodes = append(participantNodes, waBinary.Node{
+			Tag: "ephemeral",
+			Attrs: waBinary.Attrs{
+				"expiration": req.DisappearingTimer,
+				"trigger":    "1", // TODO what's this?
+			},
+		})
+	}
+	if req.IsJoinApprovalRequired {
+		participantNodes = append(participantNodes, waBinary.Node{
+			Tag: "membership_approval_mode",
+			Content: []waBinary.Node{{
+				Tag:   "group_join",
+				Attrs: waBinary.Attrs{"state": "on"},
+			}},
+		})
+	}
+	// WhatsApp web doesn't seem to include the static prefix for these
+	key := strings.TrimPrefix(req.CreateKey, "3EB0")
+	resp, err := cli.sendGroupIQ(ctx, iqSet, types.GroupServerJID, waBinary.Node{
+		Tag: "create",
+		Attrs: waBinary.Attrs{
+			"subject": req.Name,
+			"key":     key,
+		},
+		Content: participantNodes,
+	})
+	if err != nil {
+		return nil, err
+	}
+	groupNode, ok := resp.GetOptionalChildByTag("group")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "group", In: "response to create group query"}
+	}
+	return cli.parseGroupNode(&groupNode)
+}
+
+// UnlinkGroup removes a child group from a parent community.
+func (cli *Client) UnlinkGroup(ctx context.Context, parent, child types.JID) error {
+	_, err := cli.sendGroupIQ(ctx, iqSet, parent, waBinary.Node{
+		Tag:   "unlink",
+		Attrs: waBinary.Attrs{"unlink_type": string(types.GroupLinkChangeTypeSub)},
+		Content: []waBinary.Node{{
+			Tag:   "group",
+			Attrs: waBinary.Attrs{"jid": child},
+		}},
+	})
+	return err
+}
+
+// LinkGroup adds an existing group as a child group in a community.
+//
+// To create a new group within a community, set LinkedParentJID in the CreateGroup request.
+func (cli *Client) LinkGroup(ctx context.Context, parent, child types.JID) error {
+	_, err := cli.sendGroupIQ(ctx, iqSet, parent, waBinary.Node{
+		Tag: "links",
+		Content: []waBinary.Node{{
+			Tag:   "link",
+			Attrs: waBinary.Attrs{"link_type": string(types.GroupLinkChangeTypeSub)},
+			Content: []waBinary.Node{{
+				Tag:   "group",
+				Attrs: waBinary.Attrs{"jid": child},
+			}},
+		}},
+	})
+	return err
+}
+
+// LeaveGroup leaves the specified group on WhatsApp.
+func (cli *Client) LeaveGroup(ctx context.Context, jid types.JID) error {
+	_, err := cli.sendGroupIQ(ctx, iqSet, types.GroupServerJID, waBinary.Node{
+		Tag: "leave",
+		Content: []waBinary.Node{{
+			Tag:   "group",
+			Attrs: waBinary.Attrs{"id": jid},
+		}},
+	})
+	return err
+}
+
+type ParticipantChange string
+
+const (
+	ParticipantChangeAdd     ParticipantChange = "add"
+	ParticipantChangeRemove  ParticipantChange = "remove"
+	ParticipantChangePromote ParticipantChange = "promote"
+	ParticipantChangeDemote  ParticipantChange = "demote"
+)
+
+// UpdateGroupParticipants can be used to add, remove, promote and demote members in a WhatsApp group.
+func (cli *Client) UpdateGroupParticipants(ctx context.Context, jid types.JID, participantChanges []types.JID, action ParticipantChange) ([]types.GroupParticipant, error) {
+	content := make([]waBinary.Node, len(participantChanges))
+	for i, participantJID := range participantChanges {
+		content[i] = waBinary.Node{
+			Tag:   "participant",
+			Attrs: waBinary.Attrs{"jid": participantJID},
+		}
+		if participantJID.Server == types.HiddenUserServer && action == ParticipantChangeAdd {
+			pn, err := cli.Store.LIDs.GetPNForLID(ctx, participantJID)
+			if err != nil {
+				return nil, fmt.Errorf("failed to get phone number for LID %s: %v", participantJID, err)
+			} else if !pn.IsEmpty() {
+				content[i].Attrs["phone_number"] = pn
+			}
+		}
+	}
+	resp, err := cli.sendGroupIQ(ctx, iqSet, jid, waBinary.Node{
+		Tag:     string(action),
+		Content: content,
+	})
+	if err != nil {
+		return nil, err
+	}
+	requestAction, ok := resp.GetOptionalChildByTag(string(action))
+	if !ok {
+		return nil, &ElementMissingError{Tag: string(action), In: "response to group participants update"}
+	}
+	requestParticipants := requestAction.GetChildrenByTag("participant")
+	participants := make([]types.GroupParticipant, len(requestParticipants))
+	for i, child := range requestParticipants {
+		participants[i] = parseParticipant(child.AttrGetter(), &child)
+	}
+	return participants, nil
+}
+
+// GetGroupRequestParticipants gets the list of participants that have requested to join the group.
+func (cli *Client) GetGroupRequestParticipants(ctx context.Context, jid types.JID) ([]types.GroupParticipantRequest, error) {
+	resp, err := cli.sendGroupIQ(ctx, iqGet, jid, waBinary.Node{
+		Tag: "membership_approval_requests",
+	})
+	if err != nil {
+		return nil, err
+	}
+	request, ok := resp.GetOptionalChildByTag("membership_approval_requests")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "membership_approval_requests", In: "response to group request participants query"}
+	}
+	requestParticipants := request.GetChildrenByTag("membership_approval_request")
+	participants := make([]types.GroupParticipantRequest, len(requestParticipants))
+	for i, req := range requestParticipants {
+		participants[i] = types.GroupParticipantRequest{
+			JID:         req.AttrGetter().JID("jid"),
+			RequestedAt: req.AttrGetter().UnixTime("request_time"),
+		}
+	}
+	return participants, nil
+}
+
+type ParticipantRequestChange string
+
+const (
+	ParticipantChangeApprove ParticipantRequestChange = "approve"
+	ParticipantChangeReject  ParticipantRequestChange = "reject"
+)
+
+// UpdateGroupRequestParticipants can be used to approve or reject requests to join the group.
+func (cli *Client) UpdateGroupRequestParticipants(ctx context.Context, jid types.JID, participantChanges []types.JID, action ParticipantRequestChange) ([]types.GroupParticipant, error) {
+	content := make([]waBinary.Node, len(participantChanges))
+	for i, participantJID := range participantChanges {
+		content[i] = waBinary.Node{
+			Tag:   "participant",
+			Attrs: waBinary.Attrs{"jid": participantJID},
+		}
+	}
+	resp, err := cli.sendGroupIQ(ctx, iqSet, jid, waBinary.Node{
+		Tag: "membership_requests_action",
+		Content: []waBinary.Node{{
+			Tag:     string(action),
+			Content: content,
+		}},
+	})
+	if err != nil {
+		return nil, err
+	}
+	request, ok := resp.GetOptionalChildByTag("membership_requests_action")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "membership_requests_action", In: "response to group request participants update"}
+	}
+	requestAction, ok := request.GetOptionalChildByTag(string(action))
+	if !ok {
+		return nil, &ElementMissingError{Tag: string(action), In: "response to group request participants update"}
+	}
+	requestParticipants := requestAction.GetChildrenByTag("participant")
+	participants := make([]types.GroupParticipant, len(requestParticipants))
+	for i, child := range requestParticipants {
+		participants[i] = parseParticipant(child.AttrGetter(), &child)
+	}
+	return participants, nil
+}
+
+// SetGroupPhoto updates the group picture/icon of the given group on WhatsApp.
+// The avatar should be a JPEG photo, other formats may be rejected with ErrInvalidImageFormat.
+// The bytes can be nil to remove the photo. Returns the new picture ID.
+func (cli *Client) SetGroupPhoto(ctx context.Context, jid types.JID, avatar []byte) (string, error) {
+	var content interface{}
+	if avatar != nil {
+		content = []waBinary.Node{{
+			Tag:     "picture",
+			Attrs:   waBinary.Attrs{"type": "image"},
+			Content: avatar,
+		}}
+	}
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "w:profile:picture",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Target:    jid,
+		Content:   content,
+	})
+	if errors.Is(err, ErrIQNotAcceptable) {
+		return "", wrapIQError(ErrInvalidImageFormat, err)
+	} else if err != nil {
+		return "", err
+	}
+	if avatar == nil {
+		return "remove", nil
+	}
+	pictureID, ok := resp.GetChildByTag("picture").Attrs["id"].(string)
+	if !ok {
+		return "", fmt.Errorf("didn't find picture ID in response")
+	}
+	return pictureID, nil
+}
+
+// SetGroupName updates the name (subject) of the given group on WhatsApp.
+func (cli *Client) SetGroupName(ctx context.Context, jid types.JID, name string) error {
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, waBinary.Node{
+		Tag:     "subject",
+		Content: []byte(name),
+	})
+	return err
+}
+
+// SetGroupTopic updates the topic (description) of the given group on WhatsApp.
+//
+// The previousID and newID fields are optional. If the previous ID is not specified, this will
+// automatically fetch the current group info to find the previous topic ID. If the new ID is not
+// specified, one will be generated with Client.GenerateMessageID().
+func (cli *Client) SetGroupTopic(ctx context.Context, jid types.JID, previousID, newID, topic string) error {
+	if previousID == "" {
+		oldInfo, err := cli.GetGroupInfo(ctx, jid)
+		if err != nil {
+			return fmt.Errorf("failed to get old group info to update topic: %v", err)
+		}
+		previousID = oldInfo.TopicID
+	}
+	if newID == "" {
+		newID = cli.GenerateMessageID()
+	}
+	attrs := waBinary.Attrs{
+		"id": newID,
+	}
+	if previousID != "" {
+		attrs["prev"] = previousID
+	}
+	content := []waBinary.Node{{
+		Tag:     "body",
+		Content: []byte(topic),
+	}}
+	if len(topic) == 0 {
+		attrs["delete"] = "true"
+		content = nil
+	}
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, waBinary.Node{
+		Tag:     "description",
+		Attrs:   attrs,
+		Content: content,
+	})
+	return err
+}
+
+// SetGroupLocked changes whether the group is locked (i.e. whether only admins can modify group info).
+func (cli *Client) SetGroupLocked(ctx context.Context, jid types.JID, locked bool) error {
+	tag := "locked"
+	if !locked {
+		tag = "unlocked"
+	}
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, waBinary.Node{Tag: tag})
+	return err
+}
+
+// SetGroupAnnounce changes whether the group is in announce mode (i.e. whether only admins can send messages).
+func (cli *Client) SetGroupAnnounce(ctx context.Context, jid types.JID, announce bool) error {
+	tag := "announcement"
+	if !announce {
+		tag = "not_announcement"
+	}
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, waBinary.Node{Tag: tag})
+	return err
+}
+
+// GetGroupInviteLink requests the invite link to the group from the WhatsApp servers.
+//
+// If reset is true, then the old invite link will be revoked and a new one generated.
+func (cli *Client) GetGroupInviteLink(ctx context.Context, jid types.JID, reset bool) (string, error) {
+	iqType := iqGet
+	if reset {
+		iqType = iqSet
+	}
+	resp, err := cli.sendGroupIQ(ctx, iqType, jid, waBinary.Node{Tag: "invite"})
+	if errors.Is(err, ErrIQNotAuthorized) {
+		return "", wrapIQError(ErrGroupInviteLinkUnauthorized, err)
+	} else if errors.Is(err, ErrIQNotFound) {
+		return "", wrapIQError(ErrGroupNotFound, err)
+	} else if errors.Is(err, ErrIQForbidden) {
+		return "", wrapIQError(ErrNotInGroup, err)
+	} else if err != nil {
+		return "", err
+	}
+	code, ok := resp.GetChildByTag("invite").Attrs["code"].(string)
+	if !ok {
+		return "", fmt.Errorf("didn't find invite code in response")
+	}
+	return InviteLinkPrefix + code, nil
+}
+
+// GetGroupInfoFromInvite gets the group info from an invite message.
+//
+// Note that this is specifically for invite messages, not invite links. Use GetGroupInfoFromLink for resolving chat.whatsapp.com links.
+func (cli *Client) GetGroupInfoFromInvite(ctx context.Context, jid, inviter types.JID, code string, expiration int64) (*types.GroupInfo, error) {
+	resp, err := cli.sendGroupIQ(ctx, iqGet, jid, waBinary.Node{
+		Tag: "query",
+		Content: []waBinary.Node{{
+			Tag: "add_request",
+			Attrs: waBinary.Attrs{
+				"code":       code,
+				"expiration": expiration,
+				"admin":      inviter,
+			},
+		}},
+	})
+	if err != nil {
+		return nil, err
+	}
+	groupNode, ok := resp.GetOptionalChildByTag("group")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "group", In: "response to invite group info query"}
+	}
+	return cli.parseGroupNode(&groupNode)
+}
+
+// JoinGroupWithInvite joins a group using an invite message.
+//
+// Note that this is specifically for invite messages, not invite links. Use JoinGroupWithLink for joining with chat.whatsapp.com links.
+func (cli *Client) JoinGroupWithInvite(ctx context.Context, jid, inviter types.JID, code string, expiration int64) error {
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, waBinary.Node{
+		Tag: "accept",
+		Attrs: waBinary.Attrs{
+			"code":       code,
+			"expiration": expiration,
+			"admin":      inviter,
+		},
+	})
+	return err
+}
+
+// GetGroupInfoFromLink resolves the given invite link and asks the WhatsApp servers for info about the group.
+// This will not cause the user to join the group.
+func (cli *Client) GetGroupInfoFromLink(ctx context.Context, code string) (*types.GroupInfo, error) {
+	code = strings.TrimPrefix(code, InviteLinkPrefix)
+	resp, err := cli.sendGroupIQ(ctx, iqGet, types.GroupServerJID, waBinary.Node{
+		Tag:   "invite",
+		Attrs: waBinary.Attrs{"code": code},
+	})
+	if errors.Is(err, ErrIQGone) {
+		return nil, wrapIQError(ErrInviteLinkRevoked, err)
+	} else if errors.Is(err, ErrIQNotAcceptable) {
+		return nil, wrapIQError(ErrInviteLinkInvalid, err)
+	} else if err != nil {
+		return nil, err
+	}
+	groupNode, ok := resp.GetOptionalChildByTag("group")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "group", In: "response to group link info query"}
+	}
+	return cli.parseGroupNode(&groupNode)
+}
+
+// JoinGroupWithLink joins the group using the given invite link.
+func (cli *Client) JoinGroupWithLink(ctx context.Context, code string) (types.JID, error) {
+	code = strings.TrimPrefix(code, InviteLinkPrefix)
+	resp, err := cli.sendGroupIQ(ctx, iqSet, types.GroupServerJID, waBinary.Node{
+		Tag:   "invite",
+		Attrs: waBinary.Attrs{"code": code},
+	})
+	if errors.Is(err, ErrIQGone) {
+		return types.EmptyJID, wrapIQError(ErrInviteLinkRevoked, err)
+	} else if errors.Is(err, ErrIQNotAcceptable) {
+		return types.EmptyJID, wrapIQError(ErrInviteLinkInvalid, err)
+	} else if err != nil {
+		return types.EmptyJID, err
+	}
+	membershipApprovalModeNode, ok := resp.GetOptionalChildByTag("membership_approval_request")
+	if ok {
+		return membershipApprovalModeNode.AttrGetter().JID("jid"), nil
+	}
+	groupNode, ok := resp.GetOptionalChildByTag("group")
+	if !ok {
+		return types.EmptyJID, &ElementMissingError{Tag: "group", In: "response to group link join query"}
+	}
+	return groupNode.AttrGetter().JID("jid"), nil
+}
+
+// GetJoinedGroups returns the list of groups the user is participating in.
+func (cli *Client) GetJoinedGroups(ctx context.Context) ([]*types.GroupInfo, error) {
+	resp, err := cli.sendGroupIQ(ctx, iqGet, types.GroupServerJID, waBinary.Node{
+		Tag: "participating",
+		Content: []waBinary.Node{
+			{Tag: "participants"},
+			{Tag: "description"},
+		},
+	})
+	if err != nil {
+		return nil, err
+	}
+	groups, ok := resp.GetOptionalChildByTag("groups")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "groups", In: "response to group list query"}
+	}
+	children := groups.GetChildren()
+	infos := make([]*types.GroupInfo, 0, len(children))
+	var allLIDPairs []store.LIDMapping
+	var allRedactedPhones []store.RedactedPhoneEntry
+	for _, child := range children {
+		if child.Tag != "group" {
+			cli.Log.Debugf("Unexpected child in group list response: %s", child.XMLString())
+			continue
+		}
+		parsed, parseErr := cli.parseGroupNode(&child)
+		if parseErr != nil {
+			cli.Log.Warnf("Error parsing group %s: %v", parsed.JID, parseErr)
+		}
+		lidPairs, redactedPhones := cli.cacheGroupInfo(parsed, true)
+		allLIDPairs = append(allLIDPairs, lidPairs...)
+		allRedactedPhones = append(allRedactedPhones, redactedPhones...)
+		infos = append(infos, parsed)
+	}
+	err = cli.Store.LIDs.PutManyLIDMappings(ctx, allLIDPairs)
+	if err != nil {
+		cli.Log.Warnf("Failed to store LID mappings from joined groups: %v", err)
+	}
+	err = cli.Store.Contacts.PutManyRedactedPhones(ctx, allRedactedPhones)
+	if err != nil {
+		cli.Log.Warnf("Failed to store redacted phones from joined groups: %v", err)
+	}
+	return infos, nil
+}
+
+// GetSubGroups gets the subgroups of the given community.
+func (cli *Client) GetSubGroups(ctx context.Context, community types.JID) ([]*types.GroupLinkTarget, error) {
+	res, err := cli.sendGroupIQ(ctx, iqGet, community, waBinary.Node{Tag: "sub_groups"})
+	if err != nil {
+		return nil, err
+	}
+	groups, ok := res.GetOptionalChildByTag("sub_groups")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "sub_groups", In: "response to subgroups query"}
+	}
+	var parsedGroups []*types.GroupLinkTarget
+	for _, child := range groups.GetChildren() {
+		if child.Tag == "group" {
+			parsedGroup, err := parseGroupLinkTargetNode(&child)
+			if err != nil {
+				return parsedGroups, fmt.Errorf("failed to parse group in subgroups list: %w", err)
+			}
+			parsedGroups = append(parsedGroups, &parsedGroup)
+		}
+	}
+	return parsedGroups, nil
+}
+
+// GetLinkedGroupsParticipants gets all the participants in the groups of the given community.
+func (cli *Client) GetLinkedGroupsParticipants(ctx context.Context, community types.JID) ([]types.JID, error) {
+	res, err := cli.sendGroupIQ(ctx, iqGet, community, waBinary.Node{Tag: "linked_groups_participants"})
+	if err != nil {
+		return nil, err
+	}
+	participants, ok := res.GetOptionalChildByTag("linked_groups_participants")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "linked_groups_participants", In: "response to community participants query"}
+	}
+	members, lidPairs := parseParticipantList(&participants)
+	if len(lidPairs) > 0 {
+		err = cli.Store.LIDs.PutManyLIDMappings(ctx, lidPairs)
+		if err != nil {
+			cli.Log.Warnf("Failed to store LID mappings for community participants: %v", err)
+		}
+	}
+	return members, nil
+}
+
+// GetGroupInfo requests basic info about a group chat from the WhatsApp servers.
+func (cli *Client) GetGroupInfo(ctx context.Context, jid types.JID) (*types.GroupInfo, error) {
+	return cli.getGroupInfo(ctx, jid, true)
+}
+
+func (cli *Client) cacheGroupInfo(groupInfo *types.GroupInfo, lock bool) ([]store.LIDMapping, []store.RedactedPhoneEntry) {
+	participants := make([]types.JID, len(groupInfo.Participants))
+	lidPairs := make([]store.LIDMapping, len(groupInfo.Participants))
+	redactedPhones := make([]store.RedactedPhoneEntry, 0)
+	for i, part := range groupInfo.Participants {
+		participants[i] = part.JID
+		if !part.PhoneNumber.IsEmpty() && !part.LID.IsEmpty() {
+			lidPairs[i] = store.LIDMapping{
+				LID: part.LID,
+				PN:  part.PhoneNumber,
+			}
+		}
+		if part.DisplayName != "" && !part.LID.IsEmpty() {
+			redactedPhones = append(redactedPhones, store.RedactedPhoneEntry{
+				JID:           part.LID,
+				RedactedPhone: part.DisplayName,
+			})
+		}
+	}
+	if lock {
+		cli.groupCacheLock.Lock()
+		defer cli.groupCacheLock.Unlock()
+	}
+	cli.groupCache[groupInfo.JID] = &groupMetaCache{
+		AddressingMode:             groupInfo.AddressingMode,
+		CommunityAnnouncementGroup: groupInfo.IsAnnounce && groupInfo.IsDefaultSubGroup,
+		Members:                    participants,
+	}
+	return lidPairs, redactedPhones
+}
+
+func (cli *Client) getGroupInfo(ctx context.Context, jid types.JID, lockParticipantCache bool) (*types.GroupInfo, error) {
+	res, err := cli.sendGroupIQ(ctx, iqGet, jid, waBinary.Node{
+		Tag:   "query",
+		Attrs: waBinary.Attrs{"request": "interactive"},
+	})
+	if errors.Is(err, ErrIQNotFound) {
+		return nil, wrapIQError(ErrGroupNotFound, err)
+	} else if errors.Is(err, ErrIQForbidden) {
+		return nil, wrapIQError(ErrNotInGroup, err)
+	} else if err != nil {
+		return nil, err
+	}
+
+	groupNode, ok := res.GetOptionalChildByTag("group")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "groups", In: "response to group info query"}
+	}
+	groupInfo, err := cli.parseGroupNode(&groupNode)
+	if err != nil {
+		return groupInfo, err
+	}
+	lidPairs, redactedPhones := cli.cacheGroupInfo(groupInfo, lockParticipantCache)
+	err = cli.Store.LIDs.PutManyLIDMappings(ctx, lidPairs)
+	if err != nil {
+		cli.Log.Warnf("Failed to store LID mappings for members of %s: %v", jid, err)
+	}
+	err = cli.Store.Contacts.PutManyRedactedPhones(ctx, redactedPhones)
+	if err != nil {
+		cli.Log.Warnf("Failed to store redacted phones for members of %s: %v", jid, err)
+	}
+	return groupInfo, nil
+}
+
+func (cli *Client) getCachedGroupData(ctx context.Context, jid types.JID) (*groupMetaCache, error) {
+	cli.groupCacheLock.Lock()
+	defer cli.groupCacheLock.Unlock()
+	if val, ok := cli.groupCache[jid]; ok {
+		return val, nil
+	}
+	_, err := cli.getGroupInfo(ctx, jid, false)
+	if err != nil {
+		return nil, err
+	}
+	return cli.groupCache[jid], nil
+}
+
+func parseParticipant(childAG *waBinary.AttrUtility, child *waBinary.Node) types.GroupParticipant {
+	pcpType := childAG.OptionalString("type")
+	participant := types.GroupParticipant{
+		IsAdmin:      pcpType == "admin" || pcpType == "superadmin",
+		IsSuperAdmin: pcpType == "superadmin",
+		JID:          childAG.JID("jid"),
+		DisplayName:  childAG.OptionalString("display_name"),
+	}
+	if participant.JID.Server == types.HiddenUserServer {
+		participant.LID = participant.JID
+		participant.PhoneNumber = childAG.OptionalJIDOrEmpty("phone_number")
+	} else if participant.JID.Server == types.DefaultUserServer {
+		participant.PhoneNumber = participant.JID
+		participant.LID = childAG.OptionalJIDOrEmpty("lid")
+	}
+	if errorCode := childAG.OptionalInt("error"); errorCode != 0 {
+		participant.Error = errorCode
+		addRequest, ok := child.GetOptionalChildByTag("add_request")
+		if ok {
+			addAG := addRequest.AttrGetter()
+			participant.AddRequest = &types.GroupParticipantAddRequest{
+				Code:       addAG.String("code"),
+				Expiration: addAG.UnixTime("expiration"),
+			}
+		}
+	}
+	return participant
+}
+
+func (cli *Client) parseGroupNode(groupNode *waBinary.Node) (*types.GroupInfo, error) {
+	var group types.GroupInfo
+	ag := groupNode.AttrGetter()
+
+	group.JID = types.NewJID(ag.String("id"), types.GroupServer)
+	group.OwnerJID = ag.OptionalJIDOrEmpty("creator")
+	group.OwnerPN = ag.OptionalJIDOrEmpty("creator_pn")
+
+	group.Name = ag.OptionalString("subject")
+	group.NameSetAt = ag.OptionalUnixTime("s_t")
+	group.NameSetBy = ag.OptionalJIDOrEmpty("s_o")
+	group.NameSetByPN = ag.OptionalJIDOrEmpty("s_o_pn")
+
+	group.GroupCreated = ag.UnixTime("creation")
+	group.CreatorCountryCode = ag.OptionalString("creator_country_code")
+
+	group.AnnounceVersionID = ag.OptionalString("a_v_id")
+	group.ParticipantVersionID = ag.OptionalString("p_v_id")
+	group.ParticipantCount = ag.OptionalInt("size")
+	group.AddressingMode = types.AddressingMode(ag.OptionalString("addressing_mode"))
+
+	for _, child := range groupNode.GetChildren() {
+		childAG := child.AttrGetter()
+		switch child.Tag {
+		case "participant":
+			group.Participants = append(group.Participants, parseParticipant(childAG, &child))
+		case "description":
+			body, bodyOK := child.GetOptionalChildByTag("body")
+			if bodyOK {
+				topicBytes, _ := body.Content.([]byte)
+				group.Topic = string(topicBytes)
+				group.TopicID = childAG.String("id")
+				group.TopicSetBy = childAG.OptionalJIDOrEmpty("participant")
+				group.TopicSetByPN = childAG.OptionalJIDOrEmpty("participant_pn") // TODO confirm field name
+				group.TopicSetAt = childAG.UnixTime("t")
+			}
+		case "announcement":
+			group.IsAnnounce = true
+		case "locked":
+			group.IsLocked = true
+		case "ephemeral":
+			group.IsEphemeral = true
+			group.DisappearingTimer = uint32(childAG.Uint64("expiration"))
+		case "member_add_mode":
+			modeBytes, _ := child.Content.([]byte)
+			group.MemberAddMode = types.GroupMemberAddMode(modeBytes)
+		case "linked_parent":
+			group.LinkedParentJID = childAG.JID("jid")
+		case "default_sub_group":
+			group.IsDefaultSubGroup = true
+		case "parent":
+			group.IsParent = true
+			group.DefaultMembershipApprovalMode = childAG.OptionalString("default_membership_approval_mode")
+		case "incognito":
+			group.IsIncognito = true
+		case "membership_approval_mode":
+			group.IsJoinApprovalRequired = true
+		case "suspended":
+			group.Suspended = true
+		default:
+			cli.Log.Debugf("Unknown element in group node %s: %s", group.JID.String(), child.XMLString())
+		}
+		if !childAG.OK() {
+			cli.Log.Warnf("Possibly failed to parse %s element in group node: %+v", child.Tag, childAG.Errors)
+		}
+	}
+
+	return &group, ag.Error()
+}
+
+func parseGroupLinkTargetNode(groupNode *waBinary.Node) (types.GroupLinkTarget, error) {
+	ag := groupNode.AttrGetter()
+	jidKey := ag.OptionalJIDOrEmpty("jid")
+	if jidKey.IsEmpty() {
+		jidKey = types.NewJID(ag.String("id"), types.GroupServer)
+	}
+	return types.GroupLinkTarget{
+		JID: jidKey,
+		GroupName: types.GroupName{
+			Name:      ag.OptionalString("subject"),
+			NameSetAt: ag.OptionalUnixTime("s_t"),
+		},
+		GroupIsDefaultSub: types.GroupIsDefaultSub{
+			IsDefaultSubGroup: groupNode.GetChildByTag("default_sub_group").Tag == "default_sub_group",
+		},
+	}, ag.Error()
+}
+
+func parseParticipantList(node *waBinary.Node) (participants []types.JID, lidPairs []store.LIDMapping) {
+	children := node.GetChildren()
+	participants = make([]types.JID, 0, len(children))
+	for _, child := range children {
+		jid, ok := child.Attrs["jid"].(types.JID)
+		if child.Tag != "participant" || !ok {
+			continue
+		}
+		participants = append(participants, jid)
+		if jid.Server == types.HiddenUserServer {
+			phoneNumber, ok := child.Attrs["phone_number"].(types.JID)
+			if ok && !phoneNumber.IsEmpty() {
+				lidPairs = append(lidPairs, store.LIDMapping{
+					LID: jid,
+					PN:  phoneNumber,
+				})
+			}
+		} else if jid.Server == types.DefaultUserServer {
+			lid, ok := child.Attrs["lid"].(types.JID)
+			if ok && !lid.IsEmpty() {
+				lidPairs = append(lidPairs, store.LIDMapping{
+					LID: lid,
+					PN:  jid,
+				})
+			}
+		}
+	}
+	return
+}
+
+func (cli *Client) parseGroupCreate(parentNode, node *waBinary.Node) (*events.JoinedGroup, []store.LIDMapping, []store.RedactedPhoneEntry, error) {
+	groupNode, ok := node.GetOptionalChildByTag("group")
+	if !ok {
+		return nil, nil, nil, fmt.Errorf("group create notification didn't contain group info")
+	}
+	var evt events.JoinedGroup
+	pag := parentNode.AttrGetter()
+	ag := node.AttrGetter()
+	evt.Reason = ag.OptionalString("reason")
+	evt.CreateKey = ag.OptionalString("key")
+	evt.Type = ag.OptionalString("type")
+	evt.Sender = pag.OptionalJID("participant")
+	evt.SenderPN = pag.OptionalJID("participant_pn")
+	evt.Notify = pag.OptionalString("notify")
+	info, err := cli.parseGroupNode(&groupNode)
+	if err != nil {
+		return nil, nil, nil, fmt.Errorf("failed to parse group info in create notification: %w", err)
+	}
+	evt.GroupInfo = *info
+	lidPairs, redactedPhones := cli.cacheGroupInfo(info, true)
+	return &evt, lidPairs, redactedPhones, nil
+}
+
+func (cli *Client) parseGroupChange(node *waBinary.Node) (*events.GroupInfo, []store.LIDMapping, error) {
+	var evt events.GroupInfo
+	ag := node.AttrGetter()
+	evt.JID = ag.JID("from")
+	evt.Notify = ag.OptionalString("notify")
+	evt.Sender = ag.OptionalJID("participant")
+	evt.SenderPN = ag.OptionalJID("participant_pn")
+	evt.Timestamp = ag.UnixTime("t")
+	if !ag.OK() {
+		return nil, nil, fmt.Errorf("group change doesn't contain required attributes: %w", ag.Error())
+	}
+
+	var lidPairs []store.LIDMapping
+	for _, child := range node.GetChildren() {
+		cag := child.AttrGetter()
+		if child.Tag == "add" || child.Tag == "remove" || child.Tag == "promote" || child.Tag == "demote" {
+			evt.PrevParticipantVersionID = cag.OptionalString("prev_v_id")
+			evt.ParticipantVersionID = cag.OptionalString("v_id")
+		}
+		switch child.Tag {
+		case "add":
+			evt.JoinReason = cag.OptionalString("reason")
+			evt.Join, lidPairs = parseParticipantList(&child)
+		case "remove":
+			evt.Leave, lidPairs = parseParticipantList(&child)
+		case "promote":
+			evt.Promote, lidPairs = parseParticipantList(&child)
+		case "demote":
+			evt.Demote, lidPairs = parseParticipantList(&child)
+		case "locked":
+			evt.Locked = &types.GroupLocked{IsLocked: true}
+		case "unlocked":
+			evt.Locked = &types.GroupLocked{IsLocked: false}
+		case "delete":
+			evt.Delete = &types.GroupDelete{Deleted: true, DeleteReason: cag.String("reason")}
+		case "subject":
+			evt.Name = &types.GroupName{
+				Name:        cag.String("subject"),
+				NameSetAt:   cag.UnixTime("s_t"),
+				NameSetBy:   cag.OptionalJIDOrEmpty("s_o"),
+				NameSetByPN: cag.OptionalJIDOrEmpty("s_o_pn"),
+			}
+		case "description":
+			var topicStr string
+			_, isDelete := child.GetOptionalChildByTag("delete")
+			if !isDelete {
+				topicChild := child.GetChildByTag("body")
+				topicBytes, ok := topicChild.Content.([]byte)
+				if !ok {
+					return nil, nil, fmt.Errorf("group change description has unexpected body: %s", topicChild.XMLString())
+				}
+				topicStr = string(topicBytes)
+			}
+			var setBy types.JID
+			if evt.Sender != nil {
+				setBy = *evt.Sender
+			}
+			evt.Topic = &types.GroupTopic{
+				Topic:        topicStr,
+				TopicID:      cag.String("id"),
+				TopicSetAt:   evt.Timestamp,
+				TopicSetBy:   setBy,
+				TopicDeleted: isDelete,
+			}
+		case "announcement":
+			evt.Announce = &types.GroupAnnounce{
+				IsAnnounce:        true,
+				AnnounceVersionID: cag.String("v_id"),
+			}
+		case "not_announcement":
+			evt.Announce = &types.GroupAnnounce{
+				IsAnnounce:        false,
+				AnnounceVersionID: cag.String("v_id"),
+			}
+		case "invite":
+			link := InviteLinkPrefix + cag.String("code")
+			evt.NewInviteLink = &link
+		case "ephemeral":
+			timer := uint32(cag.Uint64("expiration"))
+			evt.Ephemeral = &types.GroupEphemeral{
+				IsEphemeral:       true,
+				DisappearingTimer: timer,
+			}
+		case "not_ephemeral":
+			evt.Ephemeral = &types.GroupEphemeral{IsEphemeral: false}
+		case "link":
+			evt.Link = &types.GroupLinkChange{
+				Type: types.GroupLinkChangeType(cag.String("link_type")),
+			}
+			groupNode, ok := child.GetOptionalChildByTag("group")
+			if !ok {
+				return nil, nil, &ElementMissingError{Tag: "group", In: "group link"}
+			}
+			var err error
+			evt.Link.Group, err = parseGroupLinkTargetNode(&groupNode)
+			if err != nil {
+				return nil, nil, fmt.Errorf("failed to parse group link node in group change: %w", err)
+			}
+		case "unlink":
+			evt.Unlink = &types.GroupLinkChange{
+				Type:         types.GroupLinkChangeType(cag.String("unlink_type")),
+				UnlinkReason: types.GroupUnlinkReason(cag.String("unlink_reason")),
+			}
+			groupNode, ok := child.GetOptionalChildByTag("group")
+			if !ok {
+				return nil, nil, &ElementMissingError{Tag: "group", In: "group unlink"}
+			}
+			var err error
+			evt.Unlink.Group, err = parseGroupLinkTargetNode(&groupNode)
+			if err != nil {
+				return nil, nil, fmt.Errorf("failed to parse group unlink node in group change: %w", err)
+			}
+		case "membership_approval_mode":
+			evt.MembershipApprovalMode = &types.GroupMembershipApprovalMode{
+				IsJoinApprovalRequired: true,
+			}
+		case "suspended":
+			evt.Suspended = true
+		case "unsuspended":
+			evt.Unsuspended = true
+		default:
+			evt.UnknownChanges = append(evt.UnknownChanges, &child)
+		}
+		if !cag.OK() {
+			return nil, nil, fmt.Errorf("group change %s element doesn't contain required attributes: %w", child.Tag, cag.Error())
+		}
+	}
+	return &evt, lidPairs, nil
+}
+
+func (cli *Client) updateGroupParticipantCache(evt *events.GroupInfo) {
+	// TODO can the addressing mode change here?
+	if len(evt.Join) == 0 && len(evt.Leave) == 0 {
+		return
+	}
+	cli.groupCacheLock.Lock()
+	defer cli.groupCacheLock.Unlock()
+	cached, ok := cli.groupCache[evt.JID]
+	if !ok {
+		return
+	}
+Outer:
+	for _, jid := range evt.Join {
+		for _, existingJID := range cached.Members {
+			if jid == existingJID {
+				continue Outer
+			}
+		}
+		cached.Members = append(cached.Members, jid)
+	}
+	for _, jid := range evt.Leave {
+		for i, existingJID := range cached.Members {
+			if existingJID == jid {
+				cached.Members[i] = cached.Members[len(cached.Members)-1]
+				cached.Members = cached.Members[:len(cached.Members)-1]
+				break
+			}
+		}
+	}
+}
+
+func (cli *Client) parseGroupNotification(node *waBinary.Node) (any, []store.LIDMapping, []store.RedactedPhoneEntry, error) {
+	children := node.GetChildren()
+	if len(children) == 1 && children[0].Tag == "create" {
+		return cli.parseGroupCreate(node, &children[0])
+	} else {
+		groupChange, lidPairs, err := cli.parseGroupChange(node)
+		if err != nil {
+			return nil, nil, nil, err
+		}
+		cli.updateGroupParticipantCache(groupChange)
+		return groupChange, lidPairs, nil, nil
+	}
+}
+
+// SetGroupJoinApprovalMode sets the group join approval mode to 'on' or 'off'.
+func (cli *Client) SetGroupJoinApprovalMode(ctx context.Context, jid types.JID, mode bool) error {
+	modeStr := "off"
+	if mode {
+		modeStr = "on"
+	}
+
+	content := waBinary.Node{
+		Tag: "membership_approval_mode",
+		Content: []waBinary.Node{
+			{
+				Tag:   "group_join",
+				Attrs: waBinary.Attrs{"state": modeStr},
+			},
+		},
+	}
+
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, content)
+	return err
+}
+
+// SetGroupMemberAddMode sets the group member add mode to 'admin_add' or 'all_member_add'.
+func (cli *Client) SetGroupMemberAddMode(ctx context.Context, jid types.JID, mode types.GroupMemberAddMode) error {
+	if mode != types.GroupMemberAddModeAdmin && mode != types.GroupMemberAddModeAllMember {
+		return errors.New("invalid mode, must be 'admin_add' or 'all_member_add'")
+	}
+
+	content := waBinary.Node{
+		Tag:     "member_add_mode",
+		Content: []byte(mode),
+	}
+
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, content)
+	return err
+}
+
+// SetGroupDescription updates the group description.
+func (cli *Client) SetGroupDescription(ctx context.Context, jid types.JID, description string) error {
+	content := waBinary.Node{
+		Tag: "description",
+		Content: []waBinary.Node{
+			{
+				Tag:     "body",
+				Content: []byte(description),
+			},
+		},
+	}
+
+	_, err := cli.sendGroupIQ(ctx, iqSet, jid, content)
+	return err
+}

+ 166 - 0
handshake.go

@@ -0,0 +1,166 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"time"
+
+	"go.mau.fi/libsignal/ecc"
+	"google.golang.org/protobuf/proto"
+
+	"go.mau.fi/whatsmeow/proto/waCert"
+	"go.mau.fi/whatsmeow/proto/waWa6"
+	"go.mau.fi/whatsmeow/socket"
+	"go.mau.fi/whatsmeow/util/keys"
+)
+
+const NoiseHandshakeResponseTimeout = 20 * time.Second
+const WACertIssuerSerial = 0
+
+var WACertPubKey = [...]byte{0x14, 0x23, 0x75, 0x57, 0x4d, 0xa, 0x58, 0x71, 0x66, 0xaa, 0xe7, 0x1e, 0xbe, 0x51, 0x64, 0x37, 0xc4, 0xa2, 0x8b, 0x73, 0xe3, 0x69, 0x5c, 0x6c, 0xe1, 0xf7, 0xf9, 0x54, 0x5d, 0xa8, 0xee, 0x6b}
+
+// doHandshake implements the Noise_XX_25519_AESGCM_SHA256 handshake for the WhatsApp web API.
+func (cli *Client) doHandshake(ctx context.Context, fs *socket.FrameSocket, ephemeralKP keys.KeyPair) error {
+	nh := socket.NewNoiseHandshake()
+	nh.Start(socket.NoiseStartPattern, fs.Header)
+	nh.Authenticate(ephemeralKP.Pub[:])
+	data, err := proto.Marshal(&waWa6.HandshakeMessage{
+		ClientHello: &waWa6.HandshakeMessage_ClientHello{
+			Ephemeral: ephemeralKP.Pub[:],
+		},
+	})
+	if err != nil {
+		return fmt.Errorf("failed to marshal handshake message: %w", err)
+	}
+	err = fs.SendFrame(data)
+	if err != nil {
+		return fmt.Errorf("failed to send handshake message: %w", err)
+	}
+	var resp []byte
+	select {
+	case resp = <-fs.Frames:
+	case <-time.After(NoiseHandshakeResponseTimeout):
+		return fmt.Errorf("timed out waiting for handshake response")
+	}
+	var handshakeResponse waWa6.HandshakeMessage
+	err = proto.Unmarshal(resp, &handshakeResponse)
+	if err != nil {
+		return fmt.Errorf("failed to unmarshal handshake response: %w", err)
+	}
+	serverEphemeral := handshakeResponse.GetServerHello().GetEphemeral()
+	serverStaticCiphertext := handshakeResponse.GetServerHello().GetStatic()
+	certificateCiphertext := handshakeResponse.GetServerHello().GetPayload()
+	if len(serverEphemeral) != 32 || serverStaticCiphertext == nil || certificateCiphertext == nil {
+		return fmt.Errorf("missing parts of handshake response")
+	}
+	serverEphemeralArr := *(*[32]byte)(serverEphemeral)
+
+	nh.Authenticate(serverEphemeral)
+	err = nh.MixSharedSecretIntoKey(*ephemeralKP.Priv, serverEphemeralArr)
+	if err != nil {
+		return fmt.Errorf("failed to mix server ephemeral key in: %w", err)
+	}
+
+	staticDecrypted, err := nh.Decrypt(serverStaticCiphertext)
+	if err != nil {
+		return fmt.Errorf("failed to decrypt server static ciphertext: %w", err)
+	} else if len(staticDecrypted) != 32 {
+		return fmt.Errorf("unexpected length of server static plaintext %d (expected 32)", len(staticDecrypted))
+	}
+	err = nh.MixSharedSecretIntoKey(*ephemeralKP.Priv, *(*[32]byte)(staticDecrypted))
+	if err != nil {
+		return fmt.Errorf("failed to mix server static key in: %w", err)
+	}
+
+	certDecrypted, err := nh.Decrypt(certificateCiphertext)
+	if err != nil {
+		return fmt.Errorf("failed to decrypt noise certificate ciphertext: %w", err)
+	} else if err = verifyServerCert(certDecrypted, staticDecrypted); err != nil {
+		return fmt.Errorf("failed to verify server cert: %w", err)
+	}
+
+	encryptedPubkey := nh.Encrypt(cli.Store.NoiseKey.Pub[:])
+	err = nh.MixSharedSecretIntoKey(*cli.Store.NoiseKey.Priv, serverEphemeralArr)
+	if err != nil {
+		return fmt.Errorf("failed to mix noise private key in: %w", err)
+	}
+
+	var clientPayload *waWa6.ClientPayload
+	if cli.GetClientPayload != nil {
+		clientPayload = cli.GetClientPayload()
+	} else {
+		clientPayload = cli.Store.GetClientPayload()
+	}
+
+	clientFinishPayloadBytes, err := proto.Marshal(clientPayload)
+	if err != nil {
+		return fmt.Errorf("failed to marshal client finish payload: %w", err)
+	}
+	encryptedClientFinishPayload := nh.Encrypt(clientFinishPayloadBytes)
+	data, err = proto.Marshal(&waWa6.HandshakeMessage{
+		ClientFinish: &waWa6.HandshakeMessage_ClientFinish{
+			Static:  encryptedPubkey,
+			Payload: encryptedClientFinishPayload,
+		},
+	})
+	if err != nil {
+		return fmt.Errorf("failed to marshal handshake finish message: %w", err)
+	}
+	err = fs.SendFrame(data)
+	if err != nil {
+		return fmt.Errorf("failed to send handshake finish message: %w", err)
+	}
+
+	ns, err := nh.Finish(ctx, fs, cli.handleFrame, cli.onDisconnect)
+	if err != nil {
+		return fmt.Errorf("failed to create noise socket: %w", err)
+	}
+
+	cli.socket = ns
+
+	return nil
+}
+
+func verifyServerCert(certDecrypted, staticDecrypted []byte) error {
+	var certChain waCert.CertChain
+	err := proto.Unmarshal(certDecrypted, &certChain)
+	if err != nil {
+		return fmt.Errorf("failed to unmarshal noise certificate: %w", err)
+	}
+	var intermediateCertDetails, leafCertDetails waCert.CertChain_NoiseCertificate_Details
+	intermediateCertDetailsRaw := certChain.GetIntermediate().GetDetails()
+	intermediateCertSignature := certChain.GetIntermediate().GetSignature()
+	leafCertDetailsRaw := certChain.GetLeaf().GetDetails()
+	leafCertSignature := certChain.GetLeaf().GetSignature()
+	if intermediateCertDetailsRaw == nil || intermediateCertSignature == nil || leafCertDetailsRaw == nil || leafCertSignature == nil {
+		return fmt.Errorf("missing parts of noise certificate")
+	} else if len(intermediateCertSignature) != 64 {
+		return fmt.Errorf("unexpected length of intermediate cert signature %d (expected 64)", len(intermediateCertSignature))
+	} else if len(leafCertSignature) != 64 {
+		return fmt.Errorf("unexpected length of leaf cert signature %d (expected 64)", len(leafCertSignature))
+	} else if !ecc.VerifySignature(ecc.NewDjbECPublicKey(WACertPubKey), intermediateCertDetailsRaw, [64]byte(intermediateCertSignature)) {
+		return fmt.Errorf("failed to verify intermediate cert signature")
+	} else if err = proto.Unmarshal(intermediateCertDetailsRaw, &intermediateCertDetails); err != nil {
+		return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
+	} else if intermediateCertDetails.GetIssuerSerial() != WACertIssuerSerial {
+		return fmt.Errorf("unexpected intermediate issuer serial %d (expected %d)", intermediateCertDetails.GetIssuerSerial(), WACertIssuerSerial)
+	} else if len(intermediateCertDetails.GetKey()) != 32 {
+		return fmt.Errorf("unexpected length of intermediate cert key %d (expected 32)", len(intermediateCertDetails.GetKey()))
+	} else if !ecc.VerifySignature(ecc.NewDjbECPublicKey([32]byte(intermediateCertDetails.GetKey())), leafCertDetailsRaw, [64]byte(leafCertSignature)) {
+		return fmt.Errorf("failed to verify intermediate cert signature")
+	} else if err = proto.Unmarshal(leafCertDetailsRaw, &leafCertDetails); err != nil {
+		return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
+	} else if leafCertDetails.GetIssuerSerial() != intermediateCertDetails.GetSerial() {
+		return fmt.Errorf("unexpected leaf issuer serial %d (expected %d)", leafCertDetails.GetIssuerSerial(), intermediateCertDetails.GetSerial())
+	} else if !bytes.Equal(leafCertDetails.GetKey(), staticDecrypted) {
+		return fmt.Errorf("cert key doesn't match decrypted static")
+	}
+	return nil
+}

+ 736 - 0
internals.go

@@ -0,0 +1,736 @@
+// GENERATED BY internals_generate.go; DO NOT EDIT
+
+//go:generate go run internals_generate.go
+//go:generate goimports -local go.mau.fi/whatsmeow -w internals.go
+
+package whatsmeow
+
+import (
+	"context"
+	"encoding/json"
+	"io"
+	"net/http"
+	"time"
+
+	"go.mau.fi/libsignal/keys/prekey"
+
+	"go.mau.fi/whatsmeow/appstate"
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waCommon"
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/proto/waHistorySync"
+	"go.mau.fi/whatsmeow/proto/waMsgApplication"
+	"go.mau.fi/whatsmeow/proto/waMsgTransport"
+	"go.mau.fi/whatsmeow/proto/waServerSync"
+	"go.mau.fi/whatsmeow/socket"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+	"go.mau.fi/whatsmeow/util/keys"
+)
+
+type DangerousInternalClient struct {
+	c *Client
+}
+
+// DangerousInternals allows access to all unexported methods in Client.
+//
+// Deprecated: dangerous
+func (cli *Client) DangerousInternals() *DangerousInternalClient {
+	return &DangerousInternalClient{cli}
+}
+
+type DangerousInfoQuery = infoQuery
+type DangerousInfoQueryType = infoQueryType
+
+func (int *DangerousInternalClient) FetchAppState(ctx context.Context, name appstate.WAPatchName, fullSync, onlyIfNotSynced bool) ([]any, error) {
+	return int.c.fetchAppState(ctx, name, fullSync, onlyIfNotSynced)
+}
+
+func (int *DangerousInternalClient) ApplyAppStatePatches(ctx context.Context, name appstate.WAPatchName, state appstate.HashState, patches *appstate.PatchList, fullSync bool, eventsToDispatch *[]any) (appstate.HashState, error) {
+	return int.c.applyAppStatePatches(ctx, name, state, patches, fullSync, eventsToDispatch)
+}
+
+func (int *DangerousInternalClient) FilterContacts(mutations []appstate.Mutation) ([]appstate.Mutation, []store.ContactEntry) {
+	return int.c.filterContacts(mutations)
+}
+
+func (int *DangerousInternalClient) DispatchAppState(ctx context.Context, mutation appstate.Mutation, fullSync bool) (eventToDispatch any) {
+	return int.c.dispatchAppState(ctx, mutation, fullSync)
+}
+
+func (int *DangerousInternalClient) DownloadExternalAppStateBlob(ctx context.Context, ref *waServerSync.ExternalBlobReference) ([]byte, error) {
+	return int.c.downloadExternalAppStateBlob(ctx, ref)
+}
+
+func (int *DangerousInternalClient) FetchAppStatePatches(ctx context.Context, name appstate.WAPatchName, fromVersion uint64, snapshot bool) (*appstate.PatchList, error) {
+	return int.c.fetchAppStatePatches(ctx, name, fromVersion, snapshot)
+}
+
+func (int *DangerousInternalClient) RequestMissingAppStateKeys(ctx context.Context, patches *appstate.PatchList) {
+	int.c.requestMissingAppStateKeys(ctx, patches)
+}
+
+func (int *DangerousInternalClient) RequestAppStateKeys(ctx context.Context, rawKeyIDs [][]byte) {
+	int.c.requestAppStateKeys(ctx, rawKeyIDs)
+}
+
+func (int *DangerousInternalClient) SendAppState(ctx context.Context, patch appstate.PatchInfo, allowRetry bool) error {
+	return int.c.sendAppState(ctx, patch, allowRetry)
+}
+
+func (int *DangerousInternalClient) HandleDecryptedArmadillo(ctx context.Context, info *types.MessageInfo, decrypted []byte, retryCount int) (handlerFailed, protobufFailed bool) {
+	return int.c.handleDecryptedArmadillo(ctx, info, decrypted, retryCount)
+}
+
+func (int *DangerousInternalClient) GetBroadcastListParticipants(ctx context.Context, jid types.JID) ([]types.JID, error) {
+	return int.c.getBroadcastListParticipants(ctx, jid)
+}
+
+func (int *DangerousInternalClient) GetStatusBroadcastRecipients(ctx context.Context) ([]types.JID, error) {
+	return int.c.getStatusBroadcastRecipients(ctx)
+}
+
+func (int *DangerousInternalClient) HandleCallEvent(ctx context.Context, node *waBinary.Node) {
+	int.c.handleCallEvent(ctx, node)
+}
+
+func (int *DangerousInternalClient) SetTransport(transport *http.Transport, opt SetProxyOptions) {
+	int.c.setTransport(transport, opt)
+}
+
+func (int *DangerousInternalClient) GetSocketWaitChan() <-chan struct{} {
+	return int.c.getSocketWaitChan()
+}
+
+func (int *DangerousInternalClient) CloseSocketWaitChan() {
+	int.c.closeSocketWaitChan()
+}
+
+func (int *DangerousInternalClient) GetOwnID() types.JID {
+	return int.c.getOwnID()
+}
+
+func (int *DangerousInternalClient) GetOwnLID() types.JID {
+	return int.c.getOwnLID()
+}
+
+func (int *DangerousInternalClient) Connect(ctx context.Context) error {
+	return int.c.connect(ctx)
+}
+
+func (int *DangerousInternalClient) UnlockedConnect(ctx context.Context) error {
+	return int.c.unlockedConnect(ctx)
+}
+
+func (int *DangerousInternalClient) OnDisconnect(ctx context.Context, ns *socket.NoiseSocket, remote bool) {
+	int.c.onDisconnect(ctx, ns, remote)
+}
+
+func (int *DangerousInternalClient) ExpectDisconnect() {
+	int.c.expectDisconnect()
+}
+
+func (int *DangerousInternalClient) ResetExpectedDisconnect() {
+	int.c.resetExpectedDisconnect()
+}
+
+func (int *DangerousInternalClient) IsExpectedDisconnect() bool {
+	return int.c.isExpectedDisconnect()
+}
+
+func (int *DangerousInternalClient) AutoReconnect(ctx context.Context) {
+	int.c.autoReconnect(ctx)
+}
+
+func (int *DangerousInternalClient) UnlockedDisconnect() {
+	int.c.unlockedDisconnect()
+}
+
+func (int *DangerousInternalClient) HandleFrame(ctx context.Context, data []byte) {
+	int.c.handleFrame(ctx, data)
+}
+
+func (int *DangerousInternalClient) HandlerQueueLoop(evtCtx, connCtx context.Context) {
+	int.c.handlerQueueLoop(evtCtx, connCtx)
+}
+
+func (int *DangerousInternalClient) SendNodeAndGetData(ctx context.Context, node waBinary.Node) ([]byte, error) {
+	return int.c.sendNodeAndGetData(ctx, node)
+}
+
+func (int *DangerousInternalClient) SendNode(ctx context.Context, node waBinary.Node) error {
+	return int.c.sendNode(ctx, node)
+}
+
+func (int *DangerousInternalClient) DispatchEvent(evt any) (handlerFailed bool) {
+	return int.c.dispatchEvent(evt)
+}
+
+func (int *DangerousInternalClient) HandleStreamError(ctx context.Context, node *waBinary.Node) {
+	int.c.handleStreamError(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleIB(ctx context.Context, node *waBinary.Node) {
+	int.c.handleIB(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleConnectFailure(ctx context.Context, node *waBinary.Node) {
+	int.c.handleConnectFailure(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleConnectSuccess(ctx context.Context, node *waBinary.Node) {
+	int.c.handleConnectSuccess(ctx, node)
+}
+
+func (int *DangerousInternalClient) DownloadAndDecrypt(ctx context.Context, url string, mediaKey []byte, appInfo MediaType, fileLength int, fileEncSHA256, fileSHA256 []byte) (data []byte, err error) {
+	return int.c.downloadAndDecrypt(ctx, url, mediaKey, appInfo, fileLength, fileEncSHA256, fileSHA256)
+}
+
+func (int *DangerousInternalClient) DownloadPossiblyEncryptedMediaWithRetries(ctx context.Context, url string, checksum []byte) (file, mac []byte, err error) {
+	return int.c.downloadPossiblyEncryptedMediaWithRetries(ctx, url, checksum)
+}
+
+func (int *DangerousInternalClient) DoMediaDownloadRequest(ctx context.Context, url string) (*http.Response, error) {
+	return int.c.doMediaDownloadRequest(ctx, url)
+}
+
+func (int *DangerousInternalClient) DownloadMedia(ctx context.Context, url string) ([]byte, error) {
+	return int.c.downloadMedia(ctx, url)
+}
+
+func (int *DangerousInternalClient) DownloadEncryptedMedia(ctx context.Context, url string, checksum []byte) (file, mac []byte, err error) {
+	return int.c.downloadEncryptedMedia(ctx, url, checksum)
+}
+
+func (int *DangerousInternalClient) DownloadAndDecryptToFile(ctx context.Context, url string, mediaKey []byte, appInfo MediaType, fileLength int, fileEncSHA256, fileSHA256 []byte, file File) error {
+	return int.c.downloadAndDecryptToFile(ctx, url, mediaKey, appInfo, fileLength, fileEncSHA256, fileSHA256, file)
+}
+
+func (int *DangerousInternalClient) DownloadPossiblyEncryptedMediaWithRetriesToFile(ctx context.Context, url string, checksum []byte, file File) (mac []byte, err error) {
+	return int.c.downloadPossiblyEncryptedMediaWithRetriesToFile(ctx, url, checksum, file)
+}
+
+func (int *DangerousInternalClient) DownloadMediaToFile(ctx context.Context, url string, file io.Writer) (int64, []byte, error) {
+	return int.c.downloadMediaToFile(ctx, url, file)
+}
+
+func (int *DangerousInternalClient) DownloadEncryptedMediaToFile(ctx context.Context, url string, checksum []byte, file File) ([]byte, error) {
+	return int.c.downloadEncryptedMediaToFile(ctx, url, checksum, file)
+}
+
+func (int *DangerousInternalClient) SendGroupIQ(ctx context.Context, iqType infoQueryType, jid types.JID, content waBinary.Node) (*waBinary.Node, error) {
+	return int.c.sendGroupIQ(ctx, iqType, jid, content)
+}
+
+func (int *DangerousInternalClient) CacheGroupInfo(groupInfo *types.GroupInfo, lock bool) ([]store.LIDMapping, []store.RedactedPhoneEntry) {
+	return int.c.cacheGroupInfo(groupInfo, lock)
+}
+
+func (int *DangerousInternalClient) GetGroupInfo(ctx context.Context, jid types.JID, lockParticipantCache bool) (*types.GroupInfo, error) {
+	return int.c.getGroupInfo(ctx, jid, lockParticipantCache)
+}
+
+func (int *DangerousInternalClient) GetCachedGroupData(ctx context.Context, jid types.JID) (*groupMetaCache, error) {
+	return int.c.getCachedGroupData(ctx, jid)
+}
+
+func (int *DangerousInternalClient) ParseGroupNode(groupNode *waBinary.Node) (*types.GroupInfo, error) {
+	return int.c.parseGroupNode(groupNode)
+}
+
+func (int *DangerousInternalClient) ParseGroupCreate(parentNode, node *waBinary.Node) (*events.JoinedGroup, []store.LIDMapping, []store.RedactedPhoneEntry, error) {
+	return int.c.parseGroupCreate(parentNode, node)
+}
+
+func (int *DangerousInternalClient) ParseGroupChange(node *waBinary.Node) (*events.GroupInfo, []store.LIDMapping, error) {
+	return int.c.parseGroupChange(node)
+}
+
+func (int *DangerousInternalClient) UpdateGroupParticipantCache(evt *events.GroupInfo) {
+	int.c.updateGroupParticipantCache(evt)
+}
+
+func (int *DangerousInternalClient) ParseGroupNotification(node *waBinary.Node) (any, []store.LIDMapping, []store.RedactedPhoneEntry, error) {
+	return int.c.parseGroupNotification(node)
+}
+
+func (int *DangerousInternalClient) DoHandshake(ctx context.Context, fs *socket.FrameSocket, ephemeralKP keys.KeyPair) error {
+	return int.c.doHandshake(ctx, fs, ephemeralKP)
+}
+
+func (int *DangerousInternalClient) KeepAliveLoop(ctx, connCtx context.Context) {
+	int.c.keepAliveLoop(ctx, connCtx)
+}
+
+func (int *DangerousInternalClient) SendKeepAlive(ctx context.Context) (isSuccess, shouldContinue bool) {
+	return int.c.sendKeepAlive(ctx)
+}
+
+func (int *DangerousInternalClient) RefreshMediaConn(ctx context.Context, force bool) (*MediaConn, error) {
+	return int.c.refreshMediaConn(ctx, force)
+}
+
+func (int *DangerousInternalClient) QueryMediaConn(ctx context.Context) (*MediaConn, error) {
+	return int.c.queryMediaConn(ctx)
+}
+
+func (int *DangerousInternalClient) HandleMediaRetryNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleMediaRetryNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleEncryptedMessage(ctx context.Context, node *waBinary.Node) {
+	int.c.handleEncryptedMessage(ctx, node)
+}
+
+func (int *DangerousInternalClient) ParseMessageSource(node *waBinary.Node, requireParticipant bool) (source types.MessageSource, err error) {
+	return int.c.parseMessageSource(node, requireParticipant)
+}
+
+func (int *DangerousInternalClient) ParseMsgBotInfo(node waBinary.Node) (botInfo types.MsgBotInfo, err error) {
+	return int.c.parseMsgBotInfo(node)
+}
+
+func (int *DangerousInternalClient) ParseMsgMetaInfo(node waBinary.Node) (metaInfo types.MsgMetaInfo, err error) {
+	return int.c.parseMsgMetaInfo(node)
+}
+
+func (int *DangerousInternalClient) ParseMessageInfo(node *waBinary.Node) (*types.MessageInfo, error) {
+	return int.c.parseMessageInfo(node)
+}
+
+func (int *DangerousInternalClient) HandlePlaintextMessage(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) (handlerFailed bool) {
+	return int.c.handlePlaintextMessage(ctx, info, node)
+}
+
+func (int *DangerousInternalClient) MigrateSessionStore(ctx context.Context, pn, lid types.JID) {
+	int.c.migrateSessionStore(ctx, pn, lid)
+}
+
+func (int *DangerousInternalClient) DecryptMessages(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) {
+	int.c.decryptMessages(ctx, info, node)
+}
+
+func (int *DangerousInternalClient) ClearUntrustedIdentity(ctx context.Context, target types.JID) error {
+	return int.c.clearUntrustedIdentity(ctx, target)
+}
+
+func (int *DangerousInternalClient) BufferedDecrypt(ctx context.Context, ciphertext []byte, serverTimestamp time.Time, decrypt func(context.Context) ([]byte, error)) (plaintext []byte, ciphertextHash [32]byte, err error) {
+	return int.c.bufferedDecrypt(ctx, ciphertext, serverTimestamp, decrypt)
+}
+
+func (int *DangerousInternalClient) DecryptDM(ctx context.Context, child *waBinary.Node, from types.JID, isPreKey bool, serverTS time.Time) ([]byte, *[32]byte, error) {
+	return int.c.decryptDM(ctx, child, from, isPreKey, serverTS)
+}
+
+func (int *DangerousInternalClient) DecryptGroupMsg(ctx context.Context, child *waBinary.Node, from types.JID, chat types.JID, serverTS time.Time) ([]byte, *[32]byte, error) {
+	return int.c.decryptGroupMsg(ctx, child, from, chat, serverTS)
+}
+
+func (int *DangerousInternalClient) HandleSenderKeyDistributionMessage(ctx context.Context, chat, from types.JID, axolotlSKDM []byte) {
+	int.c.handleSenderKeyDistributionMessage(ctx, chat, from, axolotlSKDM)
+}
+
+func (int *DangerousInternalClient) HandleHistorySyncNotificationLoop() {
+	int.c.handleHistorySyncNotificationLoop()
+}
+
+func (int *DangerousInternalClient) HandleAppStateSyncKeyShare(ctx context.Context, keys *waE2E.AppStateSyncKeyShare) {
+	int.c.handleAppStateSyncKeyShare(ctx, keys)
+}
+
+func (int *DangerousInternalClient) HandlePlaceholderResendResponse(msg *waE2E.PeerDataOperationRequestResponseMessage) (ok bool) {
+	return int.c.handlePlaceholderResendResponse(msg)
+}
+
+func (int *DangerousInternalClient) HandleProtocolMessage(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message) (ok bool) {
+	return int.c.handleProtocolMessage(ctx, info, msg)
+}
+
+func (int *DangerousInternalClient) ProcessProtocolParts(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message) (ok bool) {
+	return int.c.processProtocolParts(ctx, info, msg)
+}
+
+func (int *DangerousInternalClient) StoreMessageSecret(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message) {
+	int.c.storeMessageSecret(ctx, info, msg)
+}
+
+func (int *DangerousInternalClient) StoreHistoricalMessageSecrets(ctx context.Context, conversations []*waHistorySync.Conversation) {
+	int.c.storeHistoricalMessageSecrets(ctx, conversations)
+}
+
+func (int *DangerousInternalClient) StoreLIDSyncMessage(ctx context.Context, msg []byte) {
+	int.c.storeLIDSyncMessage(ctx, msg)
+}
+
+func (int *DangerousInternalClient) StoreGlobalSettings(ctx context.Context, settings *waHistorySync.GlobalSettings) {
+	int.c.storeGlobalSettings(ctx, settings)
+}
+
+func (int *DangerousInternalClient) StoreHistoricalPNLIDMappings(ctx context.Context, mappings []*waHistorySync.PhoneNumberToLIDMapping) {
+	int.c.storeHistoricalPNLIDMappings(ctx, mappings)
+}
+
+func (int *DangerousInternalClient) HandleDecryptedMessage(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message, retryCount int) bool {
+	return int.c.handleDecryptedMessage(ctx, info, msg, retryCount)
+}
+
+func (int *DangerousInternalClient) SendProtocolMessageReceipt(ctx context.Context, id types.MessageID, msgType types.ReceiptType) {
+	int.c.sendProtocolMessageReceipt(ctx, id, msgType)
+}
+
+func (int *DangerousInternalClient) DecryptMsgSecret(ctx context.Context, msg *events.Message, useCase MsgSecretType, encrypted messageEncryptedSecret, origMsgKey *waCommon.MessageKey) ([]byte, error) {
+	return int.c.decryptMsgSecret(ctx, msg, useCase, encrypted, origMsgKey)
+}
+
+func (int *DangerousInternalClient) EncryptMsgSecret(ctx context.Context, ownID, chat, origSender types.JID, origMsgID types.MessageID, useCase MsgSecretType, plaintext []byte) (ciphertext, iv []byte, err error) {
+	return int.c.encryptMsgSecret(ctx, ownID, chat, origSender, origMsgID, useCase, plaintext)
+}
+
+func (int *DangerousInternalClient) DecryptBotMessage(ctx context.Context, messageSecret []byte, msMsg messageEncryptedSecret, messageID types.MessageID, targetSenderJID types.JID, info *types.MessageInfo) ([]byte, error) {
+	return int.c.decryptBotMessage(ctx, messageSecret, msMsg, messageID, targetSenderJID, info)
+}
+
+func (int *DangerousInternalClient) SendMexIQ(ctx context.Context, queryID string, variables any) (json.RawMessage, error) {
+	return int.c.sendMexIQ(ctx, queryID, variables)
+}
+
+func (int *DangerousInternalClient) GetNewsletterInfo(ctx context.Context, input map[string]any, fetchViewerMeta bool) (*types.NewsletterMetadata, error) {
+	return int.c.getNewsletterInfo(ctx, input, fetchViewerMeta)
+}
+
+func (int *DangerousInternalClient) HandleEncryptNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleEncryptNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleAppStateNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleAppStateNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandlePictureNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handlePictureNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleDeviceNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleDeviceNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleFBDeviceNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleFBDeviceNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleOwnDevicesNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleOwnDevicesNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleBlocklist(ctx context.Context, node *waBinary.Node) {
+	int.c.handleBlocklist(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleAccountSyncNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleAccountSyncNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandlePrivacyTokenNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handlePrivacyTokenNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) ParseNewsletterMessages(node *waBinary.Node) []*types.NewsletterMessage {
+	return int.c.parseNewsletterMessages(node)
+}
+
+func (int *DangerousInternalClient) HandleNewsletterNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleNewsletterNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleMexNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleMexNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleStatusNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleStatusNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleNotification(ctx context.Context, node *waBinary.Node) {
+	int.c.handleNotification(ctx, node)
+}
+
+func (int *DangerousInternalClient) TryHandleCodePairNotification(ctx context.Context, parentNode *waBinary.Node) {
+	int.c.tryHandleCodePairNotification(ctx, parentNode)
+}
+
+func (int *DangerousInternalClient) HandleCodePairNotification(ctx context.Context, parentNode *waBinary.Node) error {
+	return int.c.handleCodePairNotification(ctx, parentNode)
+}
+
+func (int *DangerousInternalClient) HandleIQ(ctx context.Context, node *waBinary.Node) {
+	int.c.handleIQ(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandlePairDevice(ctx context.Context, node *waBinary.Node) {
+	int.c.handlePairDevice(ctx, node)
+}
+
+func (int *DangerousInternalClient) MakeQRData(ref string) string {
+	return int.c.makeQRData(ref)
+}
+
+func (int *DangerousInternalClient) HandlePairSuccess(ctx context.Context, node *waBinary.Node) {
+	int.c.handlePairSuccess(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandlePair(ctx context.Context, deviceIdentityBytes []byte, reqID, businessName, platform string, jid, lid types.JID) error {
+	return int.c.handlePair(ctx, deviceIdentityBytes, reqID, businessName, platform, jid, lid)
+}
+
+func (int *DangerousInternalClient) SendPairError(ctx context.Context, id string, code int, text string) {
+	int.c.sendPairError(ctx, id, code, text)
+}
+
+func (int *DangerousInternalClient) GetServerPreKeyCount(ctx context.Context) (int, error) {
+	return int.c.getServerPreKeyCount(ctx)
+}
+
+func (int *DangerousInternalClient) UploadPreKeys(ctx context.Context, initialUpload bool) {
+	int.c.uploadPreKeys(ctx, initialUpload)
+}
+
+func (int *DangerousInternalClient) FetchPreKeysNoError(ctx context.Context, retryDevices []types.JID) map[types.JID]*prekey.Bundle {
+	return int.c.fetchPreKeysNoError(ctx, retryDevices)
+}
+
+func (int *DangerousInternalClient) FetchPreKeys(ctx context.Context, users []types.JID) (map[types.JID]preKeyResp, error) {
+	return int.c.fetchPreKeys(ctx, users)
+}
+
+func (int *DangerousInternalClient) HandleChatState(ctx context.Context, node *waBinary.Node) {
+	int.c.handleChatState(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandlePresence(ctx context.Context, node *waBinary.Node) {
+	int.c.handlePresence(ctx, node)
+}
+
+func (int *DangerousInternalClient) ParsePrivacySettings(privacyNode *waBinary.Node, settings *types.PrivacySettings) *events.PrivacySettings {
+	return int.c.parsePrivacySettings(privacyNode, settings)
+}
+
+func (int *DangerousInternalClient) HandlePrivacySettingsNotification(ctx context.Context, privacyNode *waBinary.Node) {
+	int.c.handlePrivacySettingsNotification(ctx, privacyNode)
+}
+
+func (int *DangerousInternalClient) HandleReceipt(ctx context.Context, node *waBinary.Node) {
+	int.c.handleReceipt(ctx, node)
+}
+
+func (int *DangerousInternalClient) HandleGroupedReceipt(partialReceipt events.Receipt, participants *waBinary.Node) {
+	int.c.handleGroupedReceipt(partialReceipt, participants)
+}
+
+func (int *DangerousInternalClient) ParseReceipt(node *waBinary.Node) (*events.Receipt, error) {
+	return int.c.parseReceipt(node)
+}
+
+func (int *DangerousInternalClient) BackgroundIfAsyncAck(fn func()) {
+	int.c.backgroundIfAsyncAck(fn)
+}
+
+func (int *DangerousInternalClient) MaybeDeferredAck(ctx context.Context, node *waBinary.Node) func(...*bool) {
+	return int.c.maybeDeferredAck(ctx, node)
+}
+
+func (int *DangerousInternalClient) SendAck(ctx context.Context, node *waBinary.Node, error int) {
+	int.c.sendAck(ctx, node, error)
+}
+
+func (int *DangerousInternalClient) SendMessageReceipt(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) {
+	int.c.sendMessageReceipt(ctx, info, node)
+}
+
+func (int *DangerousInternalClient) GenerateRequestID() string {
+	return int.c.generateRequestID()
+}
+
+func (int *DangerousInternalClient) ClearResponseWaiters(node *waBinary.Node) {
+	int.c.clearResponseWaiters(node)
+}
+
+func (int *DangerousInternalClient) WaitResponse(reqID string) chan *waBinary.Node {
+	return int.c.waitResponse(reqID)
+}
+
+func (int *DangerousInternalClient) CancelResponse(reqID string, ch chan *waBinary.Node) {
+	int.c.cancelResponse(reqID, ch)
+}
+
+func (int *DangerousInternalClient) ReceiveResponse(ctx context.Context, data *waBinary.Node) bool {
+	return int.c.receiveResponse(ctx, data)
+}
+
+func (int *DangerousInternalClient) SendIQAsyncAndGetData(ctx context.Context, query *infoQuery) (<-chan *waBinary.Node, []byte, error) {
+	return int.c.sendIQAsyncAndGetData(ctx, query)
+}
+
+func (int *DangerousInternalClient) SendIQAsync(ctx context.Context, query infoQuery) (<-chan *waBinary.Node, error) {
+	return int.c.sendIQAsync(ctx, query)
+}
+
+func (int *DangerousInternalClient) SendIQ(ctx context.Context, query infoQuery) (*waBinary.Node, error) {
+	return int.c.sendIQ(ctx, query)
+}
+
+func (int *DangerousInternalClient) RetryFrame(ctx context.Context, reqType, id string, data []byte, origResp *waBinary.Node, timeout time.Duration) (*waBinary.Node, error) {
+	return int.c.retryFrame(ctx, reqType, id, data, origResp, timeout)
+}
+
+func (int *DangerousInternalClient) AddRecentMessage(to types.JID, id types.MessageID, wa *waE2E.Message, fb *waMsgApplication.MessageApplication) {
+	int.c.addRecentMessage(to, id, wa, fb)
+}
+
+func (int *DangerousInternalClient) GetRecentMessage(to types.JID, id types.MessageID) RecentMessage {
+	return int.c.getRecentMessage(to, id)
+}
+
+func (int *DangerousInternalClient) GetMessageForRetry(ctx context.Context, receipt *events.Receipt, messageID types.MessageID) (RecentMessage, error) {
+	return int.c.getMessageForRetry(ctx, receipt, messageID)
+}
+
+func (int *DangerousInternalClient) ShouldRecreateSession(ctx context.Context, retryCount int, jid types.JID) (reason string, recreate bool) {
+	return int.c.shouldRecreateSession(ctx, retryCount, jid)
+}
+
+func (int *DangerousInternalClient) HandleRetryReceipt(ctx context.Context, receipt *events.Receipt, node *waBinary.Node) error {
+	return int.c.handleRetryReceipt(ctx, receipt, node)
+}
+
+func (int *DangerousInternalClient) CancelDelayedRequestFromPhone(msgID types.MessageID) {
+	int.c.cancelDelayedRequestFromPhone(msgID)
+}
+
+func (int *DangerousInternalClient) DelayedRequestMessageFromPhone(info *types.MessageInfo) {
+	int.c.delayedRequestMessageFromPhone(info)
+}
+
+func (int *DangerousInternalClient) ImmediateRequestMessageFromPhone(ctx context.Context, info *types.MessageInfo) {
+	int.c.immediateRequestMessageFromPhone(ctx, info)
+}
+
+func (int *DangerousInternalClient) ClearDelayedMessageRequests() {
+	int.c.clearDelayedMessageRequests()
+}
+
+func (int *DangerousInternalClient) SendRetryReceipt(ctx context.Context, node *waBinary.Node, info *types.MessageInfo, forceIncludeIdentity bool) {
+	int.c.sendRetryReceipt(ctx, node, info, forceIncludeIdentity)
+}
+
+func (int *DangerousInternalClient) SendGroupV3(ctx context.Context, to, ownID types.JID, id types.MessageID, messageApp []byte, msgAttrs messageAttrs, frankingTag []byte, timings *MessageDebugTimings) (string, []byte, error) {
+	return int.c.sendGroupV3(ctx, to, ownID, id, messageApp, msgAttrs, frankingTag, timings)
+}
+
+func (int *DangerousInternalClient) SendDMV3(ctx context.Context, to, ownID types.JID, id types.MessageID, messageApp []byte, msgAttrs messageAttrs, frankingTag []byte, timings *MessageDebugTimings) ([]byte, string, error) {
+	return int.c.sendDMV3(ctx, to, ownID, id, messageApp, msgAttrs, frankingTag, timings)
+}
+
+func (int *DangerousInternalClient) PrepareMessageNodeV3(ctx context.Context, to, ownID types.JID, id types.MessageID, payload *waMsgTransport.MessageTransport_Payload, skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage, msgAttrs messageAttrs, frankingTag []byte, participants []types.JID, timings *MessageDebugTimings) (*waBinary.Node, []types.JID, error) {
+	return int.c.prepareMessageNodeV3(ctx, to, ownID, id, payload, skdm, msgAttrs, frankingTag, participants, timings)
+}
+
+func (int *DangerousInternalClient) EncryptMessageForDevicesV3(ctx context.Context, allDevices []types.JID, ownID types.JID, id string, payload *waMsgTransport.MessageTransport_Payload, skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage, dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage, encAttrs waBinary.Attrs) ([]waBinary.Node, error) {
+	return int.c.encryptMessageForDevicesV3(ctx, allDevices, ownID, id, payload, skdm, dsm, encAttrs)
+}
+
+func (int *DangerousInternalClient) EncryptMessageForDeviceAndWrapV3(ctx context.Context, payload *waMsgTransport.MessageTransport_Payload, skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage, dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage, to types.JID, bundle *prekey.Bundle, encAttrs waBinary.Attrs) (*waBinary.Node, error) {
+	return int.c.encryptMessageForDeviceAndWrapV3(ctx, payload, skdm, dsm, to, bundle, encAttrs)
+}
+
+func (int *DangerousInternalClient) EncryptMessageForDeviceV3(ctx context.Context, payload *waMsgTransport.MessageTransport_Payload, skdm *waMsgTransport.MessageTransport_Protocol_Ancillary_SenderKeyDistributionMessage, dsm *waMsgTransport.MessageTransport_Protocol_Integral_DeviceSentMessage, to types.JID, bundle *prekey.Bundle, extraAttrs waBinary.Attrs) (*waBinary.Node, error) {
+	return int.c.encryptMessageForDeviceV3(ctx, payload, skdm, dsm, to, bundle, extraAttrs)
+}
+
+func (int *DangerousInternalClient) SendNewsletter(ctx context.Context, to types.JID, id types.MessageID, message *waE2E.Message, mediaID string, timings *MessageDebugTimings) ([]byte, error) {
+	return int.c.sendNewsletter(ctx, to, id, message, mediaID, timings)
+}
+
+func (int *DangerousInternalClient) SendGroup(ctx context.Context, ownID, to types.JID, participants []types.JID, id types.MessageID, message *waE2E.Message, timings *MessageDebugTimings, extraParams nodeExtraParams) (string, []byte, error) {
+	return int.c.sendGroup(ctx, ownID, to, participants, id, message, timings, extraParams)
+}
+
+func (int *DangerousInternalClient) SendPeerMessage(ctx context.Context, to types.JID, id types.MessageID, message *waE2E.Message, timings *MessageDebugTimings) ([]byte, error) {
+	return int.c.sendPeerMessage(ctx, to, id, message, timings)
+}
+
+func (int *DangerousInternalClient) SendDM(ctx context.Context, ownID, to types.JID, id types.MessageID, message *waE2E.Message, timings *MessageDebugTimings, extraParams nodeExtraParams) (string, []byte, error) {
+	return int.c.sendDM(ctx, ownID, to, id, message, timings, extraParams)
+}
+
+func (int *DangerousInternalClient) PreparePeerMessageNode(ctx context.Context, to types.JID, id types.MessageID, message *waE2E.Message, timings *MessageDebugTimings) (*waBinary.Node, error) {
+	return int.c.preparePeerMessageNode(ctx, to, id, message, timings)
+}
+
+func (int *DangerousInternalClient) GetMessageContent(baseNode waBinary.Node, message *waE2E.Message, msgAttrs waBinary.Attrs, includeIdentity bool, extraParams nodeExtraParams) []waBinary.Node {
+	return int.c.getMessageContent(baseNode, message, msgAttrs, includeIdentity, extraParams)
+}
+
+func (int *DangerousInternalClient) PrepareMessageNode(ctx context.Context, to types.JID, id types.MessageID, message *waE2E.Message, participants []types.JID, plaintext, dsmPlaintext []byte, timings *MessageDebugTimings, extraParams nodeExtraParams) (*waBinary.Node, []types.JID, error) {
+	return int.c.prepareMessageNode(ctx, to, id, message, participants, plaintext, dsmPlaintext, timings, extraParams)
+}
+
+func (int *DangerousInternalClient) MakeDeviceIdentityNode() waBinary.Node {
+	return int.c.makeDeviceIdentityNode()
+}
+
+func (int *DangerousInternalClient) EncryptMessageForDevices(ctx context.Context, allDevices []types.JID, id string, msgPlaintext, dsmPlaintext []byte, encAttrs waBinary.Attrs) ([]waBinary.Node, bool, error) {
+	return int.c.encryptMessageForDevices(ctx, allDevices, id, msgPlaintext, dsmPlaintext, encAttrs)
+}
+
+func (int *DangerousInternalClient) EncryptMessageForDeviceAndWrap(ctx context.Context, plaintext []byte, wireIdentity, encryptionIdentity types.JID, bundle *prekey.Bundle, encAttrs waBinary.Attrs, existingSessions map[string]bool) (*waBinary.Node, bool, error) {
+	return int.c.encryptMessageForDeviceAndWrap(ctx, plaintext, wireIdentity, encryptionIdentity, bundle, encAttrs, existingSessions)
+}
+
+func (int *DangerousInternalClient) EncryptMessageForDevice(ctx context.Context, plaintext []byte, to types.JID, bundle *prekey.Bundle, extraAttrs waBinary.Attrs, existingSessions map[string]bool) (*waBinary.Node, bool, error) {
+	return int.c.encryptMessageForDevice(ctx, plaintext, to, bundle, extraAttrs, existingSessions)
+}
+
+func (int *DangerousInternalClient) RawUpload(ctx context.Context, dataToUpload io.Reader, uploadSize uint64, fileHash []byte, appInfo MediaType, newsletter bool, resp *UploadResponse) error {
+	return int.c.rawUpload(ctx, dataToUpload, uploadSize, fileHash, appInfo, newsletter, resp)
+}
+
+func (int *DangerousInternalClient) ParseBusinessProfile(node *waBinary.Node) (*types.BusinessProfile, error) {
+	return int.c.parseBusinessProfile(node)
+}
+
+func (int *DangerousInternalClient) HandleHistoricalPushNames(ctx context.Context, names []*waHistorySync.Pushname) {
+	int.c.handleHistoricalPushNames(ctx, names)
+}
+
+func (int *DangerousInternalClient) UpdatePushName(ctx context.Context, user, userAlt types.JID, messageInfo *types.MessageInfo, name string) {
+	int.c.updatePushName(ctx, user, userAlt, messageInfo, name)
+}
+
+func (int *DangerousInternalClient) UpdateBusinessName(ctx context.Context, user, userAlt types.JID, messageInfo *types.MessageInfo, name string) {
+	int.c.updateBusinessName(ctx, user, userAlt, messageInfo, name)
+}
+
+func (int *DangerousInternalClient) GetFBIDDevicesInternal(ctx context.Context, jids []types.JID) (*waBinary.Node, error) {
+	return int.c.getFBIDDevicesInternal(ctx, jids)
+}
+
+func (int *DangerousInternalClient) GetFBIDDevices(ctx context.Context, jids []types.JID) ([]types.JID, error) {
+	return int.c.getFBIDDevices(ctx, jids)
+}
+
+func (int *DangerousInternalClient) Usync(ctx context.Context, jids []types.JID, mode, context string, query []waBinary.Node, extra ...UsyncQueryExtras) (*waBinary.Node, error) {
+	return int.c.usync(ctx, jids, mode, context, query, extra...)
+}
+
+func (int *DangerousInternalClient) ParseBlocklist(node *waBinary.Node) *types.Blocklist {
+	return int.c.parseBlocklist(node)
+}
+
+func (int *DangerousInternalClient) ShouldIncludeReportingToken(message *waE2E.Message) bool {
+	return int.c.shouldIncludeReportingToken(message)
+}
+
+func (int *DangerousInternalClient) GetMessageReportingToken(msgProtobuf []byte, msg *waE2E.Message, senderJID, remoteJID types.JID, messageID types.MessageID) waBinary.Node {
+	return int.c.getMessageReportingToken(msgProtobuf, msg, senderJID, remoteJID, messageID)
+}

+ 211 - 0
internals_generate.go

@@ -0,0 +1,211 @@
+// Copyright (c) 2025 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+//go:build ignore
+
+package main
+
+import (
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"os"
+	"strings"
+
+	"go.mau.fi/util/exerrors"
+)
+
+const header = `// GENERATED BY internals_generate.go; DO NOT EDIT
+
+//go:generate go run internals_generate.go
+//go:generate goimports -local go.mau.fi/whatsmeow -w internals.go
+
+package whatsmeow
+
+`
+const postImportHeader = `
+type DangerousInternalClient struct {
+        c *Client
+}
+
+// DangerousInternals allows access to all unexported methods in Client.
+//
+// Deprecated: dangerous
+func (cli *Client) DangerousInternals() *DangerousInternalClient {
+        return &DangerousInternalClient{cli}
+}
+
+type DangerousInfoQuery = infoQuery
+type DangerousInfoQueryType = infoQueryType
+
+`
+
+func getTypeName(expr ast.Expr) string {
+	switch e := expr.(type) {
+	case *ast.Ident:
+		return e.Name
+	case *ast.StarExpr:
+		return "*" + getTypeName(e.X)
+	case *ast.ArrayType:
+		if e.Len != nil {
+			return fmt.Sprintf("[%s]%s", getTypeName(e.Len), getTypeName(e.Elt))
+		}
+		return "[]" + getTypeName(e.Elt)
+	case *ast.MapType:
+		return fmt.Sprintf("map[%s]%s", getTypeName(e.Key), getTypeName(e.Value))
+	case *ast.ChanType:
+		if e.Dir == ast.SEND {
+			return fmt.Sprintf("chan<- %s", getTypeName(e.Value))
+		} else if e.Dir == ast.RECV {
+			return fmt.Sprintf("<-chan %s", getTypeName(e.Value))
+		}
+		return fmt.Sprintf("chan %s", getTypeName(e.Value))
+	case *ast.FuncType:
+		var params []string
+		for _, param := range e.Params.List {
+			params = append(params, getTypeName(param.Type))
+		}
+		var results []string
+		if e.Results != nil {
+			for _, result := range e.Results.List {
+				results = append(results, getTypeName(result.Type))
+			}
+		}
+		retVals := strings.Join(results, ", ")
+		if len(results) > 1 {
+			retVals = fmt.Sprintf("(%s)", retVals)
+		}
+		return fmt.Sprintf("func(%s) %s", strings.Join(params, ", "), retVals)
+	case *ast.SelectorExpr:
+		return fmt.Sprintf("%s.%s", getTypeName(e.X), e.Sel.Name)
+	case *ast.StructType:
+		// This isn't technically correct, but struct literals shouldn't be used for anything else
+		return "struct{}"
+	case *ast.Ellipsis:
+		return fmt.Sprintf("...%s", getTypeName(e.Elt))
+	case *ast.BasicLit:
+		return e.Value
+	default:
+		panic(fmt.Errorf("unknown type %T", e))
+	}
+}
+
+var write func(str string)
+var writef func(format string, args ...any)
+
+func main() {
+	fset := token.NewFileSet()
+	fileNames := []string{
+		"appstate.go", "armadillomessage.go", "broadcast.go", "call.go", "client.go",
+		"connectionevents.go", "download.go", "download-to-file.go", "group.go", "handshake.go",
+		"keepalive.go", "mediaconn.go", "mediaretry.go", "message.go", "msgsecret.go",
+		"newsletter.go", "notification.go", "pair-code.go", "pair.go", "prekeys.go",
+		"presence.go", "privacysettings.go", "push.go", "qrchan.go", "receipt.go", "request.go",
+		"retry.go", "sendfb.go", "send.go", "upload.go", "user.go", "reportingtoken.go",
+	}
+	files := make([]*ast.File, len(fileNames))
+	for i, name := range fileNames {
+		files[i] = exerrors.Must(parser.ParseFile(fset, name, nil, parser.SkipObjectResolution))
+	}
+	file := exerrors.Must(os.OpenFile("internals.go", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644))
+	write = func(str string) {
+		exerrors.Must(file.WriteString(str))
+	}
+	writef = func(format string, args ...any) {
+		exerrors.Must(fmt.Fprintf(file, format, args...))
+	}
+	write(header)
+	write("import (\n")
+	for _, i := range files[0].Imports {
+		write("\t")
+		if i.Name != nil {
+			writef("%s ", i.Name.Name)
+		}
+		writef("%s\n", i.Path.Value)
+	}
+	write(")\n")
+	write(postImportHeader)
+	for _, f := range files {
+		processFile(f)
+	}
+	exerrors.PanicIfNotNil(file.Close())
+}
+
+func processFile(f *ast.File) {
+	ast.Inspect(f, func(node ast.Node) (retVal bool) {
+		retVal = true
+		funcDecl, ok := node.(*ast.FuncDecl)
+		if !ok || funcDecl.Name.IsExported() {
+			return
+		}
+		if funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 || len(funcDecl.Recv.List[0].Names) == 0 ||
+			funcDecl.Recv.List[0].Names[0].Name != "cli" {
+			return
+		}
+		writef("\nfunc (int *DangerousInternalClient) %s%s(", strings.ToUpper(funcDecl.Name.Name[0:1]), funcDecl.Name.Name[1:])
+		for i, param := range funcDecl.Type.Params.List {
+			if i != 0 {
+				write(", ")
+			}
+			for j, name := range param.Names {
+				if j != 0 {
+					write(", ")
+				}
+				write(name.Name)
+			}
+			if len(param.Names) > 0 {
+				write(" ")
+			}
+			write(getTypeName(param.Type))
+		}
+		write(") ")
+		if funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) > 0 {
+			needsParentheses := len(funcDecl.Type.Results.List) > 1 || len(funcDecl.Type.Results.List[0].Names) > 0
+			if needsParentheses {
+				write("(")
+			}
+			for i, result := range funcDecl.Type.Results.List {
+				if i != 0 {
+					write(", ")
+				}
+				for j, name := range result.Names {
+					if j != 0 {
+						write(", ")
+					}
+					write(name.Name)
+				}
+				if len(result.Names) > 0 {
+					write(" ")
+				}
+				write(getTypeName(result.Type))
+			}
+			if needsParentheses {
+				write(")")
+			}
+			write(" ")
+		}
+		write("{\n\t")
+		if funcDecl.Type.Results != nil {
+			write("return ")
+		}
+		writef("int.c.%s(", funcDecl.Name.Name)
+		for i, param := range funcDecl.Type.Params.List {
+			for j, name := range param.Names {
+				if i != 0 || j != 0 {
+					write(", ")
+				}
+				write(name.Name)
+				_, isEllipsis := param.Type.(*ast.Ellipsis)
+				if isEllipsis {
+					write("...")
+				}
+			}
+		}
+		write(")\n}\n")
+		return
+	})
+}

+ 87 - 0
keepalive.go

@@ -0,0 +1,87 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"math/rand/v2"
+	"time"
+
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+var (
+	// KeepAliveResponseDeadline specifies the duration to wait for a response to websocket keepalive pings.
+	KeepAliveResponseDeadline = 10 * time.Second
+	// KeepAliveIntervalMin specifies the minimum interval for websocket keepalive pings.
+	KeepAliveIntervalMin = 20 * time.Second
+	// KeepAliveIntervalMax specifies the maximum interval for websocket keepalive pings.
+	KeepAliveIntervalMax = 30 * time.Second
+
+	// KeepAliveMaxFailTime specifies the maximum time to wait before forcing a reconnect if keepalives fail repeatedly.
+	KeepAliveMaxFailTime = 3 * time.Minute
+)
+
+func (cli *Client) keepAliveLoop(ctx, connCtx context.Context) {
+	lastSuccess := time.Now()
+	var errorCount int
+	for {
+		interval := rand.Int64N(KeepAliveIntervalMax.Milliseconds()-KeepAliveIntervalMin.Milliseconds()) + KeepAliveIntervalMin.Milliseconds()
+		select {
+		case <-time.After(time.Duration(interval) * time.Millisecond):
+			isSuccess, shouldContinue := cli.sendKeepAlive(connCtx)
+			if !shouldContinue {
+				return
+			} else if !isSuccess {
+				errorCount++
+				go cli.dispatchEvent(&events.KeepAliveTimeout{
+					ErrorCount:  errorCount,
+					LastSuccess: lastSuccess,
+				})
+				if cli.EnableAutoReconnect && time.Since(lastSuccess) > KeepAliveMaxFailTime {
+					cli.Log.Debugf("Forcing reconnect due to keepalive failure")
+					cli.Disconnect()
+					cli.resetExpectedDisconnect()
+					go cli.autoReconnect(ctx)
+				}
+			} else {
+				if errorCount > 0 {
+					errorCount = 0
+					go cli.dispatchEvent(&events.KeepAliveRestored{})
+				}
+				lastSuccess = time.Now()
+			}
+		case <-connCtx.Done():
+			return
+		}
+	}
+}
+
+func (cli *Client) sendKeepAlive(ctx context.Context) (isSuccess, shouldContinue bool) {
+	respCh, err := cli.sendIQAsync(ctx, infoQuery{
+		Namespace: "w:p",
+		Type:      "get",
+		To:        types.ServerJID,
+	})
+	if ctx.Err() != nil {
+		return false, false
+	} else if err != nil {
+		cli.Log.Warnf("Failed to send keepalive: %v", err)
+		return false, true
+	}
+	select {
+	case <-respCh:
+		// All good
+		return true, true
+	case <-time.After(KeepAliveResponseDeadline):
+		cli.Log.Warnf("Keepalive timed out")
+		return false, true
+	case <-ctx.Done():
+		return false, false
+	}
+}

+ 97 - 0
mediaconn.go

@@ -0,0 +1,97 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/types"
+)
+
+//type MediaConnIP struct {
+//	IP4 net.IP
+//	IP6 net.IP
+//}
+
+// MediaConnHost represents a single host to download media from.
+type MediaConnHost struct {
+	Hostname string
+	//IPs      []MediaConnIP
+}
+
+// MediaConn contains a list of WhatsApp servers from which attachments can be downloaded from.
+type MediaConn struct {
+	Auth       string
+	AuthTTL    int
+	TTL        int
+	MaxBuckets int
+	FetchedAt  time.Time
+	Hosts      []MediaConnHost
+}
+
+// Expiry returns the time when the MediaConn expires.
+func (mc *MediaConn) Expiry() time.Time {
+	return mc.FetchedAt.Add(time.Duration(mc.TTL) * time.Second)
+}
+
+func (cli *Client) refreshMediaConn(ctx context.Context, force bool) (*MediaConn, error) {
+	if cli == nil {
+		return nil, ErrClientIsNil
+	}
+	cli.mediaConnLock.Lock()
+	defer cli.mediaConnLock.Unlock()
+	if cli.mediaConnCache == nil || force || time.Now().After(cli.mediaConnCache.Expiry()) {
+		var err error
+		cli.mediaConnCache, err = cli.queryMediaConn(ctx)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return cli.mediaConnCache, nil
+}
+
+func (cli *Client) queryMediaConn(ctx context.Context) (*MediaConn, error) {
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "w:m",
+		Type:      "set",
+		To:        types.ServerJID,
+		Content:   []waBinary.Node{{Tag: "media_conn"}},
+	})
+	if err != nil {
+		return nil, fmt.Errorf("failed to query media connections: %w", err)
+	} else if len(resp.GetChildren()) == 0 || resp.GetChildren()[0].Tag != "media_conn" {
+		return nil, fmt.Errorf("failed to query media connections: unexpected child tag")
+	}
+	respMC := resp.GetChildren()[0]
+	var mc MediaConn
+	ag := respMC.AttrGetter()
+	mc.FetchedAt = time.Now()
+	mc.Auth = ag.String("auth")
+	mc.TTL = ag.Int("ttl")
+	mc.AuthTTL = ag.Int("auth_ttl")
+	mc.MaxBuckets = ag.Int("max_buckets")
+	if !ag.OK() {
+		return nil, fmt.Errorf("failed to parse media connections: %+v", ag.Errors)
+	}
+	for _, child := range respMC.GetChildren() {
+		if child.Tag != "host" {
+			cli.Log.Warnf("Unexpected child in media_conn element: %s", child.XMLString())
+			continue
+		}
+		cag := child.AttrGetter()
+		mc.Hosts = append(mc.Hosts, MediaConnHost{
+			Hostname: cag.String("hostname"),
+		})
+		if !cag.OK() {
+			return nil, fmt.Errorf("failed to parse media connection host: %+v", ag.Errors)
+		}
+	}
+	return &mc, nil
+}

+ 185 - 0
mediaretry.go

@@ -0,0 +1,185 @@
+// Copyright (c) 2022 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"fmt"
+
+	"go.mau.fi/util/random"
+	"google.golang.org/protobuf/proto"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waMmsRetry"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+	"go.mau.fi/whatsmeow/util/gcmutil"
+	"go.mau.fi/whatsmeow/util/hkdfutil"
+)
+
+func getMediaRetryKey(mediaKey []byte) (cipherKey []byte) {
+	return hkdfutil.SHA256(mediaKey, nil, []byte("WhatsApp Media Retry Notification"), 32)
+}
+
+func encryptMediaRetryReceipt(messageID types.MessageID, mediaKey []byte) (ciphertext, iv []byte, err error) {
+	receipt := &waMmsRetry.ServerErrorReceipt{
+		StanzaID: proto.String(messageID),
+	}
+	var plaintext []byte
+	plaintext, err = proto.Marshal(receipt)
+	if err != nil {
+		err = fmt.Errorf("failed to marshal payload: %w", err)
+		return
+	}
+	iv = random.Bytes(12)
+	ciphertext, err = gcmutil.Encrypt(getMediaRetryKey(mediaKey), iv, plaintext, []byte(messageID))
+	return
+}
+
+// SendMediaRetryReceipt sends a request to the phone to re-upload the media in a message.
+//
+// This is mostly relevant when handling history syncs and getting a 404 or 410 error downloading media.
+// Rough example on how to use it (will not work out of the box, you must adjust it depending on what you need exactly):
+//
+//	var mediaRetryCache map[types.MessageID]*waE2E.ImageMessage
+//
+//	evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
+//	imageMsg := evt.Message.GetImageMessage() // replace this with the part of the message you want to download
+//	data, err := cli.Download(imageMsg)
+//	if errors.Is(err, whatsmeow.ErrMediaDownloadFailedWith404) || errors.Is(err, whatsmeow.ErrMediaDownloadFailedWith410) {
+//	  err = cli.SendMediaRetryReceipt(&evt.Info, imageMsg.GetMediaKey())
+//	  // You need to store the event data somewhere as it's necessary for handling the retry response.
+//	  mediaRetryCache[evt.Info.ID] = imageMsg
+//	}
+//
+// The response will come as an *events.MediaRetry. The response will then have to be decrypted
+// using DecryptMediaRetryNotification and the same media key passed here. If the media retry was successful,
+// the decrypted notification should contain an updated DirectPath, which can be used to download the file.
+//
+//	func eventHandler(rawEvt interface{}) {
+//	  switch evt := rawEvt.(type) {
+//	  case *events.MediaRetry:
+//	    imageMsg := mediaRetryCache[evt.MessageID]
+//	    retryData, err := whatsmeow.DecryptMediaRetryNotification(evt, imageMsg.GetMediaKey())
+//	    if err != nil || retryData.GetResult != waMmsRetry.MediaRetryNotification_SUCCESS {
+//	      return
+//	    }
+//	    // Use the new path to download the attachment
+//	    imageMsg.DirectPath = retryData.DirectPath
+//	    data, err := cli.Download(imageMsg)
+//	    // Alternatively, you can use cli.DownloadMediaWithPath and provide the individual fields manually.
+//	  }
+//	}
+func (cli *Client) SendMediaRetryReceipt(ctx context.Context, message *types.MessageInfo, mediaKey []byte) error {
+	if cli == nil {
+		return ErrClientIsNil
+	}
+	ciphertext, iv, err := encryptMediaRetryReceipt(message.ID, mediaKey)
+	if err != nil {
+		return fmt.Errorf("failed to prepare encrypted retry receipt: %w", err)
+	}
+	ownID := cli.getOwnID().ToNonAD()
+	if ownID.IsEmpty() {
+		return ErrNotLoggedIn
+	}
+
+	rmrAttrs := waBinary.Attrs{
+		"jid":     message.Chat,
+		"from_me": message.IsFromMe,
+	}
+	if message.IsGroup {
+		rmrAttrs["participant"] = message.Sender
+	}
+
+	encryptedRequest := []waBinary.Node{
+		{Tag: "enc_p", Content: ciphertext},
+		{Tag: "enc_iv", Content: iv},
+	}
+
+	err = cli.sendNode(ctx, waBinary.Node{
+		Tag: "receipt",
+		Attrs: waBinary.Attrs{
+			"id":   message.ID,
+			"to":   ownID,
+			"type": "server-error",
+		},
+		Content: []waBinary.Node{
+			{Tag: "encrypt", Content: encryptedRequest},
+			{Tag: "rmr", Attrs: rmrAttrs},
+		},
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// DecryptMediaRetryNotification decrypts a media retry notification using the media key.
+// See Client.SendMediaRetryReceipt for more info on how to use this.
+func DecryptMediaRetryNotification(evt *events.MediaRetry, mediaKey []byte) (*waMmsRetry.MediaRetryNotification, error) {
+	var notif waMmsRetry.MediaRetryNotification
+	if evt.Error != nil && evt.Ciphertext == nil {
+		if evt.Error.Code == 2 {
+			return nil, ErrMediaNotAvailableOnPhone
+		}
+		return nil, fmt.Errorf("%w (code: %d)", ErrUnknownMediaRetryError, evt.Error.Code)
+	} else if plaintext, err := gcmutil.Decrypt(getMediaRetryKey(mediaKey), evt.IV, evt.Ciphertext, []byte(evt.MessageID)); err != nil {
+		return nil, fmt.Errorf("failed to decrypt notification: %w", err)
+	} else if err = proto.Unmarshal(plaintext, &notif); err != nil {
+		return nil, fmt.Errorf("failed to unmarshal notification (invalid encryption key?): %w", err)
+	} else {
+		return &notif, nil
+	}
+}
+
+func parseMediaRetryNotification(node *waBinary.Node) (*events.MediaRetry, error) {
+	ag := node.AttrGetter()
+	var evt events.MediaRetry
+	evt.Timestamp = ag.UnixTime("t")
+	evt.MessageID = types.MessageID(ag.String("id"))
+	if !ag.OK() {
+		return nil, ag.Error()
+	}
+	rmr, ok := node.GetOptionalChildByTag("rmr")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "rmr", In: "retry notification"}
+	}
+	rmrAG := rmr.AttrGetter()
+	evt.ChatID = rmrAG.JID("jid")
+	evt.FromMe = rmrAG.Bool("from_me")
+	evt.SenderID = rmrAG.OptionalJIDOrEmpty("participant")
+	if !rmrAG.OK() {
+		return nil, fmt.Errorf("missing attributes in <rmr> tag: %w", rmrAG.Error())
+	}
+
+	errNode, ok := node.GetOptionalChildByTag("error")
+	if ok {
+		evt.Error = &events.MediaRetryError{
+			Code: errNode.AttrGetter().Int("code"),
+		}
+		return &evt, nil
+	}
+
+	evt.Ciphertext, ok = node.GetChildByTag("encrypt", "enc_p").Content.([]byte)
+	if !ok {
+		return nil, &ElementMissingError{Tag: "enc_p", In: fmt.Sprintf("retry notification %s", evt.MessageID)}
+	}
+	evt.IV, ok = node.GetChildByTag("encrypt", "enc_iv").Content.([]byte)
+	if !ok {
+		return nil, &ElementMissingError{Tag: "enc_iv", In: fmt.Sprintf("retry notification %s", evt.MessageID)}
+	}
+	return &evt, nil
+}
+
+func (cli *Client) handleMediaRetryNotification(ctx context.Context, node *waBinary.Node) {
+	evt, err := parseMediaRetryNotification(node)
+	if err != nil {
+		cli.Log.Warnf("Failed to parse media retry notification: %v", err)
+		return
+	}
+	cli.dispatchEvent(evt)
+}

+ 1046 - 0
message.go

@@ -0,0 +1,1046 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"bytes"
+	"compress/zlib"
+	"context"
+	"crypto/sha256"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"io"
+	"runtime/debug"
+	"strconv"
+	"time"
+
+	"github.com/rs/zerolog"
+	"go.mau.fi/libsignal/groups"
+	"go.mau.fi/libsignal/protocol"
+	"go.mau.fi/libsignal/session"
+	"go.mau.fi/libsignal/signalerror"
+	"go.mau.fi/util/random"
+	"google.golang.org/protobuf/proto"
+
+	"go.mau.fi/whatsmeow/appstate"
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/proto/waHistorySync"
+	"go.mau.fi/whatsmeow/proto/waLidMigrationSyncPayload"
+	"go.mau.fi/whatsmeow/proto/waWeb"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+var pbSerializer = store.SignalProtobufSerializer
+
+func (cli *Client) handleEncryptedMessage(ctx context.Context, node *waBinary.Node) {
+	info, err := cli.parseMessageInfo(node)
+	if err != nil {
+		cli.Log.Warnf("Failed to parse message: %v", err)
+	} else {
+		if !info.SenderAlt.IsEmpty() {
+			cli.StoreLIDPNMapping(ctx, info.SenderAlt, info.Sender)
+		} else if !info.RecipientAlt.IsEmpty() {
+			cli.StoreLIDPNMapping(ctx, info.RecipientAlt, info.Chat)
+		}
+		if info.VerifiedName != nil && len(info.VerifiedName.Details.GetVerifiedName()) > 0 {
+			go cli.updateBusinessName(ctx, info.Sender, info.SenderAlt, info, info.VerifiedName.Details.GetVerifiedName())
+		}
+		if len(info.PushName) > 0 && info.PushName != "-" && (cli.MessengerConfig == nil || info.PushName != "username") {
+			go cli.updatePushName(ctx, info.Sender, info.SenderAlt, info, info.PushName)
+		}
+		if info.Sender.Server == types.NewsletterServer {
+			var cancelled bool
+			defer cli.maybeDeferredAck(ctx, node)(&cancelled)
+			cancelled = cli.handlePlaintextMessage(ctx, info, node)
+		} else {
+			cli.decryptMessages(ctx, info, node)
+		}
+	}
+}
+
+func (cli *Client) parseMessageSource(node *waBinary.Node, requireParticipant bool) (source types.MessageSource, err error) {
+	clientID := cli.getOwnID()
+	clientLID := cli.getOwnLID()
+	if clientID.IsEmpty() {
+		err = ErrNotLoggedIn
+		return
+	}
+	ag := node.AttrGetter()
+	from := ag.JID("from")
+	source.AddressingMode = types.AddressingMode(ag.OptionalString("addressing_mode"))
+	if from.Server == types.GroupServer || from.Server == types.BroadcastServer {
+		source.IsGroup = true
+		source.Chat = from
+		if requireParticipant {
+			source.Sender = ag.JID("participant")
+		} else {
+			source.Sender = ag.OptionalJIDOrEmpty("participant")
+		}
+		if source.AddressingMode == types.AddressingModeLID {
+			source.SenderAlt = ag.OptionalJIDOrEmpty("participant_pn")
+		} else {
+			source.SenderAlt = ag.OptionalJIDOrEmpty("participant_lid")
+		}
+		if source.Sender.User == clientID.User || source.Sender.User == clientLID.User {
+			source.IsFromMe = true
+		}
+		if from.Server == types.BroadcastServer {
+			source.BroadcastListOwner = ag.OptionalJIDOrEmpty("recipient")
+			participants, ok := node.GetOptionalChildByTag("participants")
+			if ok && source.IsFromMe {
+				children := participants.GetChildren()
+				source.BroadcastRecipients = make([]types.BroadcastRecipient, 0, len(children))
+				for _, child := range children {
+					if child.Tag != "to" {
+						continue
+					}
+					cag := child.AttrGetter()
+					mainJID := cag.JID("jid")
+					if mainJID.Server == types.HiddenUserServer {
+						source.BroadcastRecipients = append(source.BroadcastRecipients, types.BroadcastRecipient{
+							LID: mainJID,
+							PN:  cag.OptionalJIDOrEmpty("peer_recipient_pn"),
+						})
+					} else {
+						source.BroadcastRecipients = append(source.BroadcastRecipients, types.BroadcastRecipient{
+							LID: cag.OptionalJIDOrEmpty("peer_recipient_lid"),
+							PN:  mainJID,
+						})
+					}
+				}
+			}
+		}
+	} else if from.Server == types.NewsletterServer {
+		source.Chat = from
+		source.Sender = from
+		// TODO IsFromMe?
+	} else if from.User == clientID.User || from.User == clientLID.User {
+		if from.Server == types.HostedServer {
+			from.Server = types.DefaultUserServer
+		} else if from.Server == types.HostedLIDServer {
+			from.Server = types.HiddenUserServer
+		}
+		source.IsFromMe = true
+		source.Sender = from
+		recipient := ag.OptionalJID("recipient")
+		if recipient != nil {
+			source.Chat = *recipient
+		} else {
+			source.Chat = from.ToNonAD()
+		}
+		if source.Chat.Server == types.HiddenUserServer || source.Chat.Server == types.HostedLIDServer {
+			source.RecipientAlt = ag.OptionalJIDOrEmpty("peer_recipient_pn")
+		} else {
+			source.RecipientAlt = ag.OptionalJIDOrEmpty("peer_recipient_lid")
+		}
+	} else if from.IsBot() {
+		source.Sender = from
+		meta := node.GetChildByTag("meta")
+		ag = meta.AttrGetter()
+		targetChatJID := ag.OptionalJID("target_chat_jid")
+		if targetChatJID != nil {
+			source.Chat = targetChatJID.ToNonAD()
+		} else {
+			source.Chat = from
+		}
+	} else {
+		if from.Server == types.HostedServer {
+			from.Server = types.DefaultUserServer
+		} else if from.Server == types.HostedLIDServer {
+			from.Server = types.HiddenUserServer
+		}
+		source.Chat = from.ToNonAD()
+		source.Sender = from
+		if source.Sender.Server == types.HiddenUserServer || source.Chat.Server == types.HostedLIDServer {
+			source.SenderAlt = ag.OptionalJIDOrEmpty("sender_pn")
+		} else {
+			source.SenderAlt = ag.OptionalJIDOrEmpty("sender_lid")
+		}
+	}
+	if !source.SenderAlt.IsEmpty() && source.SenderAlt.Device == 0 {
+		source.SenderAlt.Device = source.Sender.Device
+	}
+	err = ag.Error()
+	return
+}
+
+func (cli *Client) parseMsgBotInfo(node waBinary.Node) (botInfo types.MsgBotInfo, err error) {
+	botNode := node.GetChildByTag("bot")
+
+	ag := botNode.AttrGetter()
+	botInfo.EditType = types.BotEditType(ag.String("edit"))
+	if botInfo.EditType == types.EditTypeInner || botInfo.EditType == types.EditTypeLast {
+		botInfo.EditTargetID = types.MessageID(ag.String("edit_target_id"))
+		botInfo.EditSenderTimestampMS = ag.UnixMilli("sender_timestamp_ms")
+	}
+	err = ag.Error()
+	return
+}
+
+func (cli *Client) parseMsgMetaInfo(node waBinary.Node) (metaInfo types.MsgMetaInfo, err error) {
+	metaNode := node.GetChildByTag("meta")
+
+	ag := metaNode.AttrGetter()
+	metaInfo.TargetID = types.MessageID(ag.OptionalString("target_id"))
+	metaInfo.TargetSender = ag.OptionalJIDOrEmpty("target_sender_jid")
+	metaInfo.TargetChat = ag.OptionalJIDOrEmpty("target_chat_jid")
+	deprecatedLIDSession, ok := ag.GetBool("deprecated_lid_session", false)
+	if ok {
+		metaInfo.DeprecatedLIDSession = &deprecatedLIDSession
+	}
+	metaInfo.ThreadMessageID = types.MessageID(ag.OptionalString("thread_msg_id"))
+	metaInfo.ThreadMessageSenderJID = ag.OptionalJIDOrEmpty("thread_msg_sender_jid")
+	err = ag.Error()
+	return
+}
+
+func (cli *Client) parseMessageInfo(node *waBinary.Node) (*types.MessageInfo, error) {
+	var info types.MessageInfo
+	var err error
+	info.MessageSource, err = cli.parseMessageSource(node, true)
+	if err != nil {
+		return nil, err
+	}
+	ag := node.AttrGetter()
+	info.ID = types.MessageID(ag.String("id"))
+	info.ServerID = types.MessageServerID(ag.OptionalInt("server_id"))
+	info.Timestamp = ag.UnixTime("t")
+	info.PushName = ag.OptionalString("notify")
+	info.Category = ag.OptionalString("category")
+	info.Type = ag.OptionalString("type")
+	info.Edit = types.EditAttribute(ag.OptionalString("edit"))
+	if !ag.OK() {
+		return nil, ag.Error()
+	}
+
+	for _, child := range node.GetChildren() {
+		switch child.Tag {
+		case "multicast":
+			info.Multicast = true
+		case "verified_name":
+			info.VerifiedName, err = parseVerifiedNameContent(child)
+			if err != nil {
+				cli.Log.Warnf("Failed to parse verified_name node in %s: %v", info.ID, err)
+			}
+		case "bot":
+			info.MsgBotInfo, err = cli.parseMsgBotInfo(child)
+			if err != nil {
+				cli.Log.Warnf("Failed to parse <bot> node in %s: %v", info.ID, err)
+			}
+		case "meta":
+			info.MsgMetaInfo, err = cli.parseMsgMetaInfo(child)
+			if err != nil {
+				cli.Log.Warnf("Failed to parse <meta> node in %s: %v", info.ID, err)
+			}
+		case "franking":
+			// TODO
+		case "trace":
+			// TODO
+		default:
+			if mediaType, ok := child.AttrGetter().GetString("mediatype", false); ok {
+				info.MediaType = mediaType
+			}
+		}
+	}
+
+	return &info, nil
+}
+
+func (cli *Client) handlePlaintextMessage(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) (handlerFailed bool) {
+	// TODO edits have an additional <meta msg_edit_t="1696321271735" original_msg_t="1696321248"/> node
+	plaintext, ok := node.GetOptionalChildByTag("plaintext")
+	if !ok {
+		// 3:
+		return
+	}
+	plaintextBody, ok := plaintext.Content.([]byte)
+	if !ok {
+		cli.Log.Warnf("Plaintext message from %s doesn't have byte content", info.SourceString())
+		return
+	}
+
+	var msg waE2E.Message
+	err := proto.Unmarshal(plaintextBody, &msg)
+	if err != nil {
+		cli.Log.Warnf("Error unmarshaling plaintext message from %s: %v", info.SourceString(), err)
+		return
+	}
+	cli.storeMessageSecret(ctx, info, &msg)
+	evt := &events.Message{
+		Info:       *info,
+		RawMessage: &msg,
+	}
+	meta, ok := node.GetOptionalChildByTag("meta")
+	if ok {
+		evt.NewsletterMeta = &events.NewsletterMessageMeta{
+			EditTS:     meta.AttrGetter().UnixMilli("msg_edit_t"),
+			OriginalTS: meta.AttrGetter().UnixTime("original_msg_t"),
+		}
+	}
+	return cli.dispatchEvent(evt.UnwrapRaw())
+}
+
+func (cli *Client) migrateSessionStore(ctx context.Context, pn, lid types.JID) {
+	err := cli.Store.Sessions.MigratePNToLID(ctx, pn, lid)
+	if err != nil {
+		cli.Log.Errorf("Failed to migrate signal store from %s to %s: %v", pn, lid, err)
+	}
+}
+
+func (cli *Client) decryptMessages(ctx context.Context, info *types.MessageInfo, node *waBinary.Node) {
+	unavailableNode, ok := node.GetOptionalChildByTag("unavailable")
+	if ok && len(node.GetChildrenByTag("enc")) == 0 {
+		uType := events.UnavailableType(unavailableNode.AttrGetter().String("type"))
+		cli.Log.Warnf("Unavailable message %s from %s (type: %q)", info.ID, info.SourceString(), uType)
+		cli.backgroundIfAsyncAck(func() {
+			cli.immediateRequestMessageFromPhone(ctx, info)
+			cli.sendAck(ctx, node, 0)
+		})
+		cli.dispatchEvent(&events.UndecryptableMessage{Info: *info, IsUnavailable: true, UnavailableType: uType})
+		return
+	}
+
+	children := node.GetChildren()
+	cli.Log.Debugf("Decrypting message from %s", info.SourceString())
+	containsDirectMsg := false
+	senderEncryptionJID := info.Sender
+	if info.Sender.Server == types.DefaultUserServer && !info.Sender.IsBot() {
+		if info.SenderAlt.Server == types.HiddenUserServer {
+			senderEncryptionJID = info.SenderAlt
+			cli.migrateSessionStore(ctx, info.Sender, info.SenderAlt)
+		} else if lid, err := cli.Store.LIDs.GetLIDForPN(ctx, info.Sender); err != nil {
+			cli.Log.Errorf("Failed to get LID for %s: %v", info.Sender, err)
+		} else if !lid.IsEmpty() {
+			cli.migrateSessionStore(ctx, info.Sender, lid)
+			senderEncryptionJID = lid
+			info.SenderAlt = lid
+		} else {
+			cli.Log.Warnf("No LID found for %s", info.Sender)
+		}
+	}
+	var recognizedStanza, protobufFailed bool
+	for _, child := range children {
+		if child.Tag != "enc" {
+			continue
+		}
+		recognizedStanza = true
+		ag := child.AttrGetter()
+		encType, ok := ag.GetString("type", false)
+		if !ok {
+			continue
+		}
+		var decrypted []byte
+		var ciphertextHash *[32]byte
+		var err error
+		if encType == "pkmsg" || encType == "msg" {
+			decrypted, ciphertextHash, err = cli.decryptDM(ctx, &child, senderEncryptionJID, encType == "pkmsg", info.Timestamp)
+			containsDirectMsg = true
+		} else if info.IsGroup && encType == "skmsg" {
+			decrypted, ciphertextHash, err = cli.decryptGroupMsg(ctx, &child, senderEncryptionJID, info.Chat, info.Timestamp)
+		} else if encType == "msmsg" && info.Sender.IsBot() {
+			targetSenderJID := info.MsgMetaInfo.TargetSender
+			if targetSenderJID.User == "" {
+				if info.Sender.Server == types.BotServer {
+					targetSenderJID = cli.getOwnLID()
+				} else {
+					targetSenderJID = cli.getOwnID()
+				}
+			}
+			var decryptMessageID string
+			if info.MsgBotInfo.EditType == types.EditTypeInner || info.MsgBotInfo.EditType == types.EditTypeLast {
+				decryptMessageID = info.MsgBotInfo.EditTargetID
+			} else {
+				decryptMessageID = info.ID
+			}
+			var msMsg waE2E.MessageSecretMessage
+			var messageSecret []byte
+			if messageSecret, _, err = cli.Store.MsgSecrets.GetMessageSecret(ctx, info.Chat, targetSenderJID, info.MsgMetaInfo.TargetID); err != nil {
+				err = fmt.Errorf("failed to get message secret for %s: %v", info.MsgMetaInfo.TargetID, err)
+			} else if messageSecret == nil {
+				err = fmt.Errorf("message secret for %s not found", info.MsgMetaInfo.TargetID)
+			} else if err = proto.Unmarshal(child.Content.([]byte), &msMsg); err != nil {
+				err = fmt.Errorf("failed to unmarshal MessageSecretMessage protobuf: %v", err)
+			} else {
+				decrypted, err = cli.decryptBotMessage(ctx, messageSecret, &msMsg, decryptMessageID, targetSenderJID, info)
+			}
+		} else {
+			cli.Log.Warnf("Unhandled encrypted message (type %s) from %s", encType, info.SourceString())
+			continue
+		}
+
+		if errors.Is(err, EventAlreadyProcessed) {
+			cli.Log.Debugf("Ignoring message %s from %s: %v", info.ID, info.SourceString(), err)
+			continue
+		} else if errors.Is(err, signalerror.ErrOldCounter) {
+			cli.Log.Warnf("Ignoring message %s from %s: %v", info.ID, info.SourceString(), err)
+			continue
+		} else if err != nil {
+			cli.Log.Warnf("Error decrypting message %s from %s: %v", info.ID, info.SourceString(), err)
+			if ctx.Err() != nil || errors.Is(err, context.Canceled) {
+				return
+			}
+			isUnavailable := encType == "skmsg" && !containsDirectMsg && errors.Is(err, signalerror.ErrNoSenderKeyForUser)
+			if encType == "msmsg" {
+				cli.backgroundIfAsyncAck(func() {
+					cli.sendAck(ctx, node, NackMissingMessageSecret)
+				})
+			} else if cli.SynchronousAck {
+				cli.sendRetryReceipt(ctx, node, info, isUnavailable)
+				// TODO this probably isn't supposed to ack
+				cli.sendAck(ctx, node, 0)
+			} else {
+				go cli.sendRetryReceipt(context.WithoutCancel(ctx), node, info, isUnavailable)
+				go cli.sendAck(ctx, node, 0)
+			}
+			cli.dispatchEvent(&events.UndecryptableMessage{
+				Info:            *info,
+				IsUnavailable:   isUnavailable,
+				DecryptFailMode: events.DecryptFailMode(ag.OptionalString("decrypt-fail")),
+			})
+			return
+		}
+		retryCount := ag.OptionalInt("count")
+		cli.cancelDelayedRequestFromPhone(info.ID)
+
+		var msg waE2E.Message
+		var handlerFailed bool
+		switch ag.Int("v") {
+		case 2:
+			err = proto.Unmarshal(decrypted, &msg)
+			if err != nil {
+				cli.Log.Warnf("Error unmarshaling decrypted message from %s: %v", info.SourceString(), err)
+				protobufFailed = true
+				continue
+			}
+			protobufFailed = false
+			handlerFailed = cli.handleDecryptedMessage(ctx, info, &msg, retryCount)
+		case 3:
+			handlerFailed, protobufFailed = cli.handleDecryptedArmadillo(ctx, info, decrypted, retryCount)
+		default:
+			cli.Log.Warnf("Unknown version %d in decrypted message from %s", ag.Int("v"), info.SourceString())
+		}
+		if handlerFailed {
+			cli.Log.Warnf("Handler for %s failed", info.ID)
+			return
+		}
+		if ciphertextHash != nil && cli.EnableDecryptedEventBuffer {
+			// Use the context passed to decryptMessages
+			err = cli.Store.EventBuffer.ClearBufferedEventPlaintext(ctx, *ciphertextHash)
+			if err != nil {
+				zerolog.Ctx(ctx).Err(err).
+					Hex("ciphertext_hash", ciphertextHash[:]).
+					Str("message_id", info.ID).
+					Msg("Failed to clear buffered event plaintext")
+			} else {
+				zerolog.Ctx(ctx).Debug().
+					Hex("ciphertext_hash", ciphertextHash[:]).
+					Str("message_id", info.ID).
+					Msg("Deleted event plaintext from buffer")
+			}
+
+			if time.Since(cli.lastDecryptedBufferClear) > 12*time.Hour && ctx.Err() == nil {
+				cli.lastDecryptedBufferClear = time.Now()
+				go func() {
+					err := cli.Store.EventBuffer.DeleteOldBufferedHashes(context.WithoutCancel(ctx))
+					if err != nil {
+						zerolog.Ctx(ctx).Err(err).Msg("Failed to delete old buffered hashes")
+					}
+				}()
+			}
+		}
+	}
+	cli.backgroundIfAsyncAck(func() {
+		if !recognizedStanza {
+			cli.sendAck(ctx, node, NackUnrecognizedStanza)
+		} else if protobufFailed {
+			cli.sendAck(ctx, node, NackInvalidProtobuf)
+		} else {
+			cli.sendMessageReceipt(ctx, info, node)
+		}
+	})
+	return
+}
+
+func (cli *Client) clearUntrustedIdentity(ctx context.Context, target types.JID) error {
+	err := cli.Store.Identities.DeleteIdentity(ctx, target.SignalAddress().String())
+	if err != nil {
+		return fmt.Errorf("failed to delete identity: %w", err)
+	}
+	err = cli.Store.Sessions.DeleteSession(ctx, target.SignalAddress().String())
+	if err != nil {
+		return fmt.Errorf("failed to delete session: %w", err)
+	}
+	go cli.dispatchEvent(&events.IdentityChange{JID: target, Timestamp: time.Now(), Implicit: true})
+	return nil
+}
+
+var EventAlreadyProcessed = errors.New("event was already processed")
+
+func (cli *Client) bufferedDecrypt(
+	ctx context.Context,
+	ciphertext []byte,
+	serverTimestamp time.Time,
+	decrypt func(context.Context) ([]byte, error),
+) (plaintext []byte, ciphertextHash [32]byte, err error) {
+	if !cli.EnableDecryptedEventBuffer {
+		plaintext, err = decrypt(ctx)
+		return
+	}
+	ciphertextHash = sha256.Sum256(ciphertext)
+	var buf *store.BufferedEvent
+	buf, err = cli.Store.EventBuffer.GetBufferedEvent(ctx, ciphertextHash)
+	if err != nil {
+		err = fmt.Errorf("failed to get buffered event: %w", err)
+		return
+	} else if buf != nil {
+		if buf.Plaintext == nil {
+			zerolog.Ctx(ctx).Debug().
+				Hex("ciphertext_hash", ciphertextHash[:]).
+				Time("insertion_time", buf.InsertTime).
+				Msg("Returning event already processed error")
+			err = fmt.Errorf("%w at %s", EventAlreadyProcessed, buf.InsertTime.String())
+			return
+		}
+		zerolog.Ctx(ctx).Debug().
+			Hex("ciphertext_hash", ciphertextHash[:]).
+			Time("insertion_time", buf.InsertTime).
+			Msg("Returning previously decrypted plaintext")
+		plaintext = buf.Plaintext
+		return
+	}
+
+	err = cli.Store.EventBuffer.DoDecryptionTxn(ctx, func(ctx context.Context) (innerErr error) {
+		plaintext, innerErr = decrypt(ctx)
+		if innerErr != nil {
+			return
+		}
+		innerErr = cli.Store.EventBuffer.PutBufferedEvent(ctx, ciphertextHash, plaintext, serverTimestamp)
+		if innerErr != nil {
+			innerErr = fmt.Errorf("failed to save decrypted event to buffer: %w", innerErr)
+		}
+		return
+	})
+	if err == nil {
+		zerolog.Ctx(ctx).Debug().
+			Hex("ciphertext_hash", ciphertextHash[:]).
+			Msg("Successfully decrypted and saved event")
+	}
+	return
+}
+
+func (cli *Client) decryptDM(ctx context.Context, child *waBinary.Node, from types.JID, isPreKey bool, serverTS time.Time) ([]byte, *[32]byte, error) {
+	content, ok := child.Content.([]byte)
+	if !ok {
+		return nil, nil, fmt.Errorf("message content is not a byte slice")
+	}
+
+	builder := session.NewBuilderFromSignal(cli.Store, from.SignalAddress(), pbSerializer)
+	cipher := session.NewCipher(builder, from.SignalAddress())
+	var plaintext []byte
+	var ciphertextHash [32]byte
+	if isPreKey {
+		preKeyMsg, err := protocol.NewPreKeySignalMessageFromBytes(content, pbSerializer.PreKeySignalMessage, pbSerializer.SignalMessage)
+		if err != nil {
+			return nil, nil, fmt.Errorf("failed to parse prekey message: %w", err)
+		}
+		plaintext, ciphertextHash, err = cli.bufferedDecrypt(ctx, content, serverTS, func(decryptCtx context.Context) ([]byte, error) {
+			pt, innerErr := cipher.DecryptMessage(decryptCtx, preKeyMsg)
+			if cli.AutoTrustIdentity && errors.Is(innerErr, signalerror.ErrUntrustedIdentity) {
+				cli.Log.Warnf("Got %v error while trying to decrypt prekey message from %s, clearing stored identity and retrying", innerErr, from)
+				if innerErr = cli.clearUntrustedIdentity(decryptCtx, from); innerErr != nil {
+					innerErr = fmt.Errorf("failed to clear untrusted identity: %w", innerErr)
+					return nil, innerErr
+				}
+				pt, innerErr = cipher.DecryptMessage(decryptCtx, preKeyMsg)
+			}
+			return pt, innerErr
+		})
+		if err != nil {
+			return nil, nil, fmt.Errorf("failed to decrypt prekey message: %w", err)
+		}
+	} else {
+		msg, err := protocol.NewSignalMessageFromBytes(content, pbSerializer.SignalMessage)
+		if err != nil {
+			return nil, nil, fmt.Errorf("failed to parse normal message: %w", err)
+		}
+		plaintext, ciphertextHash, err = cli.bufferedDecrypt(ctx, content, serverTS, func(decryptCtx context.Context) ([]byte, error) {
+			return cipher.Decrypt(decryptCtx, msg)
+		})
+		if err != nil {
+			return nil, nil, fmt.Errorf("failed to decrypt normal message: %w", err)
+		}
+	}
+	var err error
+	plaintext, err = unpadMessage(plaintext, child.AttrGetter().Int("v"))
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to unpad message: %w", err)
+	}
+	return plaintext, &ciphertextHash, nil
+}
+
+func (cli *Client) decryptGroupMsg(ctx context.Context, child *waBinary.Node, from types.JID, chat types.JID, serverTS time.Time) ([]byte, *[32]byte, error) {
+	content, ok := child.Content.([]byte)
+	if !ok {
+		return nil, nil, fmt.Errorf("message content is not a byte slice")
+	}
+
+	senderKeyName := protocol.NewSenderKeyName(chat.String(), from.SignalAddress())
+	builder := groups.NewGroupSessionBuilder(cli.Store, pbSerializer)
+	cipher := groups.NewGroupCipher(builder, senderKeyName, cli.Store)
+	msg, err := protocol.NewSenderKeyMessageFromBytes(content, pbSerializer.SenderKeyMessage)
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to parse group message: %w", err)
+	}
+	plaintext, ciphertextHash, err := cli.bufferedDecrypt(ctx, content, serverTS, func(decryptCtx context.Context) ([]byte, error) {
+		return cipher.Decrypt(decryptCtx, msg)
+	})
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to decrypt group message: %w", err)
+	}
+	plaintext, err = unpadMessage(plaintext, child.AttrGetter().Int("v"))
+	if err != nil {
+		return nil, nil, err
+	}
+	return plaintext, &ciphertextHash, nil
+}
+
+const checkPadding = true
+
+func isValidPadding(plaintext []byte) bool {
+	lastByte := plaintext[len(plaintext)-1]
+	expectedPadding := bytes.Repeat([]byte{lastByte}, int(lastByte))
+	return bytes.HasSuffix(plaintext, expectedPadding)
+}
+
+func unpadMessage(plaintext []byte, version int) ([]byte, error) {
+	if version == 3 {
+		return plaintext, nil
+	} else if len(plaintext) == 0 {
+		return nil, fmt.Errorf("plaintext is empty")
+	} else if checkPadding && !isValidPadding(plaintext) {
+		return nil, fmt.Errorf("plaintext doesn't have expected padding")
+	} else {
+		return plaintext[:len(plaintext)-int(plaintext[len(plaintext)-1])], nil
+	}
+}
+
+func padMessage(plaintext []byte) []byte {
+	pad := random.Bytes(1)
+	pad[0] &= 0xf
+	if pad[0] == 0 {
+		pad[0] = 0xf
+	}
+	plaintext = append(plaintext, bytes.Repeat(pad, int(pad[0]))...)
+	return plaintext
+}
+
+func (cli *Client) handleSenderKeyDistributionMessage(ctx context.Context, chat, from types.JID, axolotlSKDM []byte) {
+	builder := groups.NewGroupSessionBuilder(cli.Store, pbSerializer)
+	senderKeyName := protocol.NewSenderKeyName(chat.String(), from.SignalAddress())
+	sdkMsg, err := protocol.NewSenderKeyDistributionMessageFromBytes(axolotlSKDM, pbSerializer.SenderKeyDistributionMessage)
+	if err != nil {
+		cli.Log.Errorf("Failed to parse sender key distribution message from %s for %s: %v", from, chat, err)
+		return
+	}
+	err = builder.Process(ctx, senderKeyName, sdkMsg)
+	if err != nil {
+		cli.Log.Errorf("Failed to process sender key distribution message from %s for %s: %v", from, chat, err)
+		return
+	}
+	cli.Log.Debugf("Processed sender key distribution message from %s in %s", senderKeyName.Sender().String(), senderKeyName.GroupID())
+}
+
+func (cli *Client) handleHistorySyncNotificationLoop() {
+	defer func() {
+		cli.historySyncHandlerStarted.Store(false)
+		err := recover()
+		if err != nil {
+			cli.Log.Errorf("History sync handler panicked: %v\n%s", err, debug.Stack())
+		}
+
+		// Check in case something new appeared in the channel between the loop stopping
+		// and the atomic variable being updated. If yes, restart the loop.
+		if len(cli.historySyncNotifications) > 0 && cli.historySyncHandlerStarted.CompareAndSwap(false, true) {
+			cli.Log.Warnf("New history sync notifications appeared after loop stopped, restarting loop...")
+			go cli.handleHistorySyncNotificationLoop()
+		}
+	}()
+	ctx := cli.BackgroundEventCtx
+	for notif := range cli.historySyncNotifications {
+		blob, err := cli.DownloadHistorySync(ctx, notif, false)
+		if err != nil {
+			cli.Log.Errorf("Failed to download history sync: %v", err)
+		} else {
+			cli.dispatchEvent(&events.HistorySync{Data: blob})
+		}
+	}
+}
+
+// DownloadHistorySync will download and parse the history sync blob from the given history sync notification.
+//
+// You only need to call this manually if you set [Client.ManualHistorySyncDownload] to true.
+// By default, whatsmeow will call this automatically and dispatch an [events.HistorySync] with the parsed data.
+func (cli *Client) DownloadHistorySync(ctx context.Context, notif *waE2E.HistorySyncNotification, synchronousStorage bool) (*waHistorySync.HistorySync, error) {
+	var data []byte
+	var err error
+	if notif.InitialHistBootstrapInlinePayload != nil {
+		data = notif.InitialHistBootstrapInlinePayload
+	} else if data, err = cli.Download(ctx, notif); err != nil {
+		return nil, fmt.Errorf("failed to download: %w", err)
+	}
+	var historySync waHistorySync.HistorySync
+	if reader, err := zlib.NewReader(bytes.NewReader(data)); err != nil {
+		return nil, fmt.Errorf("failed to prepare to decompress: %w", err)
+	} else if rawData, err := io.ReadAll(reader); err != nil {
+		return nil, fmt.Errorf("failed to decompress: %w", err)
+	} else if err = proto.Unmarshal(rawData, &historySync); err != nil {
+		return nil, fmt.Errorf("failed to unmarshal: %w", err)
+	}
+	cli.Log.Debugf("Received history sync (type %s, chunk %d, progress %d)", historySync.GetSyncType(), historySync.GetChunkOrder(), historySync.GetProgress())
+	doStorage := func(ctx context.Context) {
+		if historySync.GetSyncType() == waHistorySync.HistorySync_PUSH_NAME {
+			cli.handleHistoricalPushNames(ctx, historySync.GetPushnames())
+		} else if len(historySync.GetConversations()) > 0 {
+			cli.storeHistoricalMessageSecrets(ctx, historySync.GetConversations())
+		}
+		if len(historySync.GetPhoneNumberToLidMappings()) > 0 {
+			cli.storeHistoricalPNLIDMappings(ctx, historySync.GetPhoneNumberToLidMappings())
+		}
+		if historySync.GlobalSettings != nil {
+			cli.storeGlobalSettings(ctx, historySync.GlobalSettings)
+		}
+	}
+	if synchronousStorage {
+		doStorage(ctx)
+	} else {
+		go doStorage(context.WithoutCancel(ctx))
+	}
+	return &historySync, nil
+}
+
+func (cli *Client) handleAppStateSyncKeyShare(ctx context.Context, keys *waE2E.AppStateSyncKeyShare) {
+	onlyResyncIfNotSynced := true
+
+	cli.Log.Debugf("Got %d new app state keys", len(keys.GetKeys()))
+	cli.appStateKeyRequestsLock.RLock()
+	for _, key := range keys.GetKeys() {
+		marshaledFingerprint, err := proto.Marshal(key.GetKeyData().GetFingerprint())
+		if err != nil {
+			cli.Log.Errorf("Failed to marshal fingerprint of app state sync key %X", key.GetKeyID().GetKeyID())
+			continue
+		}
+		_, isReRequest := cli.appStateKeyRequests[hex.EncodeToString(key.GetKeyID().GetKeyID())]
+		if isReRequest {
+			onlyResyncIfNotSynced = false
+		}
+		err = cli.Store.AppStateKeys.PutAppStateSyncKey(ctx, key.GetKeyID().GetKeyID(), store.AppStateSyncKey{
+			Data:        key.GetKeyData().GetKeyData(),
+			Fingerprint: marshaledFingerprint,
+			Timestamp:   key.GetKeyData().GetTimestamp(),
+		})
+		if err != nil {
+			cli.Log.Errorf("Failed to store app state sync key %X: %v", key.GetKeyID().GetKeyID(), err)
+			continue
+		}
+		cli.Log.Debugf("Received app state sync key %X (ts: %d)", key.GetKeyID().GetKeyID(), key.GetKeyData().GetTimestamp())
+	}
+	cli.appStateKeyRequestsLock.RUnlock()
+
+	for _, name := range appstate.AllPatchNames {
+		err := cli.FetchAppState(ctx, name, false, onlyResyncIfNotSynced)
+		if err != nil {
+			cli.Log.Errorf("Failed to do initial fetch of app state %s: %v", name, err)
+		}
+	}
+}
+
+func (cli *Client) handlePlaceholderResendResponse(msg *waE2E.PeerDataOperationRequestResponseMessage) (ok bool) {
+	reqID := msg.GetStanzaID()
+	parts := msg.GetPeerDataOperationResult()
+	cli.Log.Debugf("Handling response to placeholder resend request %s with %d items", reqID, len(parts))
+	ok = true
+	for i, part := range parts {
+		var webMsg waWeb.WebMessageInfo
+		if resp := part.GetPlaceholderMessageResendResponse(); resp == nil {
+			cli.Log.Warnf("Missing response in item #%d of response to %s", i+1, reqID)
+		} else if err := proto.Unmarshal(resp.GetWebMessageInfoBytes(), &webMsg); err != nil {
+			cli.Log.Warnf("Failed to unmarshal protobuf web message in item #%d of response to %s: %v", i+1, reqID, err)
+		} else if msgEvt, err := cli.ParseWebMessage(types.EmptyJID, &webMsg); err != nil {
+			cli.Log.Warnf("Failed to parse web message info in item #%d of response to %s: %v", i+1, reqID, err)
+		} else {
+			msgEvt.UnavailableRequestID = reqID
+			ok = cli.dispatchEvent(msgEvt) && ok
+		}
+	}
+	return
+}
+
+func (cli *Client) handleProtocolMessage(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message) (ok bool) {
+	ok = true
+	protoMsg := msg.GetProtocolMessage()
+
+	if !info.IsFromMe {
+		return
+	}
+
+	if protoMsg.GetHistorySyncNotification() != nil {
+		if !cli.ManualHistorySyncDownload {
+			cli.historySyncNotifications <- protoMsg.HistorySyncNotification
+			if cli.historySyncHandlerStarted.CompareAndSwap(false, true) {
+				go cli.handleHistorySyncNotificationLoop()
+			}
+		}
+		go cli.sendProtocolMessageReceipt(ctx, info.ID, types.ReceiptTypeHistorySync)
+	}
+
+	if protoMsg.GetLidMigrationMappingSyncMessage() != nil {
+		cli.storeLIDSyncMessage(ctx, protoMsg.GetLidMigrationMappingSyncMessage().GetEncodedMappingPayload())
+	}
+
+	if protoMsg.GetPeerDataOperationRequestResponseMessage().GetPeerDataOperationRequestType() == waE2E.PeerDataOperationRequestType_PLACEHOLDER_MESSAGE_RESEND {
+		ok = cli.handlePlaceholderResendResponse(protoMsg.GetPeerDataOperationRequestResponseMessage()) && ok
+	}
+
+	if protoMsg.GetAppStateSyncKeyShare() != nil {
+		go cli.handleAppStateSyncKeyShare(context.WithoutCancel(ctx), protoMsg.AppStateSyncKeyShare)
+	}
+
+	if info.Category == "peer" {
+		go cli.sendProtocolMessageReceipt(ctx, info.ID, types.ReceiptTypePeerMsg)
+	}
+	return
+}
+
+func (cli *Client) processProtocolParts(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message) (ok bool) {
+	ok = true
+	cli.storeMessageSecret(ctx, info, msg)
+	// Hopefully sender key distribution messages and protocol messages can't be inside ephemeral messages
+	if msg.GetDeviceSentMessage().GetMessage() != nil {
+		msg = msg.GetDeviceSentMessage().GetMessage()
+	}
+	if msg.GetSenderKeyDistributionMessage() != nil {
+		if !info.IsGroup {
+			cli.Log.Warnf("Got sender key distribution message in non-group chat from %s", info.Sender)
+		} else {
+			encryptionIdentity := info.Sender
+			if encryptionIdentity.Server == types.DefaultUserServer && info.SenderAlt.Server == types.HiddenUserServer {
+				encryptionIdentity = info.SenderAlt
+			}
+			cli.handleSenderKeyDistributionMessage(ctx, info.Chat, encryptionIdentity, msg.SenderKeyDistributionMessage.AxolotlSenderKeyDistributionMessage)
+		}
+	}
+	// N.B. Edits are protocol messages, but they're also wrapped inside EditedMessage,
+	// which is only unwrapped after processProtocolParts, so this won't trigger for edits.
+	if msg.GetProtocolMessage() != nil {
+		ok = cli.handleProtocolMessage(ctx, info, msg) && ok
+	}
+	return
+}
+
+func (cli *Client) storeMessageSecret(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message) {
+	if msgSecret := msg.GetMessageContextInfo().GetMessageSecret(); len(msgSecret) > 0 {
+		err := cli.Store.MsgSecrets.PutMessageSecret(ctx, info.Chat, info.Sender, info.ID, msgSecret)
+		if err != nil {
+			cli.Log.Errorf("Failed to store message secret key for %s: %v", info.ID, err)
+		} else {
+			cli.Log.Debugf("Stored message secret key for %s", info.ID)
+		}
+	}
+}
+
+func (cli *Client) storeHistoricalMessageSecrets(ctx context.Context, conversations []*waHistorySync.Conversation) {
+	var secrets []store.MessageSecretInsert
+	var privacyTokens []store.PrivacyToken
+	ownID := cli.getOwnID().ToNonAD()
+	if ownID.IsEmpty() {
+		return
+	}
+	for _, conv := range conversations {
+		chatJID, _ := types.ParseJID(conv.GetID())
+		if chatJID.IsEmpty() {
+			continue
+		}
+		if chatJID.Server == types.DefaultUserServer && conv.GetTcToken() != nil {
+			ts := conv.GetTcTokenSenderTimestamp()
+			if ts == 0 {
+				ts = conv.GetTcTokenTimestamp()
+			}
+			privacyTokens = append(privacyTokens, store.PrivacyToken{
+				User:      chatJID,
+				Token:     conv.GetTcToken(),
+				Timestamp: time.Unix(int64(ts), 0),
+			})
+		}
+		for _, msg := range conv.GetMessages() {
+			if secret := msg.GetMessage().GetMessageSecret(); secret != nil {
+				var senderJID types.JID
+				msgKey := msg.GetMessage().GetKey()
+				if msgKey.GetFromMe() {
+					senderJID = ownID
+				} else if chatJID.Server == types.DefaultUserServer {
+					senderJID = chatJID
+				} else if msgKey.GetParticipant() != "" {
+					senderJID, _ = types.ParseJID(msgKey.GetParticipant())
+				} else if msg.GetMessage().GetParticipant() != "" {
+					senderJID, _ = types.ParseJID(msg.GetMessage().GetParticipant())
+				}
+				if senderJID.IsEmpty() || msgKey.GetID() == "" {
+					continue
+				}
+				secrets = append(secrets, store.MessageSecretInsert{
+					Chat:   chatJID,
+					Sender: senderJID,
+					ID:     msgKey.GetID(),
+					Secret: secret,
+				})
+			}
+		}
+	}
+	if len(secrets) > 0 {
+		cli.Log.Debugf("Storing %d message secret keys in history sync", len(secrets))
+		err := cli.Store.MsgSecrets.PutMessageSecrets(ctx, secrets)
+		if err != nil {
+			cli.Log.Errorf("Failed to store message secret keys in history sync: %v", err)
+		} else {
+			cli.Log.Infof("Stored %d message secret keys from history sync", len(secrets))
+		}
+	}
+	if len(privacyTokens) > 0 {
+		cli.Log.Debugf("Storing %d privacy tokens in history sync", len(privacyTokens))
+		err := cli.Store.PrivacyTokens.PutPrivacyTokens(ctx, privacyTokens...)
+		if err != nil {
+			cli.Log.Errorf("Failed to store privacy tokens in history sync: %v", err)
+		} else {
+			cli.Log.Infof("Stored %d privacy tokens from history sync", len(privacyTokens))
+		}
+	}
+}
+
+func (cli *Client) storeLIDSyncMessage(ctx context.Context, msg []byte) {
+	var decoded waLidMigrationSyncPayload.LIDMigrationMappingSyncPayload
+	err := proto.Unmarshal(msg, &decoded)
+	if err != nil {
+		zerolog.Ctx(ctx).Err(err).Msg("Failed to unmarshal LID migration mapping sync payload")
+		return
+	}
+	if cli.Store.LIDMigrationTimestamp == 0 && decoded.GetChatDbMigrationTimestamp() > 0 {
+		cli.Store.LIDMigrationTimestamp = int64(decoded.GetChatDbMigrationTimestamp())
+		err = cli.Store.Save(ctx)
+		if err != nil {
+			zerolog.Ctx(ctx).Err(err).
+				Int64("lid_migration_timestamp", cli.Store.LIDMigrationTimestamp).
+				Msg("Failed to save chat DB LID migration timestamp")
+		} else {
+			zerolog.Ctx(ctx).Debug().
+				Int64("lid_migration_timestamp", cli.Store.LIDMigrationTimestamp).
+				Msg("Saved chat DB LID migration timestamp")
+		}
+	}
+	lidPairs := make([]store.LIDMapping, len(decoded.PnToLidMappings))
+	for i, mapping := range decoded.PnToLidMappings {
+		lidPairs[i] = store.LIDMapping{
+			LID: types.JID{User: strconv.FormatUint(mapping.GetAssignedLid(), 10), Server: types.HiddenUserServer},
+			PN:  types.JID{User: strconv.FormatUint(mapping.GetPn(), 10), Server: types.DefaultUserServer},
+		}
+	}
+	err = cli.Store.LIDs.PutManyLIDMappings(ctx, lidPairs)
+	if err != nil {
+		zerolog.Ctx(ctx).Err(err).
+			Int("pair_count", len(lidPairs)).
+			Msg("Failed to store phone number to LID mappings from sync message")
+	} else {
+		zerolog.Ctx(ctx).Debug().
+			Int("pair_count", len(lidPairs)).
+			Msg("Stored PN-LID mappings from sync message")
+	}
+}
+
+func (cli *Client) storeGlobalSettings(ctx context.Context, settings *waHistorySync.GlobalSettings) {
+	if cli.Store.LIDMigrationTimestamp == 0 && settings.GetChatDbLidMigrationTimestamp() > 0 {
+		cli.Store.LIDMigrationTimestamp = settings.GetChatDbLidMigrationTimestamp()
+		err := cli.Store.Save(ctx)
+		if err != nil {
+			zerolog.Ctx(ctx).Err(err).
+				Int64("lid_migration_timestamp", cli.Store.LIDMigrationTimestamp).
+				Msg("Failed to save chat DB LID migration timestamp")
+		} else {
+			zerolog.Ctx(ctx).Debug().
+				Int64("lid_migration_timestamp", cli.Store.LIDMigrationTimestamp).
+				Msg("Saved chat DB LID migration timestamp")
+		}
+	}
+}
+
+func (cli *Client) storeHistoricalPNLIDMappings(ctx context.Context, mappings []*waHistorySync.PhoneNumberToLIDMapping) {
+	lidPairs := make([]store.LIDMapping, 0, len(mappings))
+	for _, mapping := range mappings {
+		pn, err := types.ParseJID(mapping.GetPnJID())
+		if err != nil {
+			zerolog.Ctx(ctx).Err(err).
+				Str("pn_jid", mapping.GetPnJID()).
+				Str("lid_jid", mapping.GetLidJID()).
+				Msg("Failed to parse phone number from history sync")
+			continue
+		}
+		if pn.Server == types.LegacyUserServer {
+			pn.Server = types.DefaultUserServer
+		}
+		lid, err := types.ParseJID(mapping.GetLidJID())
+		if err != nil {
+			zerolog.Ctx(ctx).Err(err).
+				Str("pn_jid", mapping.GetPnJID()).
+				Str("lid_jid", mapping.GetLidJID()).
+				Msg("Failed to parse LID from history sync")
+			continue
+		}
+		lidPairs = append(lidPairs, store.LIDMapping{
+			LID: lid,
+			PN:  pn,
+		})
+	}
+	err := cli.Store.LIDs.PutManyLIDMappings(ctx, lidPairs)
+	if err != nil {
+		zerolog.Ctx(ctx).Err(err).
+			Int("pair_count", len(lidPairs)).
+			Msg("Failed to store phone number to LID mappings from history sync")
+	} else {
+		zerolog.Ctx(ctx).Debug().
+			Int("pair_count", len(lidPairs)).
+			Msg("Stored PN-LID mappings from history sync")
+	}
+}
+
+func (cli *Client) handleDecryptedMessage(ctx context.Context, info *types.MessageInfo, msg *waE2E.Message, retryCount int) bool {
+	ok := cli.processProtocolParts(ctx, info, msg)
+	if !ok {
+		return false
+	}
+	evt := &events.Message{Info: *info, RawMessage: msg, RetryCount: retryCount}
+	return cli.dispatchEvent(evt.UnwrapRaw())
+}
+
+func (cli *Client) sendProtocolMessageReceipt(ctx context.Context, id types.MessageID, msgType types.ReceiptType) {
+	if len(id) == 0 {
+		return
+	}
+	err := cli.sendNode(ctx, waBinary.Node{
+		Tag: "receipt",
+		Attrs: waBinary.Attrs{
+			"id":   string(id),
+			"type": string(msgType),
+			"to":   cli.getOwnID().ToNonAD(),
+		},
+		Content: nil,
+	})
+	if err != nil {
+		cli.Log.Warnf("Failed to send acknowledgement for protocol message %s: %v", id, err)
+	}
+}

+ 385 - 0
msgsecret.go

@@ -0,0 +1,385 @@
+// Copyright (c) 2022 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"crypto/sha256"
+	"fmt"
+	"time"
+
+	"go.mau.fi/util/random"
+	"google.golang.org/protobuf/proto"
+
+	"go.mau.fi/whatsmeow/proto/waCommon"
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+	"go.mau.fi/whatsmeow/util/gcmutil"
+	"go.mau.fi/whatsmeow/util/hkdfutil"
+)
+
+type MsgSecretType string
+
+const (
+	EncSecretPollVote      MsgSecretType = "Poll Vote"
+	EncSecretReaction      MsgSecretType = "Enc Reaction"
+	EncSecretComment       MsgSecretType = "Enc Comment"
+	EncSecretReportToken   MsgSecretType = "Report Token"
+	EncSecretEventResponse MsgSecretType = "Event Response"
+	EncSecretEventEdit     MsgSecretType = "Event Edit"
+	EncSecretBotMsg        MsgSecretType = "Bot Message"
+)
+
+func applyBotMessageHKDF(messageSecret []byte) []byte {
+	return hkdfutil.SHA256(messageSecret, nil, []byte(EncSecretBotMsg), 32)
+}
+
+func generateMsgSecretKey(
+	modificationType MsgSecretType, modificationSender types.JID,
+	origMsgID types.MessageID, origMsgSender types.JID, origMsgSecret []byte,
+) ([]byte, []byte) {
+	origMsgSenderStr := origMsgSender.ToNonAD().String()
+	modificationSenderStr := modificationSender.ToNonAD().String()
+
+	useCaseSecret := make([]byte, 0, len(origMsgID)+len(origMsgSenderStr)+len(modificationSenderStr)+len(modificationType))
+	useCaseSecret = append(useCaseSecret, origMsgID...)
+	useCaseSecret = append(useCaseSecret, origMsgSenderStr...)
+	useCaseSecret = append(useCaseSecret, modificationSenderStr...)
+	useCaseSecret = append(useCaseSecret, modificationType...)
+
+	secretKey := hkdfutil.SHA256(origMsgSecret, nil, useCaseSecret, 32)
+	var additionalData []byte
+	switch modificationType {
+	case EncSecretPollVote, EncSecretEventResponse, "":
+		additionalData = fmt.Appendf(nil, "%s\x00%s", origMsgID, modificationSenderStr)
+	}
+
+	return secretKey, additionalData
+}
+
+func getOrigSenderFromKey(msg *events.Message, key *waCommon.MessageKey) (types.JID, error) {
+	if key.GetFromMe() {
+		// fromMe always means the poll and vote were sent by the same user
+		// TODO this is wrong if the message key used @s.whatsapp.net, but the new event is from @lid
+		return msg.Info.Sender, nil
+	} else if msg.Info.Chat.Server == types.DefaultUserServer || msg.Info.Chat.Server == types.HiddenUserServer {
+		sender, err := types.ParseJID(key.GetRemoteJID())
+		if err != nil {
+			return types.EmptyJID, fmt.Errorf("failed to parse JID %q of original message sender: %w", key.GetRemoteJID(), err)
+		}
+		return sender, nil
+	} else {
+		sender, err := types.ParseJID(key.GetParticipant())
+		if sender.Server != types.DefaultUserServer && sender.Server != types.HiddenUserServer {
+			err = fmt.Errorf("unexpected server")
+		}
+		if err != nil {
+			return types.EmptyJID, fmt.Errorf("failed to parse JID %q of original message sender: %w", key.GetParticipant(), err)
+		}
+		return sender, nil
+	}
+}
+
+type messageEncryptedSecret interface {
+	GetEncIV() []byte
+	GetEncPayload() []byte
+}
+
+func (cli *Client) decryptMsgSecret(ctx context.Context, msg *events.Message, useCase MsgSecretType, encrypted messageEncryptedSecret, origMsgKey *waCommon.MessageKey) ([]byte, error) {
+	if cli == nil {
+		return nil, ErrClientIsNil
+	}
+	origSender, err := getOrigSenderFromKey(msg, origMsgKey)
+	if err != nil {
+		return nil, err
+	}
+	baseEncKey, origSender, err := cli.Store.MsgSecrets.GetMessageSecret(ctx, msg.Info.Chat, origSender, origMsgKey.GetID())
+	if err != nil {
+		return nil, fmt.Errorf("failed to get original message secret key: %w", err)
+	}
+	if baseEncKey == nil {
+		return nil, ErrOriginalMessageSecretNotFound
+	}
+	secretKey, additionalData := generateMsgSecretKey(useCase, msg.Info.Sender, origMsgKey.GetID(), origSender, baseEncKey)
+	plaintext, err := gcmutil.Decrypt(secretKey, encrypted.GetEncIV(), encrypted.GetEncPayload(), additionalData)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decrypt secret message: %w", err)
+	}
+	return plaintext, nil
+}
+
+func (cli *Client) encryptMsgSecret(ctx context.Context, ownID, chat, origSender types.JID, origMsgID types.MessageID, useCase MsgSecretType, plaintext []byte) (ciphertext, iv []byte, err error) {
+	if cli == nil {
+		return nil, nil, ErrClientIsNil
+	} else if ownID.IsEmpty() {
+		return nil, nil, ErrNotLoggedIn
+	}
+
+	baseEncKey, origSender, err := cli.Store.MsgSecrets.GetMessageSecret(ctx, chat, origSender, origMsgID)
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to get original message secret key: %w", err)
+	} else if baseEncKey == nil {
+		return nil, nil, ErrOriginalMessageSecretNotFound
+	}
+	secretKey, additionalData := generateMsgSecretKey(useCase, ownID, origMsgID, origSender, baseEncKey)
+
+	iv = random.Bytes(12)
+	ciphertext, err = gcmutil.Encrypt(secretKey, iv, plaintext, additionalData)
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to encrypt secret message: %w", err)
+	}
+	return ciphertext, iv, nil
+}
+
+func (cli *Client) decryptBotMessage(ctx context.Context, messageSecret []byte, msMsg messageEncryptedSecret, messageID types.MessageID, targetSenderJID types.JID, info *types.MessageInfo) ([]byte, error) {
+	newKey, additionalData := generateMsgSecretKey("", info.Sender, messageID, targetSenderJID, applyBotMessageHKDF(messageSecret))
+
+	plaintext, err := gcmutil.Decrypt(newKey, msMsg.GetEncIV(), msMsg.GetEncPayload(), additionalData)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decrypt secret message: %w", err)
+	}
+
+	return plaintext, nil
+}
+
+// DecryptReaction decrypts a reaction message in a community announcement group.
+//
+//	if evt.Message.GetEncReactionMessage() != nil {
+//		reaction, err := cli.DecryptReaction(evt)
+//		if err != nil {
+//			fmt.Println(":(", err)
+//			return
+//		}
+//		fmt.Printf("Reaction message: %+v\n", reaction)
+//	}
+func (cli *Client) DecryptReaction(ctx context.Context, reaction *events.Message) (*waE2E.ReactionMessage, error) {
+	encReaction := reaction.Message.GetEncReactionMessage()
+	if encReaction == nil {
+		return nil, ErrNotEncryptedReactionMessage
+	}
+	plaintext, err := cli.decryptMsgSecret(ctx, reaction, EncSecretReaction, encReaction, encReaction.GetTargetMessageKey())
+	if err != nil {
+		return nil, fmt.Errorf("failed to decrypt reaction: %w", err)
+	}
+	var msg waE2E.ReactionMessage
+	err = proto.Unmarshal(plaintext, &msg)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode reaction protobuf: %w", err)
+	}
+	return &msg, nil
+}
+
+// DecryptComment decrypts a reply/comment message in a community announcement group.
+//
+//	if evt.Message.GetEncCommentMessage() != nil {
+//		comment, err := cli.DecryptComment(evt)
+//		if err != nil {
+//			fmt.Println(":(", err)
+//			return
+//		}
+//		fmt.Printf("Comment message: %+v\n", comment)
+//	}
+func (cli *Client) DecryptComment(ctx context.Context, comment *events.Message) (*waE2E.Message, error) {
+	encComment := comment.Message.GetEncCommentMessage()
+	if encComment == nil {
+		return nil, ErrNotEncryptedCommentMessage
+	}
+	plaintext, err := cli.decryptMsgSecret(ctx, comment, EncSecretComment, encComment, encComment.GetTargetMessageKey())
+	if err != nil {
+		return nil, fmt.Errorf("failed to decrypt comment: %w", err)
+	}
+	var msg waE2E.Message
+	err = proto.Unmarshal(plaintext, &msg)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode comment protobuf: %w", err)
+	}
+	return &msg, nil
+}
+
+// DecryptPollVote decrypts a poll update message. The vote itself includes SHA-256 hashes of the selected options.
+//
+//	if evt.Message.GetPollUpdateMessage() != nil {
+//		pollVote, err := cli.DecryptPollVote(evt)
+//		if err != nil {
+//			fmt.Println(":(", err)
+//			return
+//		}
+//		fmt.Println("Selected hashes:")
+//		for _, hash := range pollVote.GetSelectedOptions() {
+//			fmt.Printf("- %X\n", hash)
+//		}
+//	}
+func (cli *Client) DecryptPollVote(ctx context.Context, vote *events.Message) (*waE2E.PollVoteMessage, error) {
+	pollUpdate := vote.Message.GetPollUpdateMessage()
+	if pollUpdate == nil {
+		return nil, ErrNotPollUpdateMessage
+	}
+	plaintext, err := cli.decryptMsgSecret(ctx, vote, EncSecretPollVote, pollUpdate.GetVote(), pollUpdate.GetPollCreationMessageKey())
+	if err != nil {
+		return nil, fmt.Errorf("failed to decrypt poll vote: %w", err)
+	}
+	var msg waE2E.PollVoteMessage
+	err = proto.Unmarshal(plaintext, &msg)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode poll vote protobuf: %w", err)
+	}
+	return &msg, nil
+}
+
+func (cli *Client) DecryptSecretEncryptedMessage(ctx context.Context, evt *events.Message) (*waE2E.Message, error) {
+	encMessage := evt.Message.GetSecretEncryptedMessage()
+	if encMessage == nil {
+		return nil, ErrNotSecretEncryptedMessage
+	}
+	if encMessage.GetSecretEncType() != waE2E.SecretEncryptedMessage_EVENT_EDIT {
+		return nil, fmt.Errorf("unsupported secret enc type: %s", encMessage.SecretEncType.String())
+	}
+	plaintext, err := cli.decryptMsgSecret(ctx, evt, EncSecretEventEdit, encMessage, encMessage.GetTargetMessageKey())
+	if err != nil {
+		return nil, fmt.Errorf("failed to decrypt message: %w", err)
+	}
+	var msg waE2E.Message
+	err = proto.Unmarshal(plaintext, &msg)
+	if err != nil {
+		return nil, fmt.Errorf("failed to decode message protobuf: %w", err)
+	}
+	if evt.Message.MessageContextInfo != nil && msg.MessageContextInfo == nil {
+		msg.MessageContextInfo = evt.Message.MessageContextInfo
+	}
+	return &msg, nil
+}
+
+func getKeyFromInfo(msgInfo *types.MessageInfo) *waCommon.MessageKey {
+	creationKey := &waCommon.MessageKey{
+		RemoteJID: proto.String(msgInfo.Chat.String()),
+		FromMe:    proto.Bool(msgInfo.IsFromMe),
+		ID:        proto.String(msgInfo.ID),
+	}
+	if msgInfo.IsGroup {
+		creationKey.Participant = proto.String(msgInfo.Sender.String())
+	}
+	return creationKey
+}
+
+// HashPollOptions hashes poll option names using SHA-256 for voting.
+// This is used by BuildPollVote to convert selected option names to hashes.
+func HashPollOptions(optionNames []string) [][]byte {
+	optionHashes := make([][]byte, len(optionNames))
+	for i, option := range optionNames {
+		optionHash := sha256.Sum256([]byte(option))
+		optionHashes[i] = optionHash[:]
+	}
+	return optionHashes
+}
+
+// BuildPollVote builds a poll vote message using the given poll message info and option names.
+// The built message can be sent normally using Client.SendMessage.
+//
+// For example, to vote for the first option after receiving a message event (*events.Message):
+//
+//	if evt.Message.GetPollCreationMessage() != nil {
+//		pollVoteMsg, err := cli.BuildPollVote(&evt.Info, []string{evt.Message.GetPollCreationMessage().GetOptions()[0].GetOptionName()})
+//		if err != nil {
+//			fmt.Println(":(", err)
+//			return
+//		}
+//		resp, err := cli.SendMessage(context.Background(), evt.Info.Chat, pollVoteMsg)
+//	}
+func (cli *Client) BuildPollVote(ctx context.Context, pollInfo *types.MessageInfo, optionNames []string) (*waE2E.Message, error) {
+	pollUpdate, err := cli.EncryptPollVote(ctx, pollInfo, &waE2E.PollVoteMessage{
+		SelectedOptions: HashPollOptions(optionNames),
+	})
+	return &waE2E.Message{PollUpdateMessage: pollUpdate}, err
+}
+
+// BuildPollCreation builds a poll creation message with the given poll name, options and maximum number of selections.
+// The built message can be sent normally using Client.SendMessage.
+//
+//	resp, err := cli.SendMessage(context.Background(), chat, cli.BuildPollCreation("meow?", []string{"yes", "no"}, 1))
+func (cli *Client) BuildPollCreation(name string, optionNames []string, selectableOptionCount int) *waE2E.Message {
+	msgSecret := random.Bytes(32)
+	if selectableOptionCount < 0 || selectableOptionCount > len(optionNames) {
+		selectableOptionCount = 0
+	}
+	options := make([]*waE2E.PollCreationMessage_Option, len(optionNames))
+	for i, option := range optionNames {
+		options[i] = &waE2E.PollCreationMessage_Option{OptionName: proto.String(option)}
+	}
+	return &waE2E.Message{
+		PollCreationMessage: &waE2E.PollCreationMessage{
+			Name:                   proto.String(name),
+			Options:                options,
+			SelectableOptionsCount: proto.Uint32(uint32(selectableOptionCount)),
+		},
+		MessageContextInfo: &waE2E.MessageContextInfo{
+			MessageSecret: msgSecret,
+		},
+	}
+}
+
+// EncryptPollVote encrypts a poll vote message. This is a slightly lower-level function, using BuildPollVote is recommended.
+func (cli *Client) EncryptPollVote(ctx context.Context, pollInfo *types.MessageInfo, vote *waE2E.PollVoteMessage) (*waE2E.PollUpdateMessage, error) {
+	plaintext, err := proto.Marshal(vote)
+	if err != nil {
+		return nil, fmt.Errorf("failed to marshal poll vote protobuf: %w", err)
+	}
+	ciphertext, iv, err := cli.encryptMsgSecret(ctx, cli.getOwnID(), pollInfo.Chat, pollInfo.Sender, pollInfo.ID, EncSecretPollVote, plaintext)
+	if err != nil {
+		return nil, fmt.Errorf("failed to encrypt poll vote: %w", err)
+	}
+	return &waE2E.PollUpdateMessage{
+		PollCreationMessageKey: getKeyFromInfo(pollInfo),
+		Vote: &waE2E.PollEncValue{
+			EncPayload: ciphertext,
+			EncIV:      iv,
+		},
+		SenderTimestampMS: proto.Int64(time.Now().UnixMilli()),
+	}, nil
+}
+
+func (cli *Client) EncryptComment(ctx context.Context, rootMsgInfo *types.MessageInfo, comment *waE2E.Message) (*waE2E.Message, error) {
+	plaintext, err := proto.Marshal(comment)
+	if err != nil {
+		return nil, fmt.Errorf("failed to marshal comment protobuf: %w", err)
+	}
+	// TODO is hardcoding LID here correct? What about polls?
+	ciphertext, iv, err := cli.encryptMsgSecret(ctx, cli.getOwnLID(), rootMsgInfo.Chat, rootMsgInfo.Sender, rootMsgInfo.ID, EncSecretComment, plaintext)
+	if err != nil {
+		return nil, fmt.Errorf("failed to encrypt comment: %w", err)
+	}
+	return &waE2E.Message{
+		EncCommentMessage: &waE2E.EncCommentMessage{
+			TargetMessageKey: &waCommon.MessageKey{
+				RemoteJID:   proto.String(rootMsgInfo.Chat.String()),
+				Participant: proto.String(rootMsgInfo.Sender.ToNonAD().String()),
+				FromMe:      proto.Bool(rootMsgInfo.IsFromMe),
+				ID:          proto.String(rootMsgInfo.ID),
+			},
+			EncPayload: ciphertext,
+			EncIV:      iv,
+		},
+	}, nil
+}
+
+func (cli *Client) EncryptReaction(ctx context.Context, rootMsgInfo *types.MessageInfo, reaction *waE2E.ReactionMessage) (*waE2E.EncReactionMessage, error) {
+	reactionKey := reaction.Key
+	reaction.Key = nil
+	plaintext, err := proto.Marshal(reaction)
+	if err != nil {
+		return nil, fmt.Errorf("failed to marshal reaction protobuf: %w", err)
+	}
+	ciphertext, iv, err := cli.encryptMsgSecret(ctx, cli.getOwnLID(), rootMsgInfo.Chat, rootMsgInfo.Sender, rootMsgInfo.ID, EncSecretReaction, plaintext)
+	if err != nil {
+		return nil, fmt.Errorf("failed to encrypt reaction: %w", err)
+	}
+	return &waE2E.EncReactionMessage{
+		TargetMessageKey: reactionKey,
+		EncPayload:       ciphertext,
+		EncIV:            iv,
+	}, nil
+}

+ 455 - 0
newsletter.go

@@ -0,0 +1,455 @@
+// Copyright (c) 2023 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"log"
+	"strings"
+	"time"
+
+	"github.com/beeper/argo-go/codec"
+	"github.com/beeper/argo-go/pkg/buf"
+
+	"go.mau.fi/whatsmeow/argo"
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waWa6"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+)
+
+// NewsletterSubscribeLiveUpdates subscribes to receive live updates from a WhatsApp channel temporarily (for the duration returned).
+func (cli *Client) NewsletterSubscribeLiveUpdates(ctx context.Context, jid types.JID) (time.Duration, error) {
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "newsletter",
+		Type:      iqSet,
+		To:        jid,
+		Content: []waBinary.Node{{
+			Tag: "live_updates",
+		}},
+	})
+	if err != nil {
+		return 0, err
+	}
+	child := resp.GetChildByTag("live_updates")
+	dur := child.AttrGetter().Int("duration")
+	return time.Duration(dur) * time.Second, nil
+}
+
+// NewsletterMarkViewed marks a channel message as viewed, incrementing the view counter.
+//
+// This is not the same as marking the channel as read on your other devices, use the usual MarkRead function for that.
+func (cli *Client) NewsletterMarkViewed(ctx context.Context, jid types.JID, serverIDs []types.MessageServerID) error {
+	if cli == nil {
+		return ErrClientIsNil
+	}
+	items := make([]waBinary.Node, len(serverIDs))
+	for i, id := range serverIDs {
+		items[i] = waBinary.Node{
+			Tag: "item",
+			Attrs: waBinary.Attrs{
+				"server_id": id,
+			},
+		}
+	}
+	reqID := cli.generateRequestID()
+	resp := cli.waitResponse(reqID)
+	err := cli.sendNode(ctx, waBinary.Node{
+		Tag: "receipt",
+		Attrs: waBinary.Attrs{
+			"to":   jid,
+			"type": "view",
+			"id":   reqID,
+		},
+		Content: []waBinary.Node{{
+			Tag:     "list",
+			Content: items,
+		}},
+	})
+	if err != nil {
+		cli.cancelResponse(reqID, resp)
+		return err
+	}
+	// TODO handle response?
+	<-resp
+	return nil
+}
+
+// NewsletterSendReaction sends a reaction to a channel message.
+// To remove a reaction sent earlier, set reaction to an empty string.
+//
+// The last parameter is the message ID of the reaction itself. It can be left empty to let whatsmeow generate a random one.
+func (cli *Client) NewsletterSendReaction(ctx context.Context, jid types.JID, serverID types.MessageServerID, reaction string, messageID types.MessageID) error {
+	if messageID == "" {
+		messageID = cli.GenerateMessageID()
+	}
+	reactionAttrs := waBinary.Attrs{}
+	messageAttrs := waBinary.Attrs{
+		"to":        jid,
+		"id":        messageID,
+		"server_id": serverID,
+		"type":      "reaction",
+	}
+	if reaction != "" {
+		reactionAttrs["code"] = reaction
+	} else {
+		messageAttrs["edit"] = string(types.EditAttributeSenderRevoke)
+	}
+	return cli.sendNode(ctx, waBinary.Node{
+		Tag:   "message",
+		Attrs: messageAttrs,
+		Content: []waBinary.Node{{
+			Tag:   "reaction",
+			Attrs: reactionAttrs,
+		}},
+	})
+}
+
+const (
+	queryFetchNewsletter           = "6563316087068696"
+	queryFetchNewsletterDehydrated = "7272540469429201"
+	queryRecommendedNewsletters    = "7263823273662354" // variables -> input -> {limit: 20, country_codes: [string]}, output: xwa2_newsletters_recommended
+	queryNewslettersDirectory      = "6190824427689257" // variables -> input -> {view: "RECOMMENDED", limit: 50, start_cursor: base64, filters: {country_codes: [string]}}
+	querySubscribedNewsletters     = "6388546374527196" // variables -> empty, output: xwa2_newsletter_subscribed
+	queryNewsletterSubscribers     = "9800646650009898" // variables -> input -> {newsletter_id, count}, output: xwa2_newsletter_subscribers -> subscribers -> edges
+	mutationMuteNewsletter         = "6274038279359549" // variables -> {newsletter_id, updates->{description, settings}}, output: xwa2_newsletter_update -> NewsletterMetadata without viewer meta
+	mutationUnmuteNewsletter       = "6068417879924485"
+	mutationUpdateNewsletter       = "7150902998257522"
+	mutationCreateNewsletter       = "6234210096708695"
+	mutationUnfollowNewsletter     = "6392786840836363"
+	mutationFollowNewsletter       = "9926858900719341"
+
+	// desktop & mobile
+	queryFetchNewsletterDesktop        = "9779843322044422"
+	queryRecommendedNewslettersDesktop = "27256776790637714"
+	querySubscribedNewslettersDesktop  = "8621797084555037"
+	queryNewsletterSubscribersDesktop  = "25403502652570342"
+	mutationMuteNewsletterDesktop      = "5971669009605755" // variables -> {newsletter_id, updates->{description, settings}}, output: xwa2_newsletter_update -> NewsletterMetadata without viewer meta
+	mutationUnmuteNewsletterDesktop    = "6104029483058502"
+	mutationUpdateNewsletterDesktop    = "7839742399440946"
+	mutationCreateNewsletterDesktop    = "27527996220149684"
+	mutationUnfollowNewsletterDesktop  = "8782612271820087"
+	mutationFollowNewsletterDesktop    = "8621797084555037"
+)
+
+func convertQueryID(cli *Client, queryID string) string {
+	if payload := cli.Store.GetClientPayload(); payload.GetUserAgent().Platform == waWa6.ClientPayload_UserAgent_MACOS.Enum() || payload.GetWebInfo() == nil {
+		switch queryID {
+		case queryFetchNewsletter:
+			return queryFetchNewsletterDesktop
+		case queryRecommendedNewsletters:
+			return queryRecommendedNewslettersDesktop
+		case querySubscribedNewsletters:
+			return querySubscribedNewslettersDesktop
+		case queryNewsletterSubscribers:
+			return queryNewsletterSubscribersDesktop
+		case mutationMuteNewsletter:
+			return mutationMuteNewsletterDesktop
+		case mutationUnmuteNewsletter:
+			return mutationUnmuteNewsletterDesktop
+		case mutationUpdateNewsletter:
+			return mutationUpdateNewsletterDesktop
+		case mutationCreateNewsletter:
+			return mutationCreateNewsletterDesktop
+		case mutationUnfollowNewsletter:
+			return mutationUnfollowNewsletterDesktop
+		case mutationFollowNewsletter:
+			return mutationFollowNewsletterDesktop
+		default:
+			return queryID
+		}
+	} else {
+		return queryID
+	}
+}
+
+func (cli *Client) sendMexIQ(ctx context.Context, queryID string, variables any) (json.RawMessage, error) {
+	if store.BaseClientPayload.GetUserAgent().GetPlatform() == waWa6.ClientPayload_UserAgent_MACOS {
+		return nil, fmt.Errorf("argo decoding is currently broken")
+	}
+	queryID = convertQueryID(cli, queryID)
+	payload, err := json.Marshal(map[string]any{
+		"variables": variables,
+	})
+	if err != nil {
+		return nil, err
+	}
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "w:mex",
+		Type:      iqGet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "query",
+			Attrs: waBinary.Attrs{
+				"query_id": queryID,
+			},
+			Content: payload,
+		}},
+	})
+	if err != nil {
+		return nil, err
+	}
+	result, ok := resp.GetOptionalChildByTag("result")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "result", In: "mex response"}
+	}
+	resultContent, ok := result.Content.([]byte)
+	if !ok {
+		return nil, fmt.Errorf("unexpected content type %T in mex response", result.Content)
+	}
+	if result.AttrGetter().OptionalString("format") == "argo" {
+		if true {
+			return nil, fmt.Errorf("argo decoding is currently broken")
+		}
+		store, err := argo.GetStore()
+		if err != nil {
+			return nil, err
+		}
+		queryIDMap, err := argo.GetQueryIDToMessageName()
+		if err != nil {
+			return nil, err
+		}
+		wt := store[queryIDMap[queryID]]
+
+		decoder, err := codec.NewArgoDecoder(buf.NewBufReadonly(resultContent))
+		if err != nil {
+			return nil, err
+		}
+		data, err := decoder.ArgoToMap(wt)
+		if err != nil {
+			log.Fatalf("argo to map error: %v", err)
+		}
+		b, err := json.Marshal(data)
+		if err != nil {
+			return nil, err
+		}
+		return b, nil
+	} else {
+		var gqlResp types.GraphQLResponse
+		err = json.Unmarshal(resultContent, &gqlResp)
+		if err != nil {
+			return nil, fmt.Errorf("failed to unmarshal graphql response: %w", err)
+		} else if len(gqlResp.Errors) > 0 {
+			return gqlResp.Data, fmt.Errorf("graphql error: %w", gqlResp.Errors)
+		}
+		return gqlResp.Data, nil
+	}
+}
+
+type respGetNewsletterInfo struct {
+	Newsletter *types.NewsletterMetadata `json:"xwa2_newsletter"`
+}
+
+func (cli *Client) getNewsletterInfo(ctx context.Context, input map[string]any, fetchViewerMeta bool) (*types.NewsletterMetadata, error) {
+	data, err := cli.sendMexIQ(ctx, queryFetchNewsletter, map[string]any{
+		"fetch_creation_time":   true,
+		"fetch_full_image":      true,
+		"fetch_viewer_metadata": fetchViewerMeta,
+		"input":                 input,
+	})
+	var respData respGetNewsletterInfo
+	if data != nil {
+		jsonErr := json.Unmarshal(data, &respData)
+		if err == nil && jsonErr != nil {
+			err = jsonErr
+		}
+	}
+	return respData.Newsletter, err
+}
+
+// GetNewsletterInfo gets the info of a newsletter that you're joined to.
+func (cli *Client) GetNewsletterInfo(ctx context.Context, jid types.JID) (*types.NewsletterMetadata, error) {
+	return cli.getNewsletterInfo(ctx, map[string]any{
+		"key":  jid.String(),
+		"type": types.NewsletterKeyTypeJID,
+	}, true)
+}
+
+// GetNewsletterInfoWithInvite gets the info of a newsletter with an invite link.
+//
+// You can either pass the full link (https://whatsapp.com/channel/...) or just the `...` part.
+//
+// Note that the ViewerMeta field of the returned NewsletterMetadata will be nil.
+func (cli *Client) GetNewsletterInfoWithInvite(ctx context.Context, key string) (*types.NewsletterMetadata, error) {
+	return cli.getNewsletterInfo(ctx, map[string]any{
+		"key":  strings.TrimPrefix(key, NewsletterLinkPrefix),
+		"type": types.NewsletterKeyTypeInvite,
+	}, false)
+}
+
+type respGetSubscribedNewsletters struct {
+	Newsletters []*types.NewsletterMetadata `json:"xwa2_newsletter_subscribed"`
+}
+
+// GetSubscribedNewsletters gets the info of all newsletters that you're joined to.
+func (cli *Client) GetSubscribedNewsletters(ctx context.Context) ([]*types.NewsletterMetadata, error) {
+	data, err := cli.sendMexIQ(ctx, querySubscribedNewsletters, map[string]any{})
+	var respData respGetSubscribedNewsletters
+	if data != nil {
+		jsonErr := json.Unmarshal(data, &respData)
+		if err == nil && jsonErr != nil {
+			err = jsonErr
+		}
+	}
+	return respData.Newsletters, err
+}
+
+type CreateNewsletterParams struct {
+	Name        string `json:"name"`
+	Description string `json:"description,omitempty"`
+	Picture     []byte `json:"picture,omitempty"`
+}
+
+type respCreateNewsletter struct {
+	Newsletter *types.NewsletterMetadata `json:"xwa2_newsletter_create"`
+}
+
+// CreateNewsletter creates a new WhatsApp channel.
+func (cli *Client) CreateNewsletter(ctx context.Context, params CreateNewsletterParams) (*types.NewsletterMetadata, error) {
+	resp, err := cli.sendMexIQ(ctx, mutationCreateNewsletter, map[string]any{
+		"newsletter_input": &params,
+	})
+	if err != nil {
+		return nil, err
+	}
+	var respData respCreateNewsletter
+	err = json.Unmarshal(resp, &respData)
+	if err != nil {
+		return nil, err
+	}
+	return respData.Newsletter, nil
+}
+
+// AcceptTOSNotice accepts a ToS notice.
+//
+// To accept the terms for creating newsletters, use
+//
+//	cli.AcceptTOSNotice("20601218", "5")
+func (cli *Client) AcceptTOSNotice(ctx context.Context, noticeID, stage string) error {
+	_, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "tos",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "notice",
+			Attrs: waBinary.Attrs{
+				"id":    noticeID,
+				"stage": stage,
+			},
+		}},
+	})
+	return err
+}
+
+// NewsletterToggleMute changes the mute status of a newsletter.
+func (cli *Client) NewsletterToggleMute(ctx context.Context, jid types.JID, mute bool) error {
+	query := mutationUnmuteNewsletter
+	if mute {
+		query = mutationMuteNewsletter
+	}
+	_, err := cli.sendMexIQ(ctx, query, map[string]any{
+		"newsletter_id": jid.String(),
+	})
+	return err
+}
+
+// FollowNewsletter makes the user follow (join) a WhatsApp channel.
+func (cli *Client) FollowNewsletter(ctx context.Context, jid types.JID) error {
+	_, err := cli.sendMexIQ(ctx, mutationFollowNewsletter, map[string]any{
+		"newsletter_id": jid.String(),
+	})
+	return err
+}
+
+// UnfollowNewsletter makes the user unfollow (leave) a WhatsApp channel.
+func (cli *Client) UnfollowNewsletter(ctx context.Context, jid types.JID) error {
+	_, err := cli.sendMexIQ(ctx, mutationUnfollowNewsletter, map[string]any{
+		"newsletter_id": jid.String(),
+	})
+	return err
+}
+
+type GetNewsletterMessagesParams struct {
+	Count  int
+	Before types.MessageServerID
+}
+
+// GetNewsletterMessages gets messages in a WhatsApp channel.
+func (cli *Client) GetNewsletterMessages(ctx context.Context, jid types.JID, params *GetNewsletterMessagesParams) ([]*types.NewsletterMessage, error) {
+	attrs := waBinary.Attrs{
+		"type": "jid",
+		"jid":  jid,
+	}
+	if params != nil {
+		if params.Count != 0 {
+			attrs["count"] = params.Count
+		}
+		if params.Before != 0 {
+			attrs["before"] = params.Before
+		}
+	}
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "newsletter",
+		Type:      iqGet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag:   "messages",
+			Attrs: attrs,
+		}},
+	})
+	if err != nil {
+		return nil, err
+	}
+	messages, ok := resp.GetOptionalChildByTag("messages")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "messages", In: "newsletter messages response"}
+	}
+	return cli.parseNewsletterMessages(&messages), nil
+}
+
+type GetNewsletterUpdatesParams struct {
+	Count int
+	Since time.Time
+	After types.MessageServerID
+}
+
+// GetNewsletterMessageUpdates gets updates in a WhatsApp channel.
+//
+// These are the same kind of updates that NewsletterSubscribeLiveUpdates triggers (reaction and view counts).
+func (cli *Client) GetNewsletterMessageUpdates(ctx context.Context, jid types.JID, params *GetNewsletterUpdatesParams) ([]*types.NewsletterMessage, error) {
+	attrs := waBinary.Attrs{}
+	if params != nil {
+		if params.Count != 0 {
+			attrs["count"] = params.Count
+		}
+		if !params.Since.IsZero() {
+			attrs["since"] = params.Since.Unix()
+		}
+		if params.After != 0 {
+			attrs["after"] = params.After
+		}
+	}
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "newsletter",
+		Type:      iqGet,
+		To:        jid,
+		Content: []waBinary.Node{{
+			Tag:   "message_updates",
+			Attrs: attrs,
+		}},
+	})
+	if err != nil {
+		return nil, err
+	}
+	messages, ok := resp.GetOptionalChildByTag("message_updates", "messages")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "messages", In: "newsletter messages response"}
+	}
+	return cli.parseNewsletterMessages(&messages), nil
+}

+ 466 - 0
notification.go

@@ -0,0 +1,466 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"slices"
+
+	"google.golang.org/protobuf/proto"
+
+	"go.mau.fi/whatsmeow/appstate"
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waE2E"
+	"go.mau.fi/whatsmeow/store"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+func (cli *Client) handleEncryptNotification(ctx context.Context, node *waBinary.Node) {
+	from := node.AttrGetter().JID("from")
+	if from == types.ServerJID {
+		count := node.GetChildByTag("count")
+		ag := count.AttrGetter()
+		otksLeft := ag.Int("value")
+		if !ag.OK() {
+			cli.Log.Warnf("Didn't get number of OTKs left in encryption notification %s", node.XMLString())
+			return
+		}
+		cli.Log.Infof("Got prekey count from server: %s", node.XMLString())
+		if otksLeft < MinPreKeyCount {
+			cli.uploadPreKeys(ctx, false)
+		}
+	} else if _, ok := node.GetOptionalChildByTag("identity"); ok {
+		cli.Log.Debugf("Got identity change for %s: %s, deleting all identities/sessions for that number", from, node.XMLString())
+		err := cli.Store.Identities.DeleteAllIdentities(ctx, from.User)
+		if err != nil {
+			cli.Log.Warnf("Failed to delete all identities of %s from store after identity change: %v", from, err)
+		}
+		err = cli.Store.Sessions.DeleteAllSessions(ctx, from.User)
+		if err != nil {
+			cli.Log.Warnf("Failed to delete all sessions of %s from store after identity change: %v", from, err)
+		}
+		ts := node.AttrGetter().UnixTime("t")
+		cli.dispatchEvent(&events.IdentityChange{JID: from, Timestamp: ts})
+	} else {
+		cli.Log.Debugf("Got unknown encryption notification from server: %s", node.XMLString())
+	}
+}
+
+func (cli *Client) handleAppStateNotification(ctx context.Context, node *waBinary.Node) {
+	for _, collection := range node.GetChildrenByTag("collection") {
+		ag := collection.AttrGetter()
+		name := appstate.WAPatchName(ag.String("name"))
+		version := ag.Uint64("version")
+		cli.Log.Debugf("Got server sync notification that app state %s has updated to version %d", name, version)
+		err := cli.FetchAppState(ctx, name, false, false)
+		if errors.Is(err, ErrIQDisconnected) || errors.Is(err, ErrNotConnected) {
+			// There are some app state changes right before a remote logout, so stop syncing if we're disconnected.
+			cli.Log.Debugf("Failed to sync app state after notification: %v, not trying to sync other states", err)
+			return
+		} else if err != nil {
+			cli.Log.Errorf("Failed to sync app state after notification: %v", err)
+		}
+	}
+}
+
+func (cli *Client) handlePictureNotification(ctx context.Context, node *waBinary.Node) {
+	ts := node.AttrGetter().UnixTime("t")
+	for _, child := range node.GetChildren() {
+		ag := child.AttrGetter()
+		var evt events.Picture
+		evt.Timestamp = ts
+		evt.JID = ag.JID("jid")
+		evt.Author = ag.OptionalJIDOrEmpty("author")
+		if child.Tag == "delete" {
+			evt.Remove = true
+		} else if child.Tag == "add" {
+			evt.PictureID = ag.String("id")
+		} else if child.Tag == "set" {
+			// TODO sometimes there's a hash and no ID?
+			evt.PictureID = ag.String("id")
+		} else {
+			continue
+		}
+		if !ag.OK() {
+			cli.Log.Debugf("Ignoring picture change notification with unexpected attributes: %v", ag.Error())
+			continue
+		}
+		cli.dispatchEvent(&evt)
+	}
+}
+
+func (cli *Client) handleDeviceNotification(ctx context.Context, node *waBinary.Node) {
+	cli.userDevicesCacheLock.Lock()
+	defer cli.userDevicesCacheLock.Unlock()
+	ag := node.AttrGetter()
+	from := ag.JID("from")
+	fromLID := ag.OptionalJID("lid")
+	if fromLID != nil {
+		cli.StoreLIDPNMapping(ctx, *fromLID, from)
+	}
+	cached, ok := cli.userDevicesCache[from]
+	if !ok {
+		cli.Log.Debugf("No device list cached for %s, ignoring device list notification", from)
+		return
+	}
+	var cachedLID deviceCache
+	var cachedLIDHash string
+	if fromLID != nil {
+		cachedLID = cli.userDevicesCache[*fromLID]
+		cachedLIDHash = participantListHashV2(cachedLID.devices)
+	}
+	cachedParticipantHash := participantListHashV2(cached.devices)
+	for _, child := range node.GetChildren() {
+		cag := child.AttrGetter()
+		deviceHash := cag.String("device_hash")
+		deviceLIDHash := cag.OptionalString("device_lid_hash")
+		deviceChild, _ := child.GetOptionalChildByTag("device")
+		changedDeviceJID := deviceChild.AttrGetter().JID("jid")
+		changedDeviceLID := deviceChild.AttrGetter().OptionalJID("lid")
+		switch child.Tag {
+		case "add":
+			cached.devices = append(cached.devices, changedDeviceJID)
+			if changedDeviceLID != nil {
+				cachedLID.devices = append(cachedLID.devices, *changedDeviceLID)
+			}
+		case "remove":
+			cached.devices = slices.DeleteFunc(cached.devices, func(existing types.JID) bool {
+				return existing == changedDeviceJID
+			})
+			if changedDeviceLID != nil {
+				cachedLID.devices = slices.DeleteFunc(cachedLID.devices, func(existing types.JID) bool {
+					return existing == *changedDeviceLID
+				})
+			}
+		case "update":
+			// Exact meaning of "update" is unknown, clear device list cache to be safe
+			cli.Log.Debugf("%s's device list updated, dropping cached devices", from)
+			delete(cli.userDevicesCache, from)
+			continue
+		default:
+			cli.Log.Debugf("Unknown device list change tag %s", child.Tag)
+			continue
+		}
+		newParticipantHash := participantListHashV2(cached.devices)
+		if newParticipantHash == deviceHash {
+			cli.Log.Debugf("%s's device list hash changed from %s to %s (%s). New hash matches", from, cachedParticipantHash, deviceHash, child.Tag)
+			cli.userDevicesCache[from] = cached
+		} else {
+			cli.Log.Warnf("%s's device list hash changed from %s to %s (%s). New hash doesn't match (%s)", from, cachedParticipantHash, deviceHash, child.Tag, newParticipantHash)
+			delete(cli.userDevicesCache, from)
+		}
+		if fromLID != nil && changedDeviceLID != nil && deviceLIDHash != "" {
+			newLIDParticipantHash := participantListHashV2(cachedLID.devices)
+			if newLIDParticipantHash == deviceLIDHash {
+				cli.Log.Debugf("%s's device list hash changed from %s to %s (%s). New hash matches", fromLID, cachedLIDHash, deviceLIDHash, child.Tag)
+				cli.userDevicesCache[*fromLID] = cachedLID
+			} else {
+				cli.Log.Warnf("%s's device list hash changed from %s to %s (%s). New hash doesn't match (%s)", fromLID, cachedLIDHash, deviceLIDHash, child.Tag, newLIDParticipantHash)
+				delete(cli.userDevicesCache, *fromLID)
+			}
+		}
+	}
+}
+
+func (cli *Client) handleFBDeviceNotification(ctx context.Context, node *waBinary.Node) {
+	cli.userDevicesCacheLock.Lock()
+	defer cli.userDevicesCacheLock.Unlock()
+	jid := node.AttrGetter().JID("from")
+	userDevices := parseFBDeviceList(jid, node.GetChildByTag("devices"))
+	cli.userDevicesCache[jid] = userDevices
+}
+
+func (cli *Client) handleOwnDevicesNotification(ctx context.Context, node *waBinary.Node) {
+	cli.userDevicesCacheLock.Lock()
+	defer cli.userDevicesCacheLock.Unlock()
+	ownID := cli.getOwnID().ToNonAD()
+	if ownID.IsEmpty() {
+		cli.Log.Debugf("Ignoring own device change notification, session was deleted")
+		return
+	}
+	cached, ok := cli.userDevicesCache[ownID]
+	if !ok {
+		cli.Log.Debugf("Ignoring own device change notification, device list not cached")
+		return
+	}
+	oldHash := participantListHashV2(cached.devices)
+	expectedNewHash := node.AttrGetter().String("dhash")
+	var newDeviceList []types.JID
+	for _, child := range node.GetChildren() {
+		jid := child.AttrGetter().JID("jid")
+		if child.Tag == "device" && !jid.IsEmpty() {
+			newDeviceList = append(newDeviceList, jid)
+		}
+	}
+	newHash := participantListHashV2(newDeviceList)
+	if newHash != expectedNewHash {
+		cli.Log.Debugf("Received own device list change notification %s -> %s, but expected hash was %s", oldHash, newHash, expectedNewHash)
+		delete(cli.userDevicesCache, ownID)
+	} else {
+		cli.Log.Debugf("Received own device list change notification %s -> %s", oldHash, newHash)
+		cli.userDevicesCache[ownID] = deviceCache{devices: newDeviceList, dhash: expectedNewHash}
+	}
+}
+
+func (cli *Client) handleBlocklist(ctx context.Context, node *waBinary.Node) {
+	ag := node.AttrGetter()
+	evt := events.Blocklist{
+		Action:    events.BlocklistAction(ag.OptionalString("action")),
+		DHash:     ag.String("dhash"),
+		PrevDHash: ag.OptionalString("prev_dhash"),
+	}
+	for _, child := range node.GetChildren() {
+		ag := child.AttrGetter()
+		change := events.BlocklistChange{
+			JID:    ag.JID("jid"),
+			Action: events.BlocklistChangeAction(ag.String("action")),
+		}
+		if !ag.OK() {
+			cli.Log.Warnf("Unexpected data in blocklist event child %v: %v", child.XMLString(), ag.Error())
+			continue
+		}
+		evt.Changes = append(evt.Changes, change)
+	}
+	cli.dispatchEvent(&evt)
+}
+
+func (cli *Client) handleAccountSyncNotification(ctx context.Context, node *waBinary.Node) {
+	for _, child := range node.GetChildren() {
+		switch child.Tag {
+		case "privacy":
+			cli.handlePrivacySettingsNotification(ctx, &child)
+		case "devices":
+			cli.handleOwnDevicesNotification(ctx, &child)
+		case "picture":
+			cli.dispatchEvent(&events.Picture{
+				Timestamp: node.AttrGetter().UnixTime("t"),
+				JID:       cli.getOwnID().ToNonAD(),
+			})
+		case "blocklist":
+			cli.handleBlocklist(ctx, &child)
+		default:
+			cli.Log.Debugf("Unhandled account sync item %s", child.Tag)
+		}
+	}
+}
+
+func (cli *Client) handlePrivacyTokenNotification(ctx context.Context, node *waBinary.Node) {
+	ownJID := cli.getOwnID().ToNonAD()
+	ownLID := cli.getOwnLID().ToNonAD()
+	if ownJID.IsEmpty() {
+		cli.Log.Debugf("Ignoring privacy token notification, session was deleted")
+		return
+	}
+	tokens := node.GetChildByTag("tokens")
+	if tokens.Tag != "tokens" {
+		cli.Log.Warnf("privacy_token notification didn't contain <tokens> tag")
+		return
+	}
+	parentAG := node.AttrGetter()
+	sender := parentAG.JID("from")
+	if !parentAG.OK() {
+		cli.Log.Warnf("privacy_token notification didn't have a sender (%v)", parentAG.Error())
+		return
+	}
+	for _, child := range tokens.GetChildren() {
+		ag := child.AttrGetter()
+		if child.Tag != "token" {
+			cli.Log.Warnf("privacy_token notification contained unexpected <%s> tag", child.Tag)
+		} else if targetUser := ag.JID("jid"); targetUser != ownLID && targetUser != ownJID {
+			// Don't log about own privacy tokens for other users
+			if sender != ownJID && sender != ownLID {
+				cli.Log.Warnf("privacy_token notification contained token for different user %s", targetUser)
+			}
+		} else if tokenType := ag.String("type"); tokenType != "trusted_contact" {
+			cli.Log.Warnf("privacy_token notification contained unexpected token type %s", tokenType)
+		} else if token, ok := child.Content.([]byte); !ok {
+			cli.Log.Warnf("privacy_token notification contained non-binary token")
+		} else {
+			timestamp := ag.UnixTime("t")
+			if !ag.OK() {
+				cli.Log.Warnf("privacy_token notification is missing some fields: %v", ag.Error())
+			}
+			err := cli.Store.PrivacyTokens.PutPrivacyTokens(ctx, store.PrivacyToken{
+				User:      sender,
+				Token:     token,
+				Timestamp: timestamp,
+			})
+			if err != nil {
+				cli.Log.Errorf("Failed to save privacy token from %s: %v", sender, err)
+			} else {
+				cli.Log.Debugf("Stored privacy token from %s (ts: %v)", sender, timestamp)
+			}
+		}
+	}
+}
+
+func (cli *Client) parseNewsletterMessages(node *waBinary.Node) []*types.NewsletterMessage {
+	children := node.GetChildren()
+	output := make([]*types.NewsletterMessage, 0, len(children))
+	for _, child := range children {
+		if child.Tag != "message" {
+			continue
+		}
+		ag := child.AttrGetter()
+		msg := types.NewsletterMessage{
+			MessageServerID: ag.Int("server_id"),
+			MessageID:       ag.String("id"),
+			Type:            ag.String("type"),
+			Timestamp:       ag.UnixTime("t"),
+			ViewsCount:      0,
+			ReactionCounts:  nil,
+		}
+		for _, subchild := range child.GetChildren() {
+			switch subchild.Tag {
+			case "plaintext":
+				byteContent, ok := subchild.Content.([]byte)
+				if ok {
+					msg.Message = new(waE2E.Message)
+					err := proto.Unmarshal(byteContent, msg.Message)
+					if err != nil {
+						cli.Log.Warnf("Failed to unmarshal newsletter message: %v", err)
+						msg.Message = nil
+					}
+				}
+			case "views_count":
+				msg.ViewsCount = subchild.AttrGetter().Int("count")
+			case "reactions":
+				msg.ReactionCounts = make(map[string]int)
+				for _, reaction := range subchild.GetChildren() {
+					rag := reaction.AttrGetter()
+					msg.ReactionCounts[rag.String("code")] = rag.Int("count")
+				}
+			}
+		}
+		output = append(output, &msg)
+	}
+	return output
+}
+
+func (cli *Client) handleNewsletterNotification(ctx context.Context, node *waBinary.Node) {
+	ag := node.AttrGetter()
+	liveUpdates := node.GetChildByTag("live_updates")
+	cli.dispatchEvent(&events.NewsletterLiveUpdate{
+		JID:      ag.JID("from"),
+		Time:     ag.UnixTime("t"),
+		Messages: cli.parseNewsletterMessages(&liveUpdates),
+	})
+}
+
+type newsLetterEventWrapper struct {
+	Data newsletterEvent `json:"data"`
+}
+
+type newsletterEvent struct {
+	Join       *events.NewsletterJoin       `json:"xwa2_notify_newsletter_on_join"`
+	Leave      *events.NewsletterLeave      `json:"xwa2_notify_newsletter_on_leave"`
+	MuteChange *events.NewsletterMuteChange `json:"xwa2_notify_newsletter_on_mute_change"`
+	// _on_admin_metadata_update -> id, thread_metadata, messages
+	// _on_metadata_update
+	// _on_state_change -> id, is_requestor, state
+}
+
+func (cli *Client) handleMexNotification(ctx context.Context, node *waBinary.Node) {
+	for _, child := range node.GetChildren() {
+		if child.Tag != "update" {
+			continue
+		}
+		childData, ok := child.Content.([]byte)
+		if !ok {
+			continue
+		}
+		var wrapper newsLetterEventWrapper
+		err := json.Unmarshal(childData, &wrapper)
+		if err != nil {
+			cli.Log.Errorf("Failed to unmarshal JSON in mex event: %v", err)
+			continue
+		}
+		if wrapper.Data.Join != nil {
+			cli.dispatchEvent(wrapper.Data.Join)
+		} else if wrapper.Data.Leave != nil {
+			cli.dispatchEvent(wrapper.Data.Leave)
+		} else if wrapper.Data.MuteChange != nil {
+			cli.dispatchEvent(wrapper.Data.MuteChange)
+		}
+	}
+}
+
+func (cli *Client) handleStatusNotification(ctx context.Context, node *waBinary.Node) {
+	ag := node.AttrGetter()
+	child, found := node.GetOptionalChildByTag("set")
+	if !found {
+		cli.Log.Debugf("Status notifcation did not contain child with tag 'set'")
+		return
+	}
+	status, ok := child.Content.([]byte)
+	if !ok {
+		cli.Log.Warnf("Set status notification has unexpected content (%T)", child.Content)
+		return
+	}
+	cli.dispatchEvent(&events.UserAbout{
+		JID:       ag.JID("from"),
+		Timestamp: ag.UnixTime("t"),
+		Status:    string(status),
+	})
+}
+
+func (cli *Client) handleNotification(ctx context.Context, node *waBinary.Node) {
+	ag := node.AttrGetter()
+	notifType := ag.String("type")
+	if !ag.OK() {
+		return
+	}
+	var cancelled bool
+	defer cli.maybeDeferredAck(ctx, node)(&cancelled)
+	switch notifType {
+	case "encrypt":
+		go cli.handleEncryptNotification(ctx, node)
+	case "server_sync":
+		go cli.handleAppStateNotification(ctx, node)
+	case "account_sync":
+		go cli.handleAccountSyncNotification(ctx, node)
+	case "devices":
+		cli.handleDeviceNotification(ctx, node)
+	case "fbid:devices":
+		cli.handleFBDeviceNotification(ctx, node)
+	case "w:gp2":
+		evt, lidPairs, redactedPhones, err := cli.parseGroupNotification(node)
+		if err != nil {
+			cli.Log.Errorf("Failed to parse group notification: %v", err)
+		} else {
+			err = cli.Store.LIDs.PutManyLIDMappings(ctx, lidPairs)
+			if err != nil {
+				cli.Log.Errorf("Failed to store LID mappings from group notification: %v", err)
+			}
+			err = cli.Store.Contacts.PutManyRedactedPhones(ctx, redactedPhones)
+			if err != nil {
+				cli.Log.Warnf("Failed to store redacted phones from group notification: %v", err)
+			}
+			cancelled = cli.dispatchEvent(evt)
+		}
+	case "picture":
+		cli.handlePictureNotification(ctx, node)
+	case "mediaretry":
+		cli.handleMediaRetryNotification(ctx, node)
+	case "privacy_token":
+		cli.handlePrivacyTokenNotification(ctx, node)
+	case "link_code_companion_reg":
+		go cli.tryHandleCodePairNotification(ctx, node)
+	case "newsletter":
+		cli.handleNewsletterNotification(ctx, node)
+	case "mex":
+		cli.handleMexNotification(ctx, node)
+	case "status":
+		cli.handleStatusNotification(ctx, node)
+	// Other types: business, disappearing_mode, server, status, pay, psa
+	default:
+		cli.Log.Debugf("Unhandled notification with type %s", notifType)
+	}
+}

+ 243 - 0
pair-code.go

@@ -0,0 +1,243 @@
+// Copyright (c) 2023 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/sha256"
+	"encoding/base32"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"go.mau.fi/util/random"
+	"golang.org/x/crypto/curve25519"
+	"golang.org/x/crypto/pbkdf2"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/util/hkdfutil"
+	"go.mau.fi/whatsmeow/util/keys"
+)
+
+// PairClientType is the type of client to use with PairCode.
+// The type is automatically filled based on store.DeviceProps.PlatformType (which is what QR login uses).
+type PairClientType int
+
+const (
+	PairClientUnknown PairClientType = iota
+	PairClientChrome
+	PairClientEdge
+	PairClientFirefox
+	PairClientIE
+	PairClientOpera
+	PairClientSafari
+	PairClientElectron
+	PairClientUWP
+	PairClientOtherWebClient
+)
+
+var notNumbers = regexp.MustCompile("[^0-9]")
+var linkingBase32 = base32.NewEncoding("123456789ABCDEFGHJKLMNPQRSTVWXYZ")
+
+type phoneLinkingCache struct {
+	jid         types.JID
+	keyPair     *keys.KeyPair
+	linkingCode string
+	pairingRef  string
+}
+
+func generateCompanionEphemeralKey() (ephemeralKeyPair *keys.KeyPair, ephemeralKey []byte, encodedLinkingCode string) {
+	ephemeralKeyPair = keys.NewKeyPair()
+	salt := random.Bytes(32)
+	iv := random.Bytes(16)
+	linkingCode := random.Bytes(5)
+	encodedLinkingCode = linkingBase32.EncodeToString(linkingCode)
+	linkCodeKey := pbkdf2.Key([]byte(encodedLinkingCode), salt, 2<<16, 32, sha256.New)
+	linkCipherBlock, _ := aes.NewCipher(linkCodeKey)
+	encryptedPubkey := ephemeralKeyPair.Pub[:]
+	cipher.NewCTR(linkCipherBlock, iv).XORKeyStream(encryptedPubkey, encryptedPubkey)
+	ephemeralKey = make([]byte, 80)
+	copy(ephemeralKey[0:32], salt)
+	copy(ephemeralKey[32:48], iv)
+	copy(ephemeralKey[48:80], encryptedPubkey)
+	return
+}
+
+// PairPhone generates a pairing code that can be used to link to a phone without scanning a QR code.
+//
+// You must connect the client normally before calling this (which means you'll also receive a QR code
+// event, but that can be ignored when doing code pairing). You should also wait for `*events.QR` before
+// calling this to ensure the connection is fully established. If using [Client.GetQRChannel], wait for
+// the first item in the channel. Alternatively, sleeping for a second after calling Connect will probably work too.
+//
+// The exact expiry of pairing codes is unknown, but QR codes are always generated and the login websocket is closed
+// after the QR codes run out, which means there's a 160-second time limit. It is recommended to generate the pairing
+// code immediately after connecting to the websocket to have the maximum time.
+//
+// The clientType parameter must be one of the PairClient* constants, but which one doesn't matter.
+// The client display name must be formatted as `Browser (OS)`, and only common browsers/OSes are allowed
+// (the server will validate it and return 400 if it's wrong).
+//
+// See https://faq.whatsapp.com/1324084875126592 for more info
+func (cli *Client) PairPhone(ctx context.Context, phone string, showPushNotification bool, clientType PairClientType, clientDisplayName string) (string, error) {
+	if cli == nil {
+		return "", ErrClientIsNil
+	}
+	ephemeralKeyPair, ephemeralKey, encodedLinkingCode := generateCompanionEphemeralKey()
+	phone = notNumbers.ReplaceAllString(phone, "")
+	if len(phone) <= 6 {
+		return "", ErrPhoneNumberTooShort
+	} else if strings.HasPrefix(phone, "0") {
+		return "", ErrPhoneNumberIsNotInternational
+	}
+	jid := types.NewJID(phone, types.DefaultUserServer)
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "md",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "link_code_companion_reg",
+			Attrs: waBinary.Attrs{
+				"jid":   jid,
+				"stage": "companion_hello",
+
+				"should_show_push_notification": strconv.FormatBool(showPushNotification),
+			},
+			Content: []waBinary.Node{
+				{Tag: "link_code_pairing_wrapped_companion_ephemeral_pub", Content: ephemeralKey},
+				{Tag: "companion_server_auth_key_pub", Content: cli.Store.NoiseKey.Pub[:]},
+				{Tag: "companion_platform_id", Content: strconv.Itoa(int(clientType))},
+				{Tag: "companion_platform_display", Content: clientDisplayName},
+				{Tag: "link_code_pairing_nonce", Content: []byte{0}},
+			},
+		}},
+	})
+	if err != nil {
+		return "", err
+	}
+	pairingRefNode, ok := resp.GetOptionalChildByTag("link_code_companion_reg", "link_code_pairing_ref")
+	if !ok {
+		return "", &ElementMissingError{Tag: "link_code_pairing_ref", In: "code link registration response"}
+	}
+	pairingRef, ok := pairingRefNode.Content.([]byte)
+	if !ok {
+		return "", fmt.Errorf("unexpected type %T in content of link_code_pairing_ref tag", pairingRefNode.Content)
+	}
+	cli.phoneLinkingCache = &phoneLinkingCache{
+		jid:         jid,
+		keyPair:     ephemeralKeyPair,
+		linkingCode: encodedLinkingCode,
+		pairingRef:  string(pairingRef),
+	}
+	return encodedLinkingCode[0:4] + "-" + encodedLinkingCode[4:], nil
+}
+
+func (cli *Client) tryHandleCodePairNotification(ctx context.Context, parentNode *waBinary.Node) {
+	err := cli.handleCodePairNotification(ctx, parentNode)
+	if err != nil {
+		cli.Log.Errorf("Failed to handle code pair notification: %s", err)
+	}
+}
+
+func (cli *Client) handleCodePairNotification(ctx context.Context, parentNode *waBinary.Node) error {
+	node, ok := parentNode.GetOptionalChildByTag("link_code_companion_reg")
+	if !ok {
+		return &ElementMissingError{
+			Tag: "link_code_companion_reg",
+			In:  "notification",
+		}
+	}
+	linkCache := cli.phoneLinkingCache
+	if linkCache == nil {
+		return fmt.Errorf("received code pair notification without a pending pairing")
+	}
+	linkCodePairingRef, _ := node.GetChildByTag("link_code_pairing_ref").Content.([]byte)
+	if string(linkCodePairingRef) != linkCache.pairingRef {
+		return fmt.Errorf("pairing ref mismatch in code pair notification")
+	}
+	wrappedPrimaryEphemeralPub, ok := node.GetChildByTag("link_code_pairing_wrapped_primary_ephemeral_pub").Content.([]byte)
+	if !ok {
+		return &ElementMissingError{
+			Tag: "link_code_pairing_wrapped_primary_ephemeral_pub",
+			In:  "notification",
+		}
+	}
+	primaryIdentityPub, ok := node.GetChildByTag("primary_identity_pub").Content.([]byte)
+	if !ok {
+		return &ElementMissingError{
+			Tag: "primary_identity_pub",
+			In:  "notification",
+		}
+	}
+
+	advSecretRandom := random.Bytes(32)
+	keyBundleSalt := random.Bytes(32)
+	keyBundleNonce := random.Bytes(12)
+
+	// Decrypt the primary device's ephemeral public key, which was encrypted with the 8-character pairing code,
+	// then compute the DH shared secret using our ephemeral private key we generated earlier.
+	primarySalt := wrappedPrimaryEphemeralPub[0:32]
+	primaryIV := wrappedPrimaryEphemeralPub[32:48]
+	primaryEncryptedPubkey := wrappedPrimaryEphemeralPub[48:80]
+	linkCodeKey := pbkdf2.Key([]byte(linkCache.linkingCode), primarySalt, 2<<16, 32, sha256.New)
+	linkCipherBlock, err := aes.NewCipher(linkCodeKey)
+	if err != nil {
+		return fmt.Errorf("failed to create link cipher: %w", err)
+	}
+	primaryDecryptedPubkey := make([]byte, 32)
+	cipher.NewCTR(linkCipherBlock, primaryIV).XORKeyStream(primaryDecryptedPubkey, primaryEncryptedPubkey)
+	ephemeralSharedSecret, err := curve25519.X25519(linkCache.keyPair.Priv[:], primaryDecryptedPubkey)
+	if err != nil {
+		return fmt.Errorf("failed to compute ephemeral shared secret: %w", err)
+	}
+
+	// Encrypt and wrap key bundle containing our identity key, the primary device's identity key and the randomness used for the adv key.
+	keyBundleEncryptionKey := hkdfutil.SHA256(ephemeralSharedSecret, keyBundleSalt, []byte("link_code_pairing_key_bundle_encryption_key"), 32)
+	keyBundleCipherBlock, err := aes.NewCipher(keyBundleEncryptionKey)
+	if err != nil {
+		return fmt.Errorf("failed to create key bundle cipher: %w", err)
+	}
+	keyBundleGCM, err := cipher.NewGCM(keyBundleCipherBlock)
+	if err != nil {
+		return fmt.Errorf("failed to create key bundle GCM: %w", err)
+	}
+	plaintextKeyBundle := concatBytes(cli.Store.IdentityKey.Pub[:], primaryIdentityPub, advSecretRandom)
+	encryptedKeyBundle := keyBundleGCM.Seal(nil, keyBundleNonce, plaintextKeyBundle, nil)
+	wrappedKeyBundle := concatBytes(keyBundleSalt, keyBundleNonce, encryptedKeyBundle)
+
+	// Compute the adv secret key (which is used to authenticate the pair-success event later)
+	identitySharedKey, err := curve25519.X25519(cli.Store.IdentityKey.Priv[:], primaryIdentityPub)
+	if err != nil {
+		return fmt.Errorf("failed to compute identity shared key: %w", err)
+	}
+	advSecretInput := append(append(ephemeralSharedSecret, identitySharedKey...), advSecretRandom...)
+	advSecret := hkdfutil.SHA256(advSecretInput, nil, []byte("adv_secret"), 32)
+	cli.Store.AdvSecretKey = advSecret
+
+	_, err = cli.sendIQ(ctx, infoQuery{
+		Namespace: "md",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "link_code_companion_reg",
+			Attrs: waBinary.Attrs{
+				"jid":   linkCache.jid,
+				"stage": "companion_finish",
+			},
+			Content: []waBinary.Node{
+				{Tag: "link_code_pairing_wrapped_key_bundle", Content: wrappedKeyBundle},
+				{Tag: "companion_identity_public", Content: cli.Store.IdentityKey.Pub[:]},
+				{Tag: "link_code_pairing_ref", Content: linkCodePairingRef},
+			},
+		}},
+	})
+	return err
+}

+ 271 - 0
pair.go

@@ -0,0 +1,271 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"bytes"
+	"context"
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/base64"
+	"fmt"
+	"strings"
+
+	"go.mau.fi/libsignal/ecc"
+	"google.golang.org/protobuf/proto"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/proto/waAdv"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+	"go.mau.fi/whatsmeow/util/keys"
+)
+
+var (
+	AdvAccountSignaturePrefix = []byte{6, 0}
+	AdvDeviceSignaturePrefix  = []byte{6, 1}
+
+	AdvHostedAccountSignaturePrefix = []byte{6, 5}
+	AdvHostedDeviceSignaturePrefix  = []byte{6, 6}
+)
+
+func (cli *Client) handleIQ(ctx context.Context, node *waBinary.Node) {
+	children := node.GetChildren()
+	if len(children) != 1 || node.Attrs["from"] != types.ServerJID {
+		return
+	}
+	switch children[0].Tag {
+	case "pair-device":
+		cli.handlePairDevice(ctx, node)
+	case "pair-success":
+		cli.handlePairSuccess(ctx, node)
+	}
+}
+
+func (cli *Client) handlePairDevice(ctx context.Context, node *waBinary.Node) {
+	pairDevice := node.GetChildByTag("pair-device")
+	err := cli.sendNode(ctx, waBinary.Node{
+		Tag: "iq",
+		Attrs: waBinary.Attrs{
+			"to":   node.Attrs["from"],
+			"id":   node.Attrs["id"],
+			"type": "result",
+		},
+	})
+	if err != nil {
+		cli.Log.Warnf("Failed to send acknowledgement for pair-device request: %v", err)
+	}
+
+	evt := &events.QR{Codes: make([]string, 0, len(pairDevice.GetChildren()))}
+	for i, child := range pairDevice.GetChildren() {
+		if child.Tag != "ref" {
+			cli.Log.Warnf("pair-device node contains unexpected child tag %s at index %d", child.Tag, i)
+			continue
+		}
+		content, ok := child.Content.([]byte)
+		if !ok {
+			cli.Log.Warnf("pair-device node contains unexpected child content type %T at index %d", child, i)
+			continue
+		}
+		evt.Codes = append(evt.Codes, cli.makeQRData(string(content)))
+	}
+
+	cli.dispatchEvent(evt)
+}
+
+func (cli *Client) makeQRData(ref string) string {
+	noise := base64.StdEncoding.EncodeToString(cli.Store.NoiseKey.Pub[:])
+	identity := base64.StdEncoding.EncodeToString(cli.Store.IdentityKey.Pub[:])
+	adv := base64.StdEncoding.EncodeToString(cli.Store.AdvSecretKey)
+	return strings.Join([]string{ref, noise, identity, adv}, ",")
+}
+
+func (cli *Client) handlePairSuccess(ctx context.Context, node *waBinary.Node) {
+	id := node.Attrs["id"].(string)
+	pairSuccess := node.GetChildByTag("pair-success")
+
+	deviceIdentityBytes, _ := pairSuccess.GetChildByTag("device-identity").Content.([]byte)
+	businessName, _ := pairSuccess.GetChildByTag("biz").Attrs["name"].(string)
+	jid, _ := pairSuccess.GetChildByTag("device").Attrs["jid"].(types.JID)
+	lid, _ := pairSuccess.GetChildByTag("device").Attrs["lid"].(types.JID)
+	platform, _ := pairSuccess.GetChildByTag("platform").Attrs["name"].(string)
+
+	go func() {
+		err := cli.handlePair(ctx, deviceIdentityBytes, id, businessName, platform, jid, lid)
+		if err != nil {
+			cli.Log.Errorf("Failed to pair device: %v", err)
+			cli.Disconnect()
+			cli.dispatchEvent(&events.PairError{ID: jid, LID: lid, BusinessName: businessName, Platform: platform, Error: err})
+		} else {
+			cli.Log.Infof("Successfully paired %s", cli.Store.ID)
+			cli.dispatchEvent(&events.PairSuccess{ID: jid, LID: lid, BusinessName: businessName, Platform: platform})
+		}
+	}()
+}
+
+func (cli *Client) handlePair(ctx context.Context, deviceIdentityBytes []byte, reqID, businessName, platform string, jid, lid types.JID) error {
+	var deviceIdentityContainer waAdv.ADVSignedDeviceIdentityHMAC
+	err := proto.Unmarshal(deviceIdentityBytes, &deviceIdentityContainer)
+	if err != nil {
+		cli.sendPairError(ctx, reqID, 500, "internal-error")
+		return &PairProtoError{"failed to parse device identity container in pair success message", err}
+	}
+
+	h := hmac.New(sha256.New, cli.Store.AdvSecretKey)
+	if deviceIdentityContainer.GetAccountType() == waAdv.ADVEncryptionType_HOSTED {
+		h.Write(AdvHostedAccountSignaturePrefix)
+		//cli.Store.IsHosted = true
+	}
+	h.Write(deviceIdentityContainer.Details)
+
+	if !bytes.Equal(h.Sum(nil), deviceIdentityContainer.HMAC) {
+		cli.Log.Warnf("Invalid HMAC from pair success message")
+		cli.sendPairError(ctx, reqID, 401, "hmac-mismatch")
+		return ErrPairInvalidDeviceIdentityHMAC
+	}
+
+	var deviceIdentity waAdv.ADVSignedDeviceIdentity
+	err = proto.Unmarshal(deviceIdentityContainer.Details, &deviceIdentity)
+	if err != nil {
+		cli.sendPairError(ctx, reqID, 500, "internal-error")
+		return &PairProtoError{"failed to parse signed device identity in pair success message", err}
+	}
+
+	var deviceIdentityDetails waAdv.ADVDeviceIdentity
+	err = proto.Unmarshal(deviceIdentity.Details, &deviceIdentityDetails)
+	if err != nil {
+		cli.sendPairError(ctx, reqID, 500, "internal-error")
+		return &PairProtoError{"failed to parse device identity details in pair success message", err}
+	}
+
+	if !verifyAccountSignature(&deviceIdentity, cli.Store.IdentityKey, deviceIdentityDetails.GetDeviceType() == waAdv.ADVEncryptionType_HOSTED) {
+		cli.sendPairError(ctx, reqID, 401, "signature-mismatch")
+		return ErrPairInvalidDeviceSignature
+	}
+
+	deviceIdentity.DeviceSignature = generateDeviceSignature(&deviceIdentity, cli.Store.IdentityKey)[:]
+
+	if cli.PrePairCallback != nil && !cli.PrePairCallback(jid, platform, businessName) {
+		cli.sendPairError(ctx, reqID, 500, "internal-error")
+		return ErrPairRejectedLocally
+	}
+
+	cli.Store.Account = proto.Clone(&deviceIdentity).(*waAdv.ADVSignedDeviceIdentity)
+
+	mainDeviceLID := lid
+	mainDeviceLID.Device = 0
+	mainDeviceIdentity := *(*[32]byte)(deviceIdentity.AccountSignatureKey)
+	deviceIdentity.AccountSignatureKey = nil
+
+	selfSignedDeviceIdentity, err := proto.Marshal(&deviceIdentity)
+	if err != nil {
+		cli.sendPairError(ctx, reqID, 500, "internal-error")
+		return &PairProtoError{"failed to marshal self-signed device identity", err}
+	}
+
+	cli.Store.ID = &jid
+	cli.Store.LID = lid
+	cli.Store.BusinessName = businessName
+	cli.Store.Platform = platform
+	err = cli.Store.Save(ctx)
+	if err != nil {
+		cli.sendPairError(ctx, reqID, 500, "internal-error")
+		return &PairDatabaseError{"failed to save device store", err}
+	}
+	cli.StoreLIDPNMapping(ctx, lid, jid)
+	err = cli.Store.Identities.PutIdentity(ctx, mainDeviceLID.SignalAddress().String(), mainDeviceIdentity)
+	if err != nil {
+		_ = cli.Store.Delete(ctx)
+		cli.sendPairError(ctx, reqID, 500, "internal-error")
+		return &PairDatabaseError{"failed to store main device identity", err}
+	}
+
+	// Expect a disconnect after this and don't dispatch the usual Disconnected event
+	cli.expectDisconnect()
+
+	err = cli.sendNode(ctx, waBinary.Node{
+		Tag: "iq",
+		Attrs: waBinary.Attrs{
+			"to":   types.ServerJID,
+			"type": "result",
+			"id":   reqID,
+		},
+		Content: []waBinary.Node{{
+			Tag: "pair-device-sign",
+			Content: []waBinary.Node{{
+				Tag: "device-identity",
+				Attrs: waBinary.Attrs{
+					"key-index": deviceIdentityDetails.GetKeyIndex(),
+				},
+				Content: selfSignedDeviceIdentity,
+			}},
+		}},
+	})
+	if err != nil {
+		_ = cli.Store.Delete(ctx)
+		return fmt.Errorf("failed to send pairing confirmation: %w", err)
+	}
+	return nil
+}
+
+func concatBytes(data ...[]byte) []byte {
+	length := 0
+	for _, item := range data {
+		length += len(item)
+	}
+	output := make([]byte, length)
+	ptr := 0
+	for _, item := range data {
+		ptr += copy(output[ptr:ptr+len(item)], item)
+	}
+	return output
+}
+
+func verifyAccountSignature(deviceIdentity *waAdv.ADVSignedDeviceIdentity, ikp *keys.KeyPair, isHosted bool) bool {
+	if len(deviceIdentity.AccountSignatureKey) != 32 || len(deviceIdentity.AccountSignature) != 64 {
+		return false
+	}
+
+	signatureKey := ecc.NewDjbECPublicKey(*(*[32]byte)(deviceIdentity.AccountSignatureKey))
+	signature := *(*[64]byte)(deviceIdentity.AccountSignature)
+
+	prefix := AdvAccountSignaturePrefix
+	if isHosted {
+		prefix = AdvHostedAccountSignaturePrefix
+	}
+	message := concatBytes(prefix, deviceIdentity.Details, ikp.Pub[:])
+
+	return ecc.VerifySignature(signatureKey, message, signature)
+}
+
+func generateDeviceSignature(deviceIdentity *waAdv.ADVSignedDeviceIdentity, ikp *keys.KeyPair) *[64]byte {
+	prefix := AdvDeviceSignaturePrefix
+	message := concatBytes(prefix, deviceIdentity.Details, ikp.Pub[:], deviceIdentity.AccountSignatureKey)
+	sig := ecc.CalculateSignature(ecc.NewDjbECPrivateKey(*ikp.Priv), message)
+	return &sig
+}
+
+func (cli *Client) sendPairError(ctx context.Context, id string, code int, text string) {
+	err := cli.sendNode(ctx, waBinary.Node{
+		Tag: "iq",
+		Attrs: waBinary.Attrs{
+			"to":   types.ServerJID,
+			"type": "error",
+			"id":   id,
+		},
+		Content: []waBinary.Node{{
+			Tag: "error",
+			Attrs: waBinary.Attrs{
+				"code": code,
+				"text": text,
+			},
+		}},
+	})
+	if err != nil {
+		cli.Log.Errorf("Failed to send pair error node: %v", err)
+	}
+}

+ 277 - 0
prekeys.go

@@ -0,0 +1,277 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"encoding/binary"
+	"fmt"
+	"time"
+
+	"go.mau.fi/libsignal/ecc"
+	"go.mau.fi/libsignal/keys/identity"
+	"go.mau.fi/libsignal/keys/prekey"
+	"go.mau.fi/libsignal/util/optional"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/util/keys"
+)
+
+const (
+	// WantedPreKeyCount is the number of prekeys that the client should upload to the WhatsApp servers in a single batch.
+	WantedPreKeyCount = 50
+	// MinPreKeyCount is the number of prekeys when the client will upload a new batch of prekeys to the WhatsApp servers.
+	MinPreKeyCount = 5
+)
+
+func (cli *Client) getServerPreKeyCount(ctx context.Context) (int, error) {
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "encrypt",
+		Type:      "get",
+		To:        types.ServerJID,
+		Content: []waBinary.Node{
+			{Tag: "count"},
+		},
+	})
+	if err != nil {
+		return 0, fmt.Errorf("failed to get prekey count on server: %w", err)
+	}
+	count := resp.GetChildByTag("count")
+	ag := count.AttrGetter()
+	val := ag.Int("value")
+	return val, ag.Error()
+}
+
+func (cli *Client) uploadPreKeys(ctx context.Context, initialUpload bool) {
+	cli.uploadPreKeysLock.Lock()
+	defer cli.uploadPreKeysLock.Unlock()
+	if cli.lastPreKeyUpload.Add(10 * time.Minute).After(time.Now()) {
+		sc, _ := cli.getServerPreKeyCount(ctx)
+		if sc >= WantedPreKeyCount {
+			cli.Log.Debugf("Canceling prekey upload request due to likely race condition")
+			return
+		}
+	}
+	var registrationIDBytes [4]byte
+	binary.BigEndian.PutUint32(registrationIDBytes[:], cli.Store.RegistrationID)
+	wantedCount := WantedPreKeyCount
+	if initialUpload {
+		wantedCount = 812
+	}
+	preKeys, err := cli.Store.PreKeys.GetOrGenPreKeys(ctx, uint32(wantedCount))
+	if err != nil {
+		cli.Log.Errorf("Failed to get prekeys to upload: %v", err)
+		return
+	}
+	cli.Log.Infof("Uploading %d new prekeys to server", len(preKeys))
+	_, err = cli.sendIQ(ctx, infoQuery{
+		Namespace: "encrypt",
+		Type:      "set",
+		To:        types.ServerJID,
+		Content: []waBinary.Node{
+			{Tag: "registration", Content: registrationIDBytes[:]},
+			{Tag: "type", Content: []byte{ecc.DjbType}},
+			{Tag: "identity", Content: cli.Store.IdentityKey.Pub[:]},
+			{Tag: "list", Content: preKeysToNodes(preKeys)},
+			preKeyToNode(cli.Store.SignedPreKey),
+		},
+	})
+	if err != nil {
+		cli.Log.Errorf("Failed to send request to upload prekeys: %v", err)
+		return
+	}
+	cli.Log.Debugf("Got response to uploading prekeys")
+	err = cli.Store.PreKeys.MarkPreKeysAsUploaded(ctx, preKeys[len(preKeys)-1].KeyID)
+	if err != nil {
+		cli.Log.Warnf("Failed to mark prekeys as uploaded: %v", err)
+		return
+	}
+	cli.lastPreKeyUpload = time.Now()
+	return
+}
+
+func (cli *Client) fetchPreKeysNoError(ctx context.Context, retryDevices []types.JID) map[types.JID]*prekey.Bundle {
+	if len(retryDevices) == 0 {
+		return nil
+	}
+	bundlesResp, err := cli.fetchPreKeys(ctx, retryDevices)
+	if err != nil {
+		cli.Log.Warnf("Failed to fetch prekeys for %v with no existing session: %v", retryDevices, err)
+		return nil
+	}
+	bundles := make(map[types.JID]*prekey.Bundle, len(retryDevices))
+	for _, jid := range retryDevices {
+		resp := bundlesResp[jid]
+		if resp.err != nil {
+			cli.Log.Warnf("Failed to fetch prekey for %s: %v", jid, resp.err)
+			continue
+		}
+		bundles[jid] = resp.bundle
+	}
+	return bundles
+}
+
+type preKeyResp struct {
+	bundle *prekey.Bundle
+	err    error
+}
+
+func (cli *Client) fetchPreKeys(ctx context.Context, users []types.JID) (map[types.JID]preKeyResp, error) {
+	requests := make([]waBinary.Node, len(users))
+	for i, user := range users {
+		requests[i].Tag = "user"
+		requests[i].Attrs = waBinary.Attrs{
+			"jid":    user,
+			"reason": "identity",
+		}
+	}
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "encrypt",
+		Type:      "get",
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag:     "key",
+			Content: requests,
+		}},
+	})
+	if err != nil {
+		return nil, fmt.Errorf("failed to send prekey request: %w", err)
+	} else if len(resp.GetChildren()) == 0 {
+		return nil, fmt.Errorf("got empty response to prekey request")
+	}
+	list := resp.GetChildByTag("list")
+	respData := make(map[types.JID]preKeyResp)
+	for _, child := range list.GetChildren() {
+		if child.Tag != "user" {
+			continue
+		}
+		jid := child.AttrGetter().JID("jid")
+		bundle, err := nodeToPreKeyBundle(uint32(jid.Device), child)
+		respData[jid] = preKeyResp{bundle, err}
+	}
+	return respData, nil
+}
+
+func preKeyToNode(key *keys.PreKey) waBinary.Node {
+	var keyID [4]byte
+	binary.BigEndian.PutUint32(keyID[:], key.KeyID)
+	node := waBinary.Node{
+		Tag: "key",
+		Content: []waBinary.Node{
+			{Tag: "id", Content: keyID[1:]},
+			{Tag: "value", Content: key.Pub[:]},
+		},
+	}
+	if key.Signature != nil {
+		node.Tag = "skey"
+		node.Content = append(node.GetChildren(), waBinary.Node{
+			Tag:     "signature",
+			Content: key.Signature[:],
+		})
+	}
+	return node
+}
+
+func nodeToPreKeyBundle(deviceID uint32, node waBinary.Node) (*prekey.Bundle, error) {
+	errorNode, ok := node.GetOptionalChildByTag("error")
+	if ok && errorNode.Tag == "error" {
+		return nil, fmt.Errorf("got error getting prekeys: %s", errorNode.XMLString())
+	}
+
+	registrationBytes, ok := node.GetChildByTag("registration").Content.([]byte)
+	if !ok || len(registrationBytes) != 4 {
+		return nil, fmt.Errorf("invalid registration ID in prekey response")
+	}
+	registrationID := binary.BigEndian.Uint32(registrationBytes)
+
+	keysNode, ok := node.GetOptionalChildByTag("keys")
+	if !ok {
+		keysNode = node
+	}
+
+	identityKeyRaw, ok := keysNode.GetChildByTag("identity").Content.([]byte)
+	if !ok || len(identityKeyRaw) != 32 {
+		return nil, fmt.Errorf("invalid identity key in prekey response")
+	}
+	identityKeyPub := *(*[32]byte)(identityKeyRaw)
+
+	preKeyNode, ok := keysNode.GetOptionalChildByTag("key")
+	preKey := &keys.PreKey{}
+	if ok {
+		var err error
+		preKey, err = nodeToPreKey(preKeyNode)
+		if err != nil {
+			return nil, fmt.Errorf("invalid prekey in prekey response: %w", err)
+		}
+	}
+
+	signedPreKey, err := nodeToPreKey(keysNode.GetChildByTag("skey"))
+	if err != nil {
+		return nil, fmt.Errorf("invalid signed prekey in prekey response: %w", err)
+	}
+
+	var bundle *prekey.Bundle
+	if ok {
+		bundle = prekey.NewBundle(registrationID, deviceID,
+			optional.NewOptionalUint32(preKey.KeyID), signedPreKey.KeyID,
+			ecc.NewDjbECPublicKey(*preKey.Pub), ecc.NewDjbECPublicKey(*signedPreKey.Pub), *signedPreKey.Signature,
+			identity.NewKey(ecc.NewDjbECPublicKey(identityKeyPub)))
+	} else {
+		bundle = prekey.NewBundle(registrationID, deviceID, optional.NewEmptyUint32(), signedPreKey.KeyID,
+			nil, ecc.NewDjbECPublicKey(*signedPreKey.Pub), *signedPreKey.Signature,
+			identity.NewKey(ecc.NewDjbECPublicKey(identityKeyPub)))
+	}
+
+	return bundle, nil
+}
+
+func nodeToPreKey(node waBinary.Node) (*keys.PreKey, error) {
+	key := keys.PreKey{
+		KeyPair:   keys.KeyPair{},
+		KeyID:     0,
+		Signature: nil,
+	}
+	if id := node.GetChildByTag("id"); id.Tag != "id" {
+		return nil, fmt.Errorf("prekey node doesn't contain ID tag")
+	} else if idBytes, ok := id.Content.([]byte); !ok {
+		return nil, fmt.Errorf("prekey ID has unexpected content (%T)", id.Content)
+	} else if len(idBytes) != 3 {
+		return nil, fmt.Errorf("prekey ID has unexpected number of bytes (%d, expected 3)", len(idBytes))
+	} else {
+		key.KeyID = binary.BigEndian.Uint32(append([]byte{0}, idBytes...))
+	}
+	if pubkey := node.GetChildByTag("value"); pubkey.Tag != "value" {
+		return nil, fmt.Errorf("prekey node doesn't contain value tag")
+	} else if pubkeyBytes, ok := pubkey.Content.([]byte); !ok {
+		return nil, fmt.Errorf("prekey value has unexpected content (%T)", pubkey.Content)
+	} else if len(pubkeyBytes) != 32 {
+		return nil, fmt.Errorf("prekey value has unexpected number of bytes (%d, expected 32)", len(pubkeyBytes))
+	} else {
+		key.KeyPair.Pub = (*[32]byte)(pubkeyBytes)
+	}
+	if node.Tag == "skey" {
+		if sig := node.GetChildByTag("signature"); sig.Tag != "signature" {
+			return nil, fmt.Errorf("prekey node doesn't contain signature tag")
+		} else if sigBytes, ok := sig.Content.([]byte); !ok {
+			return nil, fmt.Errorf("prekey signature has unexpected content (%T)", sig.Content)
+		} else if len(sigBytes) != 64 {
+			return nil, fmt.Errorf("prekey signature has unexpected number of bytes (%d, expected 64)", len(sigBytes))
+		} else {
+			key.Signature = (*[64]byte)(sigBytes)
+		}
+	}
+	return &key, nil
+}
+
+func preKeysToNodes(prekeys []*keys.PreKey) []waBinary.Node {
+	nodes := make([]waBinary.Node, len(prekeys))
+	for i, key := range prekeys {
+		nodes[i] = preKeyToNode(key)
+	}
+	return nodes
+}

+ 148 - 0
presence.go

@@ -0,0 +1,148 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"fmt"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+func (cli *Client) handleChatState(ctx context.Context, node *waBinary.Node) {
+	source, err := cli.parseMessageSource(node, true)
+	if err != nil {
+		cli.Log.Warnf("Failed to parse chat state update: %v", err)
+	} else if len(node.GetChildren()) != 1 {
+		cli.Log.Warnf("Failed to parse chat state update: unexpected number of children in element (%d)", len(node.GetChildren()))
+	} else {
+		child := node.GetChildren()[0]
+		presence := types.ChatPresence(child.Tag)
+		if presence != types.ChatPresenceComposing && presence != types.ChatPresencePaused {
+			cli.Log.Warnf("Unrecognized chat presence state %s", child.Tag)
+		}
+		media := types.ChatPresenceMedia(child.AttrGetter().OptionalString("media"))
+		cli.dispatchEvent(&events.ChatPresence{
+			MessageSource: source,
+			State:         presence,
+			Media:         media,
+		})
+	}
+}
+
+func (cli *Client) handlePresence(ctx context.Context, node *waBinary.Node) {
+	var evt events.Presence
+	ag := node.AttrGetter()
+	evt.From = ag.JID("from")
+	presenceType := ag.OptionalString("type")
+	if presenceType == "unavailable" {
+		evt.Unavailable = true
+	} else if presenceType != "" {
+		cli.Log.Debugf("Unrecognized presence type '%s' in presence event from %s", presenceType, evt.From)
+	}
+	lastSeen := ag.OptionalString("last")
+	if lastSeen != "" && lastSeen != "deny" {
+		evt.LastSeen = ag.UnixTime("last")
+	}
+	if !ag.OK() {
+		cli.Log.Warnf("Error parsing presence event: %+v", ag.Errors)
+	} else {
+		cli.dispatchEvent(&evt)
+	}
+}
+
+// SendPresence updates the user's presence status on WhatsApp.
+//
+// You should call this at least once after connecting so that the server has your pushname.
+// Otherwise, other users will see "-" as the name.
+func (cli *Client) SendPresence(ctx context.Context, state types.Presence) error {
+	if cli == nil {
+		return ErrClientIsNil
+	} else if len(cli.Store.PushName) == 0 && cli.MessengerConfig == nil {
+		return ErrNoPushName
+	}
+	if state == types.PresenceAvailable {
+		cli.sendActiveReceipts.CompareAndSwap(0, 1)
+	} else {
+		cli.sendActiveReceipts.CompareAndSwap(1, 0)
+	}
+	attrs := waBinary.Attrs{
+		"type": string(state),
+	}
+	// PushName not set when using WhatsApp for Messenger E2EE
+	if cli.MessengerConfig == nil {
+		attrs["name"] = cli.Store.PushName
+	}
+	return cli.sendNode(ctx, waBinary.Node{
+		Tag:   "presence",
+		Attrs: attrs,
+	})
+}
+
+// SubscribePresence asks the WhatsApp servers to send presence updates of a specific user to this client.
+//
+// After subscribing to this event, you should start receiving *events.Presence for that user in normal event handlers.
+//
+// Also, it seems that the WhatsApp servers require you to be online to receive presence status from other users,
+// so you should mark yourself as online before trying to use this function:
+//
+//	cli.SendPresence(types.PresenceAvailable)
+func (cli *Client) SubscribePresence(ctx context.Context, jid types.JID) error {
+	if cli == nil {
+		return ErrClientIsNil
+	}
+	privacyToken, err := cli.Store.PrivacyTokens.GetPrivacyToken(ctx, jid)
+	if err != nil {
+		return fmt.Errorf("failed to get privacy token: %w", err)
+	} else if privacyToken == nil {
+		if cli.ErrorOnSubscribePresenceWithoutToken {
+			return fmt.Errorf("%w for %v", ErrNoPrivacyToken, jid.ToNonAD())
+		} else {
+			cli.Log.Debugf("Trying to subscribe to presence of %s without privacy token", jid)
+		}
+	}
+	req := waBinary.Node{
+		Tag: "presence",
+		Attrs: waBinary.Attrs{
+			"type": "subscribe",
+			"to":   jid,
+		},
+	}
+	if privacyToken != nil {
+		req.Content = []waBinary.Node{{
+			Tag:     "tctoken",
+			Content: privacyToken.Token,
+		}}
+	}
+	return cli.sendNode(ctx, req)
+}
+
+// SendChatPresence updates the user's typing status in a specific chat.
+//
+// The media parameter can be set to indicate the user is recording media (like a voice message) rather than typing a text message.
+func (cli *Client) SendChatPresence(ctx context.Context, jid types.JID, state types.ChatPresence, media types.ChatPresenceMedia) error {
+	ownID := cli.getOwnID()
+	if ownID.IsEmpty() {
+		return ErrNotLoggedIn
+	}
+	content := []waBinary.Node{{Tag: string(state)}}
+	if state == types.ChatPresenceComposing && len(media) > 0 {
+		content[0].Attrs = waBinary.Attrs{
+			"media": string(media),
+		}
+	}
+	return cli.sendNode(ctx, waBinary.Node{
+		Tag: "chatstate",
+		Attrs: waBinary.Attrs{
+			"from": ownID,
+			"to":   jid,
+		},
+		Content: content,
+	})
+}

+ 169 - 0
privacysettings.go

@@ -0,0 +1,169 @@
+// Copyright (c) 2021 Tulir Asokan
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package whatsmeow
+
+import (
+	"context"
+	"strconv"
+	"time"
+
+	waBinary "go.mau.fi/whatsmeow/binary"
+	"go.mau.fi/whatsmeow/types"
+	"go.mau.fi/whatsmeow/types/events"
+)
+
+// TryFetchPrivacySettings will fetch the user's privacy settings, either from the in-memory cache or from the server.
+func (cli *Client) TryFetchPrivacySettings(ctx context.Context, ignoreCache bool) (*types.PrivacySettings, error) {
+	if cli == nil {
+		return nil, ErrClientIsNil
+	} else if val := cli.privacySettingsCache.Load(); val != nil && !ignoreCache {
+		return val.(*types.PrivacySettings), nil
+	}
+	resp, err := cli.sendIQ(ctx, infoQuery{
+		Namespace: "privacy",
+		Type:      iqGet,
+		To:        types.ServerJID,
+		Content:   []waBinary.Node{{Tag: "privacy"}},
+	})
+	if err != nil {
+		return nil, err
+	}
+	privacyNode, ok := resp.GetOptionalChildByTag("privacy")
+	if !ok {
+		return nil, &ElementMissingError{Tag: "privacy", In: "response to privacy settings query"}
+	}
+	var settings types.PrivacySettings
+	cli.parsePrivacySettings(&privacyNode, &settings)
+	cli.privacySettingsCache.Store(&settings)
+	return &settings, nil
+}
+
+// GetPrivacySettings will get the user's privacy settings. If an error occurs while fetching them, the error will be
+// logged, but the method will just return an empty struct.
+func (cli *Client) GetPrivacySettings(ctx context.Context) (settings types.PrivacySettings) {
+	if cli == nil || cli.MessengerConfig != nil {
+		return
+	}
+	settingsPtr, err := cli.TryFetchPrivacySettings(ctx, false)
+	if err != nil {
+		cli.Log.Errorf("Failed to fetch privacy settings: %v", err)
+	} else {
+		settings = *settingsPtr
+	}
+	return
+}
+
+// SetPrivacySetting will set the given privacy setting to the given value.
+// The privacy settings will be fetched from the server after the change and the new settings will be returned.
+// If an error occurs while fetching the new settings, will return an empty struct.
+func (cli *Client) SetPrivacySetting(ctx context.Context, name types.PrivacySettingType, value types.PrivacySetting) (settings types.PrivacySettings, err error) {
+	settingsPtr, err := cli.TryFetchPrivacySettings(ctx, false)
+	if err != nil {
+		return settings, err
+	}
+	_, err = cli.sendIQ(ctx, infoQuery{
+		Namespace: "privacy",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "privacy",
+			Content: []waBinary.Node{{
+				Tag: "category",
+				Attrs: waBinary.Attrs{
+					"name":  string(name),
+					"value": string(value),
+				},
+			}},
+		}},
+	})
+	if err != nil {
+		return settings, err
+	}
+	settings = *settingsPtr
+	switch name {
+	case types.PrivacySettingTypeGroupAdd:
+		settings.GroupAdd = value
+	case types.PrivacySettingTypeLastSeen:
+		settings.LastSeen = value
+	case types.PrivacySettingTypeStatus:
+		settings.Status = value
+	case types.PrivacySettingTypeProfile:
+		settings.Profile = value
+	case types.PrivacySettingTypeReadReceipts:
+		settings.ReadReceipts = value
+	case types.PrivacySettingTypeOnline:
+		settings.Online = value
+	case types.PrivacySettingTypeCallAdd:
+		settings.CallAdd = value
+	}
+	cli.privacySettingsCache.Store(&settings)
+	return
+}
+
+// SetDefaultDisappearingTimer will set the default disappearing message timer.
+func (cli *Client) SetDefaultDisappearingTimer(ctx context.Context, timer time.Duration) (err error) {
+	_, err = cli.sendIQ(ctx, infoQuery{
+		Namespace: "disappearing_mode",
+		Type:      iqSet,
+		To:        types.ServerJID,
+		Content: []waBinary.Node{{
+			Tag: "disappearing_mode",
+			Attrs: waBinary.Attrs{
+				"duration": strconv.Itoa(int(timer.Seconds())),
+			},
+		}},
+	})
+	return
+}
+
+func (cli *Client) parsePrivacySettings(privacyNode *waBinary.Node, settings *types.PrivacySettings) *events.PrivacySettings {
+	var evt events.PrivacySettings
+	for _, child := range privacyNode.GetChildren() {
+		if child.Tag != "category" {
+			continue
+		}
+		ag := child.AttrGetter()
+		name := types.PrivacySettingType(ag.String("name"))
+		value := types.PrivacySetting(ag.String("value"))
+		switch name {
+		case types.PrivacySettingTypeGroupAdd:
+			settings.GroupAdd = value
+			evt.GroupAddChanged = true
+		case types.PrivacySettingTypeLastSeen:
+			settings.LastSeen = value
+			evt.LastSeenChanged = true
+		case types.PrivacySettingTypeStatus:
+			settings.Status = value
+			evt.StatusChanged = true
+		case types.PrivacySettingTypeProfile:
+			settings.Profile = value
+			evt.ProfileChanged = true
+		case types.PrivacySettingTypeReadReceipts:
+			settings.ReadReceipts = value
+			evt.ReadReceiptsChanged = true
+		case types.PrivacySettingTypeOnline:
+			settings.Online = value
+			evt.OnlineChanged = true
+		case types.PrivacySettingTypeCallAdd:
+			settings.CallAdd = value
+			evt.CallAddChanged = true
+		}
+	}
+	return &evt
+}
+
+func (cli *Client) handlePrivacySettingsNotification(ctx context.Context, privacyNode *waBinary.Node) {
+	cli.Log.Debugf("Parsing privacy settings change notification")
+	settings, err := cli.TryFetchPrivacySettings(ctx, false)
+	if err != nil {
+		cli.Log.Errorf("Failed to fetch privacy settings when handling change: %v", err)
+		return
+	}
+	evt := cli.parsePrivacySettings(privacyNode, settings)
+	cli.privacySettingsCache.Store(settings)
+	cli.dispatchEvent(evt)
+}

+ 1 - 0
proto/.gitignore

@@ -0,0 +1 @@
+protos.js

+ 32 - 0
proto/armadilloutil/decode.go

@@ -0,0 +1,32 @@
+package armadilloutil
+
+import (
+	"errors"
+	"fmt"
+
+	"google.golang.org/protobuf/proto"
+
+	"go.mau.fi/whatsmeow/proto/waCommon"
+)
+
+var ErrUnsupportedVersion = errors.New("unsupported subprotocol version")
+
+func Unmarshal[T proto.Message](into T, msg *waCommon.SubProtocol, expectedVersion int32) (T, error) {
+	if msg.GetVersion() != expectedVersion {
+		return into, fmt.Errorf("%w %d in %T (expected %d)", ErrUnsupportedVersion, msg.GetVersion(), into, expectedVersion)
+	}
+
+	err := proto.Unmarshal(msg.GetPayload(), into)
+	return into, err
+}
+
+func Marshal[T proto.Message](msg T, version int32) (*waCommon.SubProtocol, error) {
+	payload, err := proto.Marshal(msg)
+	if err != nil {
+		return nil, err
+	}
+	return &waCommon.SubProtocol{
+		Payload: payload,
+		Version: &version,
+	}, nil
+}

+ 43 - 0
proto/extra.go

@@ -0,0 +1,43 @@
+package armadillo
+
+import (
+	"google.golang.org/protobuf/proto"
+
+	"go.mau.fi/whatsmeow/proto/instamadilloAddMessage"
+	"go.mau.fi/whatsmeow/proto/instamadilloDeleteMessage"
+	"go.mau.fi/whatsmeow/proto/instamadilloSupplementMessage"
+	"go.mau.fi/whatsmeow/proto/waArmadilloApplication"
+	"go.mau.fi/whatsmeow/proto/waCommon"
+	"go.mau.fi/whatsmeow/proto/waConsumerApplication"
+	"go.mau.fi/whatsmeow/proto/waMultiDevice"
+)
+
+type MessageApplicationSub interface {
+	IsMessageApplicationSub()
+}
+
+type RealMessageApplicationSub interface {
+	MessageApplicationSub
+	proto.Message
+}
+
+type Unsupported_BusinessApplication waCommon.SubProtocol
+type Unsupported_PaymentApplication waCommon.SubProtocol
+type Unsupported_Voip waCommon.SubProtocol
+
+var (
+	_ MessageApplicationSub = (*waConsumerApplication.ConsumerApplication)(nil) // 2
+	_ MessageApplicationSub = (*Unsupported_BusinessApplication)(nil)           // 3
+	_ MessageApplicationSub = (*Unsupported_PaymentApplication)(nil)            // 4
+	_ MessageApplicationSub = (*waMultiDevice.MultiDevice)(nil)                 // 5
+	_ MessageApplicationSub = (*Unsupported_Voip)(nil)                          // 6
+	_ MessageApplicationSub = (*waArmadilloApplication.Armadillo)(nil)          // 7
+
+	_ MessageApplicationSub = (*instamadilloAddMessage.AddMessagePayload)(nil)
+	_ MessageApplicationSub = (*instamadilloSupplementMessage.SupplementMessagePayload)(nil)
+	_ MessageApplicationSub = (*instamadilloDeleteMessage.DeleteMessagePayload)(nil)
+)
+
+func (*Unsupported_BusinessApplication) IsMessageApplicationSub() {}
+func (*Unsupported_PaymentApplication) IsMessageApplicationSub()  {}
+func (*Unsupported_Voip) IsMessageApplicationSub()                {}

+ 983 - 0
proto/instamadilloAddMessage/InstamadilloAddMessage.pb.go

@@ -0,0 +1,983 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloAddMessage/InstamadilloAddMessage.proto
+
+package instamadilloAddMessage
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	instamadilloCoreTypeActionLog "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeActionLog"
+	instamadilloCoreTypeAdminMessage "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeAdminMessage"
+	instamadilloCoreTypeCollection "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeCollection"
+	instamadilloCoreTypeLink "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeLink"
+	instamadilloCoreTypeMedia "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia"
+	instamadilloCoreTypeText "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeText"
+	instamadilloXmaContentRef "go.mau.fi/whatsmeow/proto/instamadilloXmaContentRef"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Placeholder_Type int32
+
+const (
+	Placeholder_PLACEHOLDER_TYPE_NONE                          Placeholder_Type = 0
+	Placeholder_PLACEHOLDER_TYPE_DECRYPTION_FAILURE            Placeholder_Type = 1
+	Placeholder_PLACEHOLDER_TYPE_NOT_SUPPORTED_NEED_UPDATE     Placeholder_Type = 2
+	Placeholder_PLACEHOLDER_TYPE_DEVICE_UNAVAILABLE            Placeholder_Type = 3
+	Placeholder_PLACEHOLDER_TYPE_NOT_SUPPORTED_NOT_RECOVERABLE Placeholder_Type = 4
+)
+
+// Enum value maps for Placeholder_Type.
+var (
+	Placeholder_Type_name = map[int32]string{
+		0: "PLACEHOLDER_TYPE_NONE",
+		1: "PLACEHOLDER_TYPE_DECRYPTION_FAILURE",
+		2: "PLACEHOLDER_TYPE_NOT_SUPPORTED_NEED_UPDATE",
+		3: "PLACEHOLDER_TYPE_DEVICE_UNAVAILABLE",
+		4: "PLACEHOLDER_TYPE_NOT_SUPPORTED_NOT_RECOVERABLE",
+	}
+	Placeholder_Type_value = map[string]int32{
+		"PLACEHOLDER_TYPE_NONE":                          0,
+		"PLACEHOLDER_TYPE_DECRYPTION_FAILURE":            1,
+		"PLACEHOLDER_TYPE_NOT_SUPPORTED_NEED_UPDATE":     2,
+		"PLACEHOLDER_TYPE_DEVICE_UNAVAILABLE":            3,
+		"PLACEHOLDER_TYPE_NOT_SUPPORTED_NOT_RECOVERABLE": 4,
+	}
+)
+
+func (x Placeholder_Type) Enum() *Placeholder_Type {
+	p := new(Placeholder_Type)
+	*p = x
+	return p
+}
+
+func (x Placeholder_Type) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Placeholder_Type) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_enumTypes[0].Descriptor()
+}
+
+func (Placeholder_Type) Type() protoreflect.EnumType {
+	return &file_instamadilloAddMessage_InstamadilloAddMessage_proto_enumTypes[0]
+}
+
+func (x Placeholder_Type) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Placeholder_Type) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Placeholder_Type(num)
+	return nil
+}
+
+// Deprecated: Use Placeholder_Type.Descriptor instead.
+func (Placeholder_Type) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{10, 0}
+}
+
+type AddMessagePayload struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Content       *AddMessageContent     `protobuf:"bytes,1,opt,name=content" json:"content,omitempty"`
+	Metadata      *AddMessageMetadata    `protobuf:"bytes,2,opt,name=metadata" json:"metadata,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AddMessagePayload) Reset() {
+	*x = AddMessagePayload{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AddMessagePayload) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddMessagePayload) ProtoMessage() {}
+
+func (x *AddMessagePayload) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AddMessagePayload.ProtoReflect.Descriptor instead.
+func (*AddMessagePayload) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *AddMessagePayload) GetContent() *AddMessageContent {
+	if x != nil {
+		return x.Content
+	}
+	return nil
+}
+
+func (x *AddMessagePayload) GetMetadata() *AddMessageMetadata {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+type AddMessageContent struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to AddMessageContent:
+	//
+	//	*AddMessageContent_Text
+	//	*AddMessageContent_Like
+	//	*AddMessageContent_Link
+	//	*AddMessageContent_ReceiverFetchXma
+	//	*AddMessageContent_Media
+	//	*AddMessageContent_Placeholder
+	//	*AddMessageContent_Collection
+	//	*AddMessageContent_AdminMessage
+	//	*AddMessageContent_ActionLog
+	AddMessageContent isAddMessageContent_AddMessageContent `protobuf_oneof:"addMessageContent"`
+	unknownFields     protoimpl.UnknownFields
+	sizeCache         protoimpl.SizeCache
+}
+
+func (x *AddMessageContent) Reset() {
+	*x = AddMessageContent{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AddMessageContent) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddMessageContent) ProtoMessage() {}
+
+func (x *AddMessageContent) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AddMessageContent.ProtoReflect.Descriptor instead.
+func (*AddMessageContent) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *AddMessageContent) GetAddMessageContent() isAddMessageContent_AddMessageContent {
+	if x != nil {
+		return x.AddMessageContent
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetText() *instamadilloCoreTypeText.Text {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_Text); ok {
+			return x.Text
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetLike() *Like {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_Like); ok {
+			return x.Like
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetLink() *instamadilloCoreTypeLink.Link {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_Link); ok {
+			return x.Link
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetReceiverFetchXma() *ReceiverFetchXma {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_ReceiverFetchXma); ok {
+			return x.ReceiverFetchXma
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetMedia() *instamadilloCoreTypeMedia.Media {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_Media); ok {
+			return x.Media
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetPlaceholder() *Placeholder {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_Placeholder); ok {
+			return x.Placeholder
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetCollection() *instamadilloCoreTypeCollection.Collection {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_Collection); ok {
+			return x.Collection
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetAdminMessage() *instamadilloCoreTypeAdminMessage.AdminMessage {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_AdminMessage); ok {
+			return x.AdminMessage
+		}
+	}
+	return nil
+}
+
+func (x *AddMessageContent) GetActionLog() *instamadilloCoreTypeActionLog.ActionLog {
+	if x != nil {
+		if x, ok := x.AddMessageContent.(*AddMessageContent_ActionLog); ok {
+			return x.ActionLog
+		}
+	}
+	return nil
+}
+
+type isAddMessageContent_AddMessageContent interface {
+	isAddMessageContent_AddMessageContent()
+}
+
+type AddMessageContent_Text struct {
+	Text *instamadilloCoreTypeText.Text `protobuf:"bytes,1,opt,name=text,oneof"`
+}
+
+type AddMessageContent_Like struct {
+	Like *Like `protobuf:"bytes,2,opt,name=like,oneof"`
+}
+
+type AddMessageContent_Link struct {
+	Link *instamadilloCoreTypeLink.Link `protobuf:"bytes,3,opt,name=link,oneof"`
+}
+
+type AddMessageContent_ReceiverFetchXma struct {
+	ReceiverFetchXma *ReceiverFetchXma `protobuf:"bytes,4,opt,name=receiverFetchXma,oneof"`
+}
+
+type AddMessageContent_Media struct {
+	Media *instamadilloCoreTypeMedia.Media `protobuf:"bytes,5,opt,name=media,oneof"`
+}
+
+type AddMessageContent_Placeholder struct {
+	Placeholder *Placeholder `protobuf:"bytes,6,opt,name=placeholder,oneof"`
+}
+
+type AddMessageContent_Collection struct {
+	Collection *instamadilloCoreTypeCollection.Collection `protobuf:"bytes,7,opt,name=collection,oneof"`
+}
+
+type AddMessageContent_AdminMessage struct {
+	AdminMessage *instamadilloCoreTypeAdminMessage.AdminMessage `protobuf:"bytes,8,opt,name=adminMessage,oneof"`
+}
+
+type AddMessageContent_ActionLog struct {
+	ActionLog *instamadilloCoreTypeActionLog.ActionLog `protobuf:"bytes,9,opt,name=actionLog,oneof"`
+}
+
+func (*AddMessageContent_Text) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_Like) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_Link) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_ReceiverFetchXma) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_Media) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_Placeholder) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_Collection) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_AdminMessage) isAddMessageContent_AddMessageContent() {}
+
+func (*AddMessageContent_ActionLog) isAddMessageContent_AddMessageContent() {}
+
+type AddMessageMetadata struct {
+	state              protoimpl.MessageState `protogen:"open.v1"`
+	SendSilently       *bool                  `protobuf:"varint,1,opt,name=sendSilently" json:"sendSilently,omitempty"`
+	PrivateReplyInfo   *PrivateReplyInfo      `protobuf:"bytes,2,opt,name=privateReplyInfo" json:"privateReplyInfo,omitempty"`
+	RepliedToMessage   *RepliedToMessage      `protobuf:"bytes,3,opt,name=repliedToMessage" json:"repliedToMessage,omitempty"`
+	ForwardingParams   *ForwardingParams      `protobuf:"bytes,4,opt,name=forwardingParams" json:"forwardingParams,omitempty"`
+	EphemeralityParams *EphemeralityParams    `protobuf:"bytes,5,opt,name=ephemeralityParams" json:"ephemeralityParams,omitempty"`
+	unknownFields      protoimpl.UnknownFields
+	sizeCache          protoimpl.SizeCache
+}
+
+func (x *AddMessageMetadata) Reset() {
+	*x = AddMessageMetadata{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AddMessageMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AddMessageMetadata) ProtoMessage() {}
+
+func (x *AddMessageMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AddMessageMetadata.ProtoReflect.Descriptor instead.
+func (*AddMessageMetadata) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *AddMessageMetadata) GetSendSilently() bool {
+	if x != nil && x.SendSilently != nil {
+		return *x.SendSilently
+	}
+	return false
+}
+
+func (x *AddMessageMetadata) GetPrivateReplyInfo() *PrivateReplyInfo {
+	if x != nil {
+		return x.PrivateReplyInfo
+	}
+	return nil
+}
+
+func (x *AddMessageMetadata) GetRepliedToMessage() *RepliedToMessage {
+	if x != nil {
+		return x.RepliedToMessage
+	}
+	return nil
+}
+
+func (x *AddMessageMetadata) GetForwardingParams() *ForwardingParams {
+	if x != nil {
+		return x.ForwardingParams
+	}
+	return nil
+}
+
+func (x *AddMessageMetadata) GetEphemeralityParams() *EphemeralityParams {
+	if x != nil {
+		return x.EphemeralityParams
+	}
+	return nil
+}
+
+type RepliedToMessage struct {
+	state                            protoimpl.MessageState           `protogen:"open.v1"`
+	RepliedToMessageOtid             *string                          `protobuf:"bytes,1,opt,name=repliedToMessageOtid" json:"repliedToMessageOtid,omitempty"`
+	RepliedToMessageWaServerTimeSec  *string                          `protobuf:"bytes,2,opt,name=repliedToMessageWaServerTimeSec" json:"repliedToMessageWaServerTimeSec,omitempty"`
+	RepliedToMessageCollectionItemID *string                          `protobuf:"bytes,3,opt,name=repliedToMessageCollectionItemID" json:"repliedToMessageCollectionItemID,omitempty"`
+	OmMicroSecTS                     *OpenMessageMicroSecondTimestamp `protobuf:"bytes,4,opt,name=omMicroSecTS" json:"omMicroSecTS,omitempty"`
+	unknownFields                    protoimpl.UnknownFields
+	sizeCache                        protoimpl.SizeCache
+}
+
+func (x *RepliedToMessage) Reset() {
+	*x = RepliedToMessage{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *RepliedToMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RepliedToMessage) ProtoMessage() {}
+
+func (x *RepliedToMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RepliedToMessage.ProtoReflect.Descriptor instead.
+func (*RepliedToMessage) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *RepliedToMessage) GetRepliedToMessageOtid() string {
+	if x != nil && x.RepliedToMessageOtid != nil {
+		return *x.RepliedToMessageOtid
+	}
+	return ""
+}
+
+func (x *RepliedToMessage) GetRepliedToMessageWaServerTimeSec() string {
+	if x != nil && x.RepliedToMessageWaServerTimeSec != nil {
+		return *x.RepliedToMessageWaServerTimeSec
+	}
+	return ""
+}
+
+func (x *RepliedToMessage) GetRepliedToMessageCollectionItemID() string {
+	if x != nil && x.RepliedToMessageCollectionItemID != nil {
+		return *x.RepliedToMessageCollectionItemID
+	}
+	return ""
+}
+
+func (x *RepliedToMessage) GetOmMicroSecTS() *OpenMessageMicroSecondTimestamp {
+	if x != nil {
+		return x.OmMicroSecTS
+	}
+	return nil
+}
+
+type OpenMessageMicroSecondTimestamp struct {
+	state            protoimpl.MessageState `protogen:"open.v1"`
+	TimestampMS      *int64                 `protobuf:"varint,1,opt,name=timestampMS" json:"timestampMS,omitempty"`
+	MicroSecondsBits *int32                 `protobuf:"varint,2,opt,name=microSecondsBits" json:"microSecondsBits,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *OpenMessageMicroSecondTimestamp) Reset() {
+	*x = OpenMessageMicroSecondTimestamp{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OpenMessageMicroSecondTimestamp) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OpenMessageMicroSecondTimestamp) ProtoMessage() {}
+
+func (x *OpenMessageMicroSecondTimestamp) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OpenMessageMicroSecondTimestamp.ProtoReflect.Descriptor instead.
+func (*OpenMessageMicroSecondTimestamp) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *OpenMessageMicroSecondTimestamp) GetTimestampMS() int64 {
+	if x != nil && x.TimestampMS != nil {
+		return *x.TimestampMS
+	}
+	return 0
+}
+
+func (x *OpenMessageMicroSecondTimestamp) GetMicroSecondsBits() int32 {
+	if x != nil && x.MicroSecondsBits != nil {
+		return *x.MicroSecondsBits
+	}
+	return 0
+}
+
+type PrivateReplyInfo struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	CommentID     *string                `protobuf:"bytes,1,opt,name=commentID" json:"commentID,omitempty"`
+	PostLink      *string                `protobuf:"bytes,2,opt,name=postLink" json:"postLink,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *PrivateReplyInfo) Reset() {
+	*x = PrivateReplyInfo{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *PrivateReplyInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrivateReplyInfo) ProtoMessage() {}
+
+func (x *PrivateReplyInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PrivateReplyInfo.ProtoReflect.Descriptor instead.
+func (*PrivateReplyInfo) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *PrivateReplyInfo) GetCommentID() string {
+	if x != nil && x.CommentID != nil {
+		return *x.CommentID
+	}
+	return ""
+}
+
+func (x *PrivateReplyInfo) GetPostLink() string {
+	if x != nil && x.PostLink != nil {
+		return *x.PostLink
+	}
+	return ""
+}
+
+type ForwardingParams struct {
+	state             protoimpl.MessageState `protogen:"open.v1"`
+	ForwardedThreadID *string                `protobuf:"bytes,1,opt,name=forwardedThreadID" json:"forwardedThreadID,omitempty"`
+	unknownFields     protoimpl.UnknownFields
+	sizeCache         protoimpl.SizeCache
+}
+
+func (x *ForwardingParams) Reset() {
+	*x = ForwardingParams{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ForwardingParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ForwardingParams) ProtoMessage() {}
+
+func (x *ForwardingParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ForwardingParams.ProtoReflect.Descriptor instead.
+func (*ForwardingParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ForwardingParams) GetForwardedThreadID() string {
+	if x != nil && x.ForwardedThreadID != nil {
+		return *x.ForwardedThreadID
+	}
+	return ""
+}
+
+type EphemeralityParams struct {
+	state                protoimpl.MessageState `protogen:"open.v1"`
+	EphemeralDurationSec *int64                 `protobuf:"varint,1,opt,name=ephemeralDurationSec" json:"ephemeralDurationSec,omitempty"`
+	unknownFields        protoimpl.UnknownFields
+	sizeCache            protoimpl.SizeCache
+}
+
+func (x *EphemeralityParams) Reset() {
+	*x = EphemeralityParams{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *EphemeralityParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EphemeralityParams) ProtoMessage() {}
+
+func (x *EphemeralityParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use EphemeralityParams.ProtoReflect.Descriptor instead.
+func (*EphemeralityParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *EphemeralityParams) GetEphemeralDurationSec() int64 {
+	if x != nil && x.EphemeralDurationSec != nil {
+		return *x.EphemeralDurationSec
+	}
+	return 0
+}
+
+type Like struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Like) Reset() {
+	*x = Like{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Like) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Like) ProtoMessage() {}
+
+func (x *Like) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Like.ProtoReflect.Descriptor instead.
+func (*Like) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{8}
+}
+
+type ReceiverFetchXma struct {
+	state         protoimpl.MessageState                   `protogen:"open.v1"`
+	ContentRef    *string                                  `protobuf:"bytes,1,opt,name=contentRef" json:"contentRef,omitempty"`
+	Text          *string                                  `protobuf:"bytes,2,opt,name=text" json:"text,omitempty"`
+	Media         *instamadilloCoreTypeMedia.Media         `protobuf:"bytes,3,opt,name=media" json:"media,omitempty"`
+	XmaContentRef *instamadilloXmaContentRef.XmaContentRef `protobuf:"bytes,4,opt,name=xmaContentRef" json:"xmaContentRef,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXma) Reset() {
+	*x = ReceiverFetchXma{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXma) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXma) ProtoMessage() {}
+
+func (x *ReceiverFetchXma) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXma.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXma) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *ReceiverFetchXma) GetContentRef() string {
+	if x != nil && x.ContentRef != nil {
+		return *x.ContentRef
+	}
+	return ""
+}
+
+func (x *ReceiverFetchXma) GetText() string {
+	if x != nil && x.Text != nil {
+		return *x.Text
+	}
+	return ""
+}
+
+func (x *ReceiverFetchXma) GetMedia() *instamadilloCoreTypeMedia.Media {
+	if x != nil {
+		return x.Media
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXma) GetXmaContentRef() *instamadilloXmaContentRef.XmaContentRef {
+	if x != nil {
+		return x.XmaContentRef
+	}
+	return nil
+}
+
+type Placeholder struct {
+	state           protoimpl.MessageState `protogen:"open.v1"`
+	PlaceholderType *Placeholder_Type      `protobuf:"varint,1,opt,name=placeholderType,enum=InstamadilloAddMessage.Placeholder_Type" json:"placeholderType,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *Placeholder) Reset() {
+	*x = Placeholder{}
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Placeholder) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Placeholder) ProtoMessage() {}
+
+func (x *Placeholder) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Placeholder.ProtoReflect.Descriptor instead.
+func (*Placeholder) Descriptor() ([]byte, []int) {
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *Placeholder) GetPlaceholderType() Placeholder_Type {
+	if x != nil && x.PlaceholderType != nil {
+		return *x.PlaceholderType
+	}
+	return Placeholder_PLACEHOLDER_TYPE_NONE
+}
+
+var File_instamadilloAddMessage_InstamadilloAddMessage_proto protoreflect.FileDescriptor
+
+const file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDesc = "" +
+	"\n" +
+	"3instamadilloAddMessage/InstamadilloAddMessage.proto\x12\x16InstamadilloAddMessage\x1aAinstamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.proto\x1aGinstamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.proto\x1aCinstamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.proto\x1a7instamadilloCoreTypeLink/InstamadilloCoreTypeLink.proto\x1a9instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto\x1a7instamadilloCoreTypeText/InstamadilloCoreTypeText.proto\x1a9instamadilloXmaContentRef/InstamadilloXmaContentRef.proto\"\xa0\x01\n" +
+	"\x11AddMessagePayload\x12C\n" +
+	"\acontent\x18\x01 \x01(\v2).InstamadilloAddMessage.AddMessageContentR\acontent\x12F\n" +
+	"\bmetadata\x18\x02 \x01(\v2*.InstamadilloAddMessage.AddMessageMetadataR\bmetadata\"\x91\x05\n" +
+	"\x11AddMessageContent\x124\n" +
+	"\x04text\x18\x01 \x01(\v2\x1e.InstamadilloCoreTypeText.TextH\x00R\x04text\x122\n" +
+	"\x04like\x18\x02 \x01(\v2\x1c.InstamadilloAddMessage.LikeH\x00R\x04like\x124\n" +
+	"\x04link\x18\x03 \x01(\v2\x1e.InstamadilloCoreTypeLink.LinkH\x00R\x04link\x12V\n" +
+	"\x10receiverFetchXma\x18\x04 \x01(\v2(.InstamadilloAddMessage.ReceiverFetchXmaH\x00R\x10receiverFetchXma\x128\n" +
+	"\x05media\x18\x05 \x01(\v2 .InstamadilloCoreTypeMedia.MediaH\x00R\x05media\x12G\n" +
+	"\vplaceholder\x18\x06 \x01(\v2#.InstamadilloAddMessage.PlaceholderH\x00R\vplaceholder\x12L\n" +
+	"\n" +
+	"collection\x18\a \x01(\v2*.InstamadilloCoreTypeCollection.CollectionH\x00R\n" +
+	"collection\x12T\n" +
+	"\fadminMessage\x18\b \x01(\v2..InstamadilloCoreTypeAdminMessage.AdminMessageH\x00R\fadminMessage\x12H\n" +
+	"\tactionLog\x18\t \x01(\v2(.InstamadilloCoreTypeActionLog.ActionLogH\x00R\tactionLogB\x13\n" +
+	"\x11addMessageContent\"\x96\x03\n" +
+	"\x12AddMessageMetadata\x12\"\n" +
+	"\fsendSilently\x18\x01 \x01(\bR\fsendSilently\x12T\n" +
+	"\x10privateReplyInfo\x18\x02 \x01(\v2(.InstamadilloAddMessage.PrivateReplyInfoR\x10privateReplyInfo\x12T\n" +
+	"\x10repliedToMessage\x18\x03 \x01(\v2(.InstamadilloAddMessage.RepliedToMessageR\x10repliedToMessage\x12T\n" +
+	"\x10forwardingParams\x18\x04 \x01(\v2(.InstamadilloAddMessage.ForwardingParamsR\x10forwardingParams\x12Z\n" +
+	"\x12ephemeralityParams\x18\x05 \x01(\v2*.InstamadilloAddMessage.EphemeralityParamsR\x12ephemeralityParams\"\xb9\x02\n" +
+	"\x10RepliedToMessage\x122\n" +
+	"\x14repliedToMessageOtid\x18\x01 \x01(\tR\x14repliedToMessageOtid\x12H\n" +
+	"\x1frepliedToMessageWaServerTimeSec\x18\x02 \x01(\tR\x1frepliedToMessageWaServerTimeSec\x12J\n" +
+	" repliedToMessageCollectionItemID\x18\x03 \x01(\tR repliedToMessageCollectionItemID\x12[\n" +
+	"\fomMicroSecTS\x18\x04 \x01(\v27.InstamadilloAddMessage.OpenMessageMicroSecondTimestampR\fomMicroSecTS\"o\n" +
+	"\x1fOpenMessageMicroSecondTimestamp\x12 \n" +
+	"\vtimestampMS\x18\x01 \x01(\x03R\vtimestampMS\x12*\n" +
+	"\x10microSecondsBits\x18\x02 \x01(\x05R\x10microSecondsBits\"L\n" +
+	"\x10PrivateReplyInfo\x12\x1c\n" +
+	"\tcommentID\x18\x01 \x01(\tR\tcommentID\x12\x1a\n" +
+	"\bpostLink\x18\x02 \x01(\tR\bpostLink\"@\n" +
+	"\x10ForwardingParams\x12,\n" +
+	"\x11forwardedThreadID\x18\x01 \x01(\tR\x11forwardedThreadID\"H\n" +
+	"\x12EphemeralityParams\x122\n" +
+	"\x14ephemeralDurationSec\x18\x01 \x01(\x03R\x14ephemeralDurationSec\"\x06\n" +
+	"\x04Like\"\xce\x01\n" +
+	"\x10ReceiverFetchXma\x12\x1e\n" +
+	"\n" +
+	"contentRef\x18\x01 \x01(\tR\n" +
+	"contentRef\x12\x12\n" +
+	"\x04text\x18\x02 \x01(\tR\x04text\x126\n" +
+	"\x05media\x18\x03 \x01(\v2 .InstamadilloCoreTypeMedia.MediaR\x05media\x12N\n" +
+	"\rxmaContentRef\x18\x04 \x01(\v2(.InstamadilloXmaContentRef.XmaContentRefR\rxmaContentRef\"\xbb\x02\n" +
+	"\vPlaceholder\x12R\n" +
+	"\x0fplaceholderType\x18\x01 \x01(\x0e2(.InstamadilloAddMessage.Placeholder.TypeR\x0fplaceholderType\"\xd7\x01\n" +
+	"\x04Type\x12\x19\n" +
+	"\x15PLACEHOLDER_TYPE_NONE\x10\x00\x12'\n" +
+	"#PLACEHOLDER_TYPE_DECRYPTION_FAILURE\x10\x01\x12.\n" +
+	"*PLACEHOLDER_TYPE_NOT_SUPPORTED_NEED_UPDATE\x10\x02\x12'\n" +
+	"#PLACEHOLDER_TYPE_DEVICE_UNAVAILABLE\x10\x03\x122\n" +
+	".PLACEHOLDER_TYPE_NOT_SUPPORTED_NOT_RECOVERABLE\x10\x04B2Z0go.mau.fi/whatsmeow/proto/instamadilloAddMessage"
+
+var (
+	file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescOnce sync.Once
+	file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescData []byte
+)
+
+func file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescGZIP() []byte {
+	file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescOnce.Do(func() {
+		file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDesc), len(file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDesc)))
+	})
+	return file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDescData
+}
+
+var file_instamadilloAddMessage_InstamadilloAddMessage_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
+var file_instamadilloAddMessage_InstamadilloAddMessage_proto_goTypes = []any{
+	(Placeholder_Type)(0),                                 // 0: InstamadilloAddMessage.Placeholder.Type
+	(*AddMessagePayload)(nil),                             // 1: InstamadilloAddMessage.AddMessagePayload
+	(*AddMessageContent)(nil),                             // 2: InstamadilloAddMessage.AddMessageContent
+	(*AddMessageMetadata)(nil),                            // 3: InstamadilloAddMessage.AddMessageMetadata
+	(*RepliedToMessage)(nil),                              // 4: InstamadilloAddMessage.RepliedToMessage
+	(*OpenMessageMicroSecondTimestamp)(nil),               // 5: InstamadilloAddMessage.OpenMessageMicroSecondTimestamp
+	(*PrivateReplyInfo)(nil),                              // 6: InstamadilloAddMessage.PrivateReplyInfo
+	(*ForwardingParams)(nil),                              // 7: InstamadilloAddMessage.ForwardingParams
+	(*EphemeralityParams)(nil),                            // 8: InstamadilloAddMessage.EphemeralityParams
+	(*Like)(nil),                                          // 9: InstamadilloAddMessage.Like
+	(*ReceiverFetchXma)(nil),                              // 10: InstamadilloAddMessage.ReceiverFetchXma
+	(*Placeholder)(nil),                                   // 11: InstamadilloAddMessage.Placeholder
+	(*instamadilloCoreTypeText.Text)(nil),                 // 12: InstamadilloCoreTypeText.Text
+	(*instamadilloCoreTypeLink.Link)(nil),                 // 13: InstamadilloCoreTypeLink.Link
+	(*instamadilloCoreTypeMedia.Media)(nil),               // 14: InstamadilloCoreTypeMedia.Media
+	(*instamadilloCoreTypeCollection.Collection)(nil),     // 15: InstamadilloCoreTypeCollection.Collection
+	(*instamadilloCoreTypeAdminMessage.AdminMessage)(nil), // 16: InstamadilloCoreTypeAdminMessage.AdminMessage
+	(*instamadilloCoreTypeActionLog.ActionLog)(nil),       // 17: InstamadilloCoreTypeActionLog.ActionLog
+	(*instamadilloXmaContentRef.XmaContentRef)(nil),       // 18: InstamadilloXmaContentRef.XmaContentRef
+}
+var file_instamadilloAddMessage_InstamadilloAddMessage_proto_depIdxs = []int32{
+	2,  // 0: InstamadilloAddMessage.AddMessagePayload.content:type_name -> InstamadilloAddMessage.AddMessageContent
+	3,  // 1: InstamadilloAddMessage.AddMessagePayload.metadata:type_name -> InstamadilloAddMessage.AddMessageMetadata
+	12, // 2: InstamadilloAddMessage.AddMessageContent.text:type_name -> InstamadilloCoreTypeText.Text
+	9,  // 3: InstamadilloAddMessage.AddMessageContent.like:type_name -> InstamadilloAddMessage.Like
+	13, // 4: InstamadilloAddMessage.AddMessageContent.link:type_name -> InstamadilloCoreTypeLink.Link
+	10, // 5: InstamadilloAddMessage.AddMessageContent.receiverFetchXma:type_name -> InstamadilloAddMessage.ReceiverFetchXma
+	14, // 6: InstamadilloAddMessage.AddMessageContent.media:type_name -> InstamadilloCoreTypeMedia.Media
+	11, // 7: InstamadilloAddMessage.AddMessageContent.placeholder:type_name -> InstamadilloAddMessage.Placeholder
+	15, // 8: InstamadilloAddMessage.AddMessageContent.collection:type_name -> InstamadilloCoreTypeCollection.Collection
+	16, // 9: InstamadilloAddMessage.AddMessageContent.adminMessage:type_name -> InstamadilloCoreTypeAdminMessage.AdminMessage
+	17, // 10: InstamadilloAddMessage.AddMessageContent.actionLog:type_name -> InstamadilloCoreTypeActionLog.ActionLog
+	6,  // 11: InstamadilloAddMessage.AddMessageMetadata.privateReplyInfo:type_name -> InstamadilloAddMessage.PrivateReplyInfo
+	4,  // 12: InstamadilloAddMessage.AddMessageMetadata.repliedToMessage:type_name -> InstamadilloAddMessage.RepliedToMessage
+	7,  // 13: InstamadilloAddMessage.AddMessageMetadata.forwardingParams:type_name -> InstamadilloAddMessage.ForwardingParams
+	8,  // 14: InstamadilloAddMessage.AddMessageMetadata.ephemeralityParams:type_name -> InstamadilloAddMessage.EphemeralityParams
+	5,  // 15: InstamadilloAddMessage.RepliedToMessage.omMicroSecTS:type_name -> InstamadilloAddMessage.OpenMessageMicroSecondTimestamp
+	14, // 16: InstamadilloAddMessage.ReceiverFetchXma.media:type_name -> InstamadilloCoreTypeMedia.Media
+	18, // 17: InstamadilloAddMessage.ReceiverFetchXma.xmaContentRef:type_name -> InstamadilloXmaContentRef.XmaContentRef
+	0,  // 18: InstamadilloAddMessage.Placeholder.placeholderType:type_name -> InstamadilloAddMessage.Placeholder.Type
+	19, // [19:19] is the sub-list for method output_type
+	19, // [19:19] is the sub-list for method input_type
+	19, // [19:19] is the sub-list for extension type_name
+	19, // [19:19] is the sub-list for extension extendee
+	0,  // [0:19] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloAddMessage_InstamadilloAddMessage_proto_init() }
+func file_instamadilloAddMessage_InstamadilloAddMessage_proto_init() {
+	if File_instamadilloAddMessage_InstamadilloAddMessage_proto != nil {
+		return
+	}
+	file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes[1].OneofWrappers = []any{
+		(*AddMessageContent_Text)(nil),
+		(*AddMessageContent_Like)(nil),
+		(*AddMessageContent_Link)(nil),
+		(*AddMessageContent_ReceiverFetchXma)(nil),
+		(*AddMessageContent_Media)(nil),
+		(*AddMessageContent_Placeholder)(nil),
+		(*AddMessageContent_Collection)(nil),
+		(*AddMessageContent_AdminMessage)(nil),
+		(*AddMessageContent_ActionLog)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDesc), len(file_instamadilloAddMessage_InstamadilloAddMessage_proto_rawDesc)),
+			NumEnums:      1,
+			NumMessages:   11,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloAddMessage_InstamadilloAddMessage_proto_goTypes,
+		DependencyIndexes: file_instamadilloAddMessage_InstamadilloAddMessage_proto_depIdxs,
+		EnumInfos:         file_instamadilloAddMessage_InstamadilloAddMessage_proto_enumTypes,
+		MessageInfos:      file_instamadilloAddMessage_InstamadilloAddMessage_proto_msgTypes,
+	}.Build()
+	File_instamadilloAddMessage_InstamadilloAddMessage_proto = out.File
+	file_instamadilloAddMessage_InstamadilloAddMessage_proto_goTypes = nil
+	file_instamadilloAddMessage_InstamadilloAddMessage_proto_depIdxs = nil
+}

+ 85 - 0
proto/instamadilloAddMessage/InstamadilloAddMessage.proto

@@ -0,0 +1,85 @@
+syntax = "proto2";
+package InstamadilloAddMessage;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloAddMessage";
+
+import "instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.proto";
+import "instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.proto";
+import "instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.proto";
+import "instamadilloCoreTypeLink/InstamadilloCoreTypeLink.proto";
+import "instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto";
+import "instamadilloCoreTypeText/InstamadilloCoreTypeText.proto";
+import "instamadilloXmaContentRef/InstamadilloXmaContentRef.proto";
+
+message AddMessagePayload {
+	optional AddMessageContent content = 1;
+	optional AddMessageMetadata metadata = 2;
+}
+
+message AddMessageContent {
+	oneof addMessageContent {
+		InstamadilloCoreTypeText.Text text = 1;
+		Like like = 2;
+		InstamadilloCoreTypeLink.Link link = 3;
+		ReceiverFetchXma receiverFetchXma = 4;
+		InstamadilloCoreTypeMedia.Media media = 5;
+		Placeholder placeholder = 6;
+		InstamadilloCoreTypeCollection.Collection collection = 7;
+		InstamadilloCoreTypeAdminMessage.AdminMessage adminMessage = 8;
+		InstamadilloCoreTypeActionLog.ActionLog actionLog = 9;
+	}
+}
+
+message AddMessageMetadata {
+	optional bool sendSilently = 1;
+	optional PrivateReplyInfo privateReplyInfo = 2;
+	optional RepliedToMessage repliedToMessage = 3;
+	optional ForwardingParams forwardingParams = 4;
+	optional EphemeralityParams ephemeralityParams = 5;
+}
+
+message RepliedToMessage {
+	optional string repliedToMessageOtid = 1;
+	optional string repliedToMessageWaServerTimeSec = 2;
+	optional string repliedToMessageCollectionItemID = 3;
+	optional OpenMessageMicroSecondTimestamp omMicroSecTS = 4;
+}
+
+message OpenMessageMicroSecondTimestamp {
+	optional int64 timestampMS = 1;
+	optional int32 microSecondsBits = 2;
+}
+
+message PrivateReplyInfo {
+	optional string commentID = 1;
+	optional string postLink = 2;
+}
+
+message ForwardingParams {
+	optional string forwardedThreadID = 1;
+}
+
+message EphemeralityParams {
+	optional int64 ephemeralDurationSec = 1;
+}
+
+message Like {
+}
+
+message ReceiverFetchXma {
+	optional string contentRef = 1;
+	optional string text = 2;
+	optional InstamadilloCoreTypeMedia.Media media = 3;
+	optional InstamadilloXmaContentRef.XmaContentRef xmaContentRef = 4;
+}
+
+message Placeholder {
+	enum Type {
+		PLACEHOLDER_TYPE_NONE = 0;
+		PLACEHOLDER_TYPE_DECRYPTION_FAILURE = 1;
+		PLACEHOLDER_TYPE_NOT_SUPPORTED_NEED_UPDATE = 2;
+		PLACEHOLDER_TYPE_DEVICE_UNAVAILABLE = 3;
+		PLACEHOLDER_TYPE_NOT_SUPPORTED_NOT_RECOVERABLE = 4;
+	}
+
+	optional Type placeholderType = 1;
+}

+ 3 - 0
proto/instamadilloAddMessage/extra.go

@@ -0,0 +1,3 @@
+package instamadilloAddMessage
+
+func (*AddMessagePayload) IsMessageApplicationSub() {}

+ 197 - 0
proto/instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.pb.go

@@ -0,0 +1,197 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.proto
+
+package instamadilloCoreTypeActionLog
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ActionLog struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to ActionLogSubtype:
+	//
+	//	*ActionLog_ActionLogReaction
+	ActionLogSubtype isActionLog_ActionLogSubtype `protobuf_oneof:"actionLogSubtype"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *ActionLog) Reset() {
+	*x = ActionLog{}
+	mi := &file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ActionLog) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ActionLog) ProtoMessage() {}
+
+func (x *ActionLog) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ActionLog.ProtoReflect.Descriptor instead.
+func (*ActionLog) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ActionLog) GetActionLogSubtype() isActionLog_ActionLogSubtype {
+	if x != nil {
+		return x.ActionLogSubtype
+	}
+	return nil
+}
+
+func (x *ActionLog) GetActionLogReaction() *ActionLogReaction {
+	if x != nil {
+		if x, ok := x.ActionLogSubtype.(*ActionLog_ActionLogReaction); ok {
+			return x.ActionLogReaction
+		}
+	}
+	return nil
+}
+
+type isActionLog_ActionLogSubtype interface {
+	isActionLog_ActionLogSubtype()
+}
+
+type ActionLog_ActionLogReaction struct {
+	ActionLogReaction *ActionLogReaction `protobuf:"bytes,1,opt,name=actionLogReaction,oneof"`
+}
+
+func (*ActionLog_ActionLogReaction) isActionLog_ActionLogSubtype() {}
+
+type ActionLogReaction struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	EmojiUnicode  *string                `protobuf:"bytes,1,opt,name=emojiUnicode" json:"emojiUnicode,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ActionLogReaction) Reset() {
+	*x = ActionLogReaction{}
+	mi := &file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ActionLogReaction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ActionLogReaction) ProtoMessage() {}
+
+func (x *ActionLogReaction) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ActionLogReaction.ProtoReflect.Descriptor instead.
+func (*ActionLogReaction) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ActionLogReaction) GetEmojiUnicode() string {
+	if x != nil && x.EmojiUnicode != nil {
+		return *x.EmojiUnicode
+	}
+	return ""
+}
+
+var File_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto protoreflect.FileDescriptor
+
+const file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDesc = "" +
+	"\n" +
+	"AinstamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.proto\x12\x1dInstamadilloCoreTypeActionLog\"\x81\x01\n" +
+	"\tActionLog\x12`\n" +
+	"\x11actionLogReaction\x18\x01 \x01(\v20.InstamadilloCoreTypeActionLog.ActionLogReactionH\x00R\x11actionLogReactionB\x12\n" +
+	"\x10actionLogSubtype\"7\n" +
+	"\x11ActionLogReaction\x12\"\n" +
+	"\femojiUnicode\x18\x01 \x01(\tR\femojiUnicodeB9Z7go.mau.fi/whatsmeow/proto/instamadilloCoreTypeActionLog"
+
+var (
+	file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescOnce sync.Once
+	file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescData []byte
+)
+
+func file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescGZIP() []byte {
+	file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescOnce.Do(func() {
+		file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDesc), len(file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDesc)))
+	})
+	return file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDescData
+}
+
+var file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_goTypes = []any{
+	(*ActionLog)(nil),         // 0: InstamadilloCoreTypeActionLog.ActionLog
+	(*ActionLogReaction)(nil), // 1: InstamadilloCoreTypeActionLog.ActionLogReaction
+}
+var file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_depIdxs = []int32{
+	1, // 0: InstamadilloCoreTypeActionLog.ActionLog.actionLogReaction:type_name -> InstamadilloCoreTypeActionLog.ActionLogReaction
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_init() }
+func file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_init() {
+	if File_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto != nil {
+		return
+	}
+	file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_msgTypes[0].OneofWrappers = []any{
+		(*ActionLog_ActionLogReaction)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDesc), len(file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_goTypes,
+		DependencyIndexes: file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_depIdxs,
+		MessageInfos:      file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_msgTypes,
+	}.Build()
+	File_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto = out.File
+	file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_goTypes = nil
+	file_instamadilloCoreTypeActionLog_InstamadilloCoreTypeActionLog_proto_depIdxs = nil
+}

+ 13 - 0
proto/instamadilloCoreTypeActionLog/InstamadilloCoreTypeActionLog.proto

@@ -0,0 +1,13 @@
+syntax = "proto2";
+package InstamadilloCoreTypeActionLog;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeActionLog";
+
+message ActionLog {
+	oneof actionLogSubtype {
+		ActionLogReaction actionLogReaction = 1;
+	}
+}
+
+message ActionLogReaction {
+	optional string emojiUnicode = 1;
+}

+ 279 - 0
proto/instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.pb.go

@@ -0,0 +1,279 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.proto
+
+package instamadilloCoreTypeAdminMessage
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type DeviceAdminMessage_Type int32
+
+const (
+	DeviceAdminMessage_DEVICE_ADMIN_MESSAGE_TYPE_NONE                                         DeviceAdminMessage_Type = 0
+	DeviceAdminMessage_DEVICE_ADMIN_MESSAGE_TYPE_LOCAL_USER_CHANGED_IDENTITY_KEY_NAMED_DEVICE DeviceAdminMessage_Type = 1
+	DeviceAdminMessage_DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_KEY_CHANGE        DeviceAdminMessage_Type = 2
+	DeviceAdminMessage_DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_NEW_LOGIN         DeviceAdminMessage_Type = 3
+)
+
+// Enum value maps for DeviceAdminMessage_Type.
+var (
+	DeviceAdminMessage_Type_name = map[int32]string{
+		0: "DEVICE_ADMIN_MESSAGE_TYPE_NONE",
+		1: "DEVICE_ADMIN_MESSAGE_TYPE_LOCAL_USER_CHANGED_IDENTITY_KEY_NAMED_DEVICE",
+		2: "DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_KEY_CHANGE",
+		3: "DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_NEW_LOGIN",
+	}
+	DeviceAdminMessage_Type_value = map[string]int32{
+		"DEVICE_ADMIN_MESSAGE_TYPE_NONE":                                         0,
+		"DEVICE_ADMIN_MESSAGE_TYPE_LOCAL_USER_CHANGED_IDENTITY_KEY_NAMED_DEVICE": 1,
+		"DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_KEY_CHANGE":        2,
+		"DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_NEW_LOGIN":         3,
+	}
+)
+
+func (x DeviceAdminMessage_Type) Enum() *DeviceAdminMessage_Type {
+	p := new(DeviceAdminMessage_Type)
+	*p = x
+	return p
+}
+
+func (x DeviceAdminMessage_Type) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (DeviceAdminMessage_Type) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_enumTypes[0].Descriptor()
+}
+
+func (DeviceAdminMessage_Type) Type() protoreflect.EnumType {
+	return &file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_enumTypes[0]
+}
+
+func (x DeviceAdminMessage_Type) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *DeviceAdminMessage_Type) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = DeviceAdminMessage_Type(num)
+	return nil
+}
+
+// Deprecated: Use DeviceAdminMessage_Type.Descriptor instead.
+func (DeviceAdminMessage_Type) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescGZIP(), []int{1, 0}
+}
+
+type AdminMessage struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to AdminMessageSubtype:
+	//
+	//	*AdminMessage_DeviceAdminMessage
+	AdminMessageSubtype isAdminMessage_AdminMessageSubtype `protobuf_oneof:"adminMessageSubtype"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *AdminMessage) Reset() {
+	*x = AdminMessage{}
+	mi := &file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AdminMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AdminMessage) ProtoMessage() {}
+
+func (x *AdminMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AdminMessage.ProtoReflect.Descriptor instead.
+func (*AdminMessage) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *AdminMessage) GetAdminMessageSubtype() isAdminMessage_AdminMessageSubtype {
+	if x != nil {
+		return x.AdminMessageSubtype
+	}
+	return nil
+}
+
+func (x *AdminMessage) GetDeviceAdminMessage() *DeviceAdminMessage {
+	if x != nil {
+		if x, ok := x.AdminMessageSubtype.(*AdminMessage_DeviceAdminMessage); ok {
+			return x.DeviceAdminMessage
+		}
+	}
+	return nil
+}
+
+type isAdminMessage_AdminMessageSubtype interface {
+	isAdminMessage_AdminMessageSubtype()
+}
+
+type AdminMessage_DeviceAdminMessage struct {
+	DeviceAdminMessage *DeviceAdminMessage `protobuf:"bytes,1,opt,name=deviceAdminMessage,oneof"`
+}
+
+func (*AdminMessage_DeviceAdminMessage) isAdminMessage_AdminMessageSubtype() {}
+
+type DeviceAdminMessage struct {
+	state                  protoimpl.MessageState   `protogen:"open.v1"`
+	DeviceAdminMessageType *DeviceAdminMessage_Type `protobuf:"varint,1,opt,name=deviceAdminMessageType,enum=InstamadilloCoreTypeAdminMessage.DeviceAdminMessage_Type" json:"deviceAdminMessageType,omitempty"`
+	DeviceName             *string                  `protobuf:"bytes,2,opt,name=deviceName" json:"deviceName,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *DeviceAdminMessage) Reset() {
+	*x = DeviceAdminMessage{}
+	mi := &file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *DeviceAdminMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeviceAdminMessage) ProtoMessage() {}
+
+func (x *DeviceAdminMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeviceAdminMessage.ProtoReflect.Descriptor instead.
+func (*DeviceAdminMessage) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *DeviceAdminMessage) GetDeviceAdminMessageType() DeviceAdminMessage_Type {
+	if x != nil && x.DeviceAdminMessageType != nil {
+		return *x.DeviceAdminMessageType
+	}
+	return DeviceAdminMessage_DEVICE_ADMIN_MESSAGE_TYPE_NONE
+}
+
+func (x *DeviceAdminMessage) GetDeviceName() string {
+	if x != nil && x.DeviceName != nil {
+		return *x.DeviceName
+	}
+	return ""
+}
+
+var File_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto protoreflect.FileDescriptor
+
+const file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDesc = "" +
+	"\n" +
+	"GinstamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.proto\x12 InstamadilloCoreTypeAdminMessage\"\x8d\x01\n" +
+	"\fAdminMessage\x12f\n" +
+	"\x12deviceAdminMessage\x18\x01 \x01(\v24.InstamadilloCoreTypeAdminMessage.DeviceAdminMessageH\x00R\x12deviceAdminMessageB\x15\n" +
+	"\x13adminMessageSubtype\"\xa9\x03\n" +
+	"\x12DeviceAdminMessage\x12q\n" +
+	"\x16deviceAdminMessageType\x18\x01 \x01(\x0e29.InstamadilloCoreTypeAdminMessage.DeviceAdminMessage.TypeR\x16deviceAdminMessageType\x12\x1e\n" +
+	"\n" +
+	"deviceName\x18\x02 \x01(\tR\n" +
+	"deviceName\"\xff\x01\n" +
+	"\x04Type\x12\"\n" +
+	"\x1eDEVICE_ADMIN_MESSAGE_TYPE_NONE\x10\x00\x12J\n" +
+	"FDEVICE_ADMIN_MESSAGE_TYPE_LOCAL_USER_CHANGED_IDENTITY_KEY_NAMED_DEVICE\x10\x01\x12C\n" +
+	"?DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_KEY_CHANGE\x10\x02\x12B\n" +
+	">DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_NEW_LOGIN\x10\x03B<Z:go.mau.fi/whatsmeow/proto/instamadilloCoreTypeAdminMessage"
+
+var (
+	file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescOnce sync.Once
+	file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescData []byte
+)
+
+func file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescGZIP() []byte {
+	file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescOnce.Do(func() {
+		file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDesc), len(file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDesc)))
+	})
+	return file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDescData
+}
+
+var file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_goTypes = []any{
+	(DeviceAdminMessage_Type)(0), // 0: InstamadilloCoreTypeAdminMessage.DeviceAdminMessage.Type
+	(*AdminMessage)(nil),         // 1: InstamadilloCoreTypeAdminMessage.AdminMessage
+	(*DeviceAdminMessage)(nil),   // 2: InstamadilloCoreTypeAdminMessage.DeviceAdminMessage
+}
+var file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_depIdxs = []int32{
+	2, // 0: InstamadilloCoreTypeAdminMessage.AdminMessage.deviceAdminMessage:type_name -> InstamadilloCoreTypeAdminMessage.DeviceAdminMessage
+	0, // 1: InstamadilloCoreTypeAdminMessage.DeviceAdminMessage.deviceAdminMessageType:type_name -> InstamadilloCoreTypeAdminMessage.DeviceAdminMessage.Type
+	2, // [2:2] is the sub-list for method output_type
+	2, // [2:2] is the sub-list for method input_type
+	2, // [2:2] is the sub-list for extension type_name
+	2, // [2:2] is the sub-list for extension extendee
+	0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_init() }
+func file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_init() {
+	if File_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto != nil {
+		return
+	}
+	file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_msgTypes[0].OneofWrappers = []any{
+		(*AdminMessage_DeviceAdminMessage)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDesc), len(file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_rawDesc)),
+			NumEnums:      1,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_goTypes,
+		DependencyIndexes: file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_depIdxs,
+		EnumInfos:         file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_enumTypes,
+		MessageInfos:      file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_msgTypes,
+	}.Build()
+	File_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto = out.File
+	file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_goTypes = nil
+	file_instamadilloCoreTypeAdminMessage_InstamadilloCoreTypeAdminMessage_proto_depIdxs = nil
+}

+ 21 - 0
proto/instamadilloCoreTypeAdminMessage/InstamadilloCoreTypeAdminMessage.proto

@@ -0,0 +1,21 @@
+syntax = "proto2";
+package InstamadilloCoreTypeAdminMessage;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeAdminMessage";
+
+message AdminMessage {
+	oneof adminMessageSubtype {
+		DeviceAdminMessage deviceAdminMessage = 1;
+	}
+}
+
+message DeviceAdminMessage {
+	enum Type {
+		DEVICE_ADMIN_MESSAGE_TYPE_NONE = 0;
+		DEVICE_ADMIN_MESSAGE_TYPE_LOCAL_USER_CHANGED_IDENTITY_KEY_NAMED_DEVICE = 1;
+		DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_KEY_CHANGE = 2;
+		DEVICE_ADMIN_MESSAGE_TYPE_SECURITY_ALERT_PARTICIPANT_NEW_LOGIN = 3;
+	}
+
+	optional Type deviceAdminMessageType = 1;
+	optional string deviceName = 2;
+}

+ 137 - 0
proto/instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.pb.go

@@ -0,0 +1,137 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.proto
+
+package instamadilloCoreTypeCollection
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	instamadilloCoreTypeMedia "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Collection struct {
+	state         protoimpl.MessageState             `protogen:"open.v1"`
+	Name          *string                            `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	Media         []*instamadilloCoreTypeMedia.Media `protobuf:"bytes,2,rep,name=media" json:"media,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Collection) Reset() {
+	*x = Collection{}
+	mi := &file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Collection) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Collection) ProtoMessage() {}
+
+func (x *Collection) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Collection.ProtoReflect.Descriptor instead.
+func (*Collection) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Collection) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *Collection) GetMedia() []*instamadilloCoreTypeMedia.Media {
+	if x != nil {
+		return x.Media
+	}
+	return nil
+}
+
+var File_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto protoreflect.FileDescriptor
+
+const file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDesc = "" +
+	"\n" +
+	"CinstamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.proto\x12\x1eInstamadilloCoreTypeCollection\x1a9instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto\"X\n" +
+	"\n" +
+	"Collection\x12\x12\n" +
+	"\x04name\x18\x01 \x01(\tR\x04name\x126\n" +
+	"\x05media\x18\x02 \x03(\v2 .InstamadilloCoreTypeMedia.MediaR\x05mediaB:Z8go.mau.fi/whatsmeow/proto/instamadilloCoreTypeCollection"
+
+var (
+	file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDescOnce sync.Once
+	file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDescData []byte
+)
+
+func file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDescGZIP() []byte {
+	file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDescOnce.Do(func() {
+		file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDesc), len(file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDesc)))
+	})
+	return file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDescData
+}
+
+var file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_goTypes = []any{
+	(*Collection)(nil),                      // 0: InstamadilloCoreTypeCollection.Collection
+	(*instamadilloCoreTypeMedia.Media)(nil), // 1: InstamadilloCoreTypeMedia.Media
+}
+var file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_depIdxs = []int32{
+	1, // 0: InstamadilloCoreTypeCollection.Collection.media:type_name -> InstamadilloCoreTypeMedia.Media
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_init() }
+func file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_init() {
+	if File_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDesc), len(file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_goTypes,
+		DependencyIndexes: file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_depIdxs,
+		MessageInfos:      file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_msgTypes,
+	}.Build()
+	File_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto = out.File
+	file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_goTypes = nil
+	file_instamadilloCoreTypeCollection_InstamadilloCoreTypeCollection_proto_depIdxs = nil
+}

+ 10 - 0
proto/instamadilloCoreTypeCollection/InstamadilloCoreTypeCollection.proto

@@ -0,0 +1,10 @@
+syntax = "proto2";
+package InstamadilloCoreTypeCollection;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeCollection";
+
+import "instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto";
+
+message Collection {
+	optional string name = 1;
+	repeated InstamadilloCoreTypeMedia.Media media = 2;
+}

+ 313 - 0
proto/instamadilloCoreTypeLink/InstamadilloCoreTypeLink.pb.go

@@ -0,0 +1,313 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloCoreTypeLink/InstamadilloCoreTypeLink.proto
+
+package instamadilloCoreTypeLink
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	instamadilloCoreTypeMedia "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Link struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Text          *string                `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"`
+	LinkContext   *LinkContext           `protobuf:"bytes,2,opt,name=linkContext" json:"linkContext,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Link) Reset() {
+	*x = Link{}
+	mi := &file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Link) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Link) ProtoMessage() {}
+
+func (x *Link) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Link.ProtoReflect.Descriptor instead.
+func (*Link) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Link) GetText() string {
+	if x != nil && x.Text != nil {
+		return *x.Text
+	}
+	return ""
+}
+
+func (x *Link) GetLinkContext() *LinkContext {
+	if x != nil {
+		return x.LinkContext
+	}
+	return nil
+}
+
+type LinkContext struct {
+	state                            protoimpl.MessageState               `protogen:"open.v1"`
+	LinkImageURL                     *ImageUrl                            `protobuf:"bytes,1,opt,name=linkImageURL" json:"linkImageURL,omitempty"`
+	LinkPreviewTitle                 *string                              `protobuf:"bytes,2,opt,name=linkPreviewTitle" json:"linkPreviewTitle,omitempty"`
+	LinkURL                          *string                              `protobuf:"bytes,3,opt,name=linkURL" json:"linkURL,omitempty"`
+	LinkSummary                      *string                              `protobuf:"bytes,4,opt,name=linkSummary" json:"linkSummary,omitempty"`
+	LinkMusicPreviewURL              *string                              `protobuf:"bytes,5,opt,name=linkMusicPreviewURL" json:"linkMusicPreviewURL,omitempty"`
+	LinkMusicPreviewCountriesAllowed []string                             `protobuf:"bytes,6,rep,name=linkMusicPreviewCountriesAllowed" json:"linkMusicPreviewCountriesAllowed,omitempty"`
+	LinkPreviewThumbnail             *instamadilloCoreTypeMedia.Thumbnail `protobuf:"bytes,7,opt,name=linkPreviewThumbnail" json:"linkPreviewThumbnail,omitempty"`
+	LinkPreviewBody                  *string                              `protobuf:"bytes,8,opt,name=linkPreviewBody" json:"linkPreviewBody,omitempty"`
+	unknownFields                    protoimpl.UnknownFields
+	sizeCache                        protoimpl.SizeCache
+}
+
+func (x *LinkContext) Reset() {
+	*x = LinkContext{}
+	mi := &file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *LinkContext) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LinkContext) ProtoMessage() {}
+
+func (x *LinkContext) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use LinkContext.ProtoReflect.Descriptor instead.
+func (*LinkContext) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *LinkContext) GetLinkImageURL() *ImageUrl {
+	if x != nil {
+		return x.LinkImageURL
+	}
+	return nil
+}
+
+func (x *LinkContext) GetLinkPreviewTitle() string {
+	if x != nil && x.LinkPreviewTitle != nil {
+		return *x.LinkPreviewTitle
+	}
+	return ""
+}
+
+func (x *LinkContext) GetLinkURL() string {
+	if x != nil && x.LinkURL != nil {
+		return *x.LinkURL
+	}
+	return ""
+}
+
+func (x *LinkContext) GetLinkSummary() string {
+	if x != nil && x.LinkSummary != nil {
+		return *x.LinkSummary
+	}
+	return ""
+}
+
+func (x *LinkContext) GetLinkMusicPreviewURL() string {
+	if x != nil && x.LinkMusicPreviewURL != nil {
+		return *x.LinkMusicPreviewURL
+	}
+	return ""
+}
+
+func (x *LinkContext) GetLinkMusicPreviewCountriesAllowed() []string {
+	if x != nil {
+		return x.LinkMusicPreviewCountriesAllowed
+	}
+	return nil
+}
+
+func (x *LinkContext) GetLinkPreviewThumbnail() *instamadilloCoreTypeMedia.Thumbnail {
+	if x != nil {
+		return x.LinkPreviewThumbnail
+	}
+	return nil
+}
+
+func (x *LinkContext) GetLinkPreviewBody() string {
+	if x != nil && x.LinkPreviewBody != nil {
+		return *x.LinkPreviewBody
+	}
+	return ""
+}
+
+type ImageUrl struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	URL           *string                `protobuf:"bytes,1,opt,name=URL" json:"URL,omitempty"`
+	Width         *int32                 `protobuf:"varint,2,opt,name=width" json:"width,omitempty"`
+	Height        *int32                 `protobuf:"varint,3,opt,name=height" json:"height,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ImageUrl) Reset() {
+	*x = ImageUrl{}
+	mi := &file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ImageUrl) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImageUrl) ProtoMessage() {}
+
+func (x *ImageUrl) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImageUrl.ProtoReflect.Descriptor instead.
+func (*ImageUrl) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ImageUrl) GetURL() string {
+	if x != nil && x.URL != nil {
+		return *x.URL
+	}
+	return ""
+}
+
+func (x *ImageUrl) GetWidth() int32 {
+	if x != nil && x.Width != nil {
+		return *x.Width
+	}
+	return 0
+}
+
+func (x *ImageUrl) GetHeight() int32 {
+	if x != nil && x.Height != nil {
+		return *x.Height
+	}
+	return 0
+}
+
+var File_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto protoreflect.FileDescriptor
+
+const file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDesc = "" +
+	"\n" +
+	"7instamadilloCoreTypeLink/InstamadilloCoreTypeLink.proto\x12\x18InstamadilloCoreTypeLink\x1a9instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto\"c\n" +
+	"\x04Link\x12\x12\n" +
+	"\x04text\x18\x01 \x01(\tR\x04text\x12G\n" +
+	"\vlinkContext\x18\x02 \x01(\v2%.InstamadilloCoreTypeLink.LinkContextR\vlinkContext\"\xbf\x03\n" +
+	"\vLinkContext\x12F\n" +
+	"\flinkImageURL\x18\x01 \x01(\v2\".InstamadilloCoreTypeLink.ImageUrlR\flinkImageURL\x12*\n" +
+	"\x10linkPreviewTitle\x18\x02 \x01(\tR\x10linkPreviewTitle\x12\x18\n" +
+	"\alinkURL\x18\x03 \x01(\tR\alinkURL\x12 \n" +
+	"\vlinkSummary\x18\x04 \x01(\tR\vlinkSummary\x120\n" +
+	"\x13linkMusicPreviewURL\x18\x05 \x01(\tR\x13linkMusicPreviewURL\x12J\n" +
+	" linkMusicPreviewCountriesAllowed\x18\x06 \x03(\tR linkMusicPreviewCountriesAllowed\x12X\n" +
+	"\x14linkPreviewThumbnail\x18\a \x01(\v2$.InstamadilloCoreTypeMedia.ThumbnailR\x14linkPreviewThumbnail\x12(\n" +
+	"\x0flinkPreviewBody\x18\b \x01(\tR\x0flinkPreviewBody\"J\n" +
+	"\bImageUrl\x12\x10\n" +
+	"\x03URL\x18\x01 \x01(\tR\x03URL\x12\x14\n" +
+	"\x05width\x18\x02 \x01(\x05R\x05width\x12\x16\n" +
+	"\x06height\x18\x03 \x01(\x05R\x06heightB4Z2go.mau.fi/whatsmeow/proto/instamadilloCoreTypeLink"
+
+var (
+	file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescOnce sync.Once
+	file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescData []byte
+)
+
+func file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescGZIP() []byte {
+	file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescOnce.Do(func() {
+		file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDesc), len(file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDesc)))
+	})
+	return file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDescData
+}
+
+var file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_goTypes = []any{
+	(*Link)(nil),        // 0: InstamadilloCoreTypeLink.Link
+	(*LinkContext)(nil), // 1: InstamadilloCoreTypeLink.LinkContext
+	(*ImageUrl)(nil),    // 2: InstamadilloCoreTypeLink.ImageUrl
+	(*instamadilloCoreTypeMedia.Thumbnail)(nil), // 3: InstamadilloCoreTypeMedia.Thumbnail
+}
+var file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_depIdxs = []int32{
+	1, // 0: InstamadilloCoreTypeLink.Link.linkContext:type_name -> InstamadilloCoreTypeLink.LinkContext
+	2, // 1: InstamadilloCoreTypeLink.LinkContext.linkImageURL:type_name -> InstamadilloCoreTypeLink.ImageUrl
+	3, // 2: InstamadilloCoreTypeLink.LinkContext.linkPreviewThumbnail:type_name -> InstamadilloCoreTypeMedia.Thumbnail
+	3, // [3:3] is the sub-list for method output_type
+	3, // [3:3] is the sub-list for method input_type
+	3, // [3:3] is the sub-list for extension type_name
+	3, // [3:3] is the sub-list for extension extendee
+	0, // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_init() }
+func file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_init() {
+	if File_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDesc), len(file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_goTypes,
+		DependencyIndexes: file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_depIdxs,
+		MessageInfos:      file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_msgTypes,
+	}.Build()
+	File_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto = out.File
+	file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_goTypes = nil
+	file_instamadilloCoreTypeLink_InstamadilloCoreTypeLink_proto_depIdxs = nil
+}

+ 27 - 0
proto/instamadilloCoreTypeLink/InstamadilloCoreTypeLink.proto

@@ -0,0 +1,27 @@
+syntax = "proto2";
+package InstamadilloCoreTypeLink;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeLink";
+
+import "instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto";
+
+message Link {
+	optional string text = 1;
+	optional LinkContext linkContext = 2;
+}
+
+message LinkContext {
+	optional ImageUrl linkImageURL = 1;
+	optional string linkPreviewTitle = 2;
+	optional string linkURL = 3;
+	optional string linkSummary = 4;
+	optional string linkMusicPreviewURL = 5;
+	repeated string linkMusicPreviewCountriesAllowed = 6;
+	optional InstamadilloCoreTypeMedia.Thumbnail linkPreviewThumbnail = 7;
+	optional string linkPreviewBody = 8;
+}
+
+message ImageUrl {
+	optional string URL = 1;
+	optional int32 width = 2;
+	optional int32 height = 3;
+}

+ 1299 - 0
proto/instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.pb.go

@@ -0,0 +1,1299 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto
+
+package instamadilloCoreTypeMedia
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type PjpegScanConfiguration int32
+
+const (
+	PjpegScanConfiguration_PJPEG_SCAN_CONFIGURATION_UNSPECIFIED PjpegScanConfiguration = 0
+	PjpegScanConfiguration_PJPEG_SCAN_CONFIGURATION_WA          PjpegScanConfiguration = 1
+	PjpegScanConfiguration_PJPEG_SCAN_CONFIGURATION_E15         PjpegScanConfiguration = 2
+	PjpegScanConfiguration_PJPEG_SCAN_CONFIGURATION_E35         PjpegScanConfiguration = 3
+)
+
+// Enum value maps for PjpegScanConfiguration.
+var (
+	PjpegScanConfiguration_name = map[int32]string{
+		0: "PJPEG_SCAN_CONFIGURATION_UNSPECIFIED",
+		1: "PJPEG_SCAN_CONFIGURATION_WA",
+		2: "PJPEG_SCAN_CONFIGURATION_E15",
+		3: "PJPEG_SCAN_CONFIGURATION_E35",
+	}
+	PjpegScanConfiguration_value = map[string]int32{
+		"PJPEG_SCAN_CONFIGURATION_UNSPECIFIED": 0,
+		"PJPEG_SCAN_CONFIGURATION_WA":          1,
+		"PJPEG_SCAN_CONFIGURATION_E15":         2,
+		"PJPEG_SCAN_CONFIGURATION_E35":         3,
+	}
+)
+
+func (x PjpegScanConfiguration) Enum() *PjpegScanConfiguration {
+	p := new(PjpegScanConfiguration)
+	*p = x
+	return p
+}
+
+func (x PjpegScanConfiguration) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (PjpegScanConfiguration) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes[0].Descriptor()
+}
+
+func (PjpegScanConfiguration) Type() protoreflect.EnumType {
+	return &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes[0]
+}
+
+func (x PjpegScanConfiguration) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *PjpegScanConfiguration) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = PjpegScanConfiguration(num)
+	return nil
+}
+
+// Deprecated: Use PjpegScanConfiguration.Descriptor instead.
+func (PjpegScanConfiguration) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{0}
+}
+
+type Media_InterventionType int32
+
+const (
+	Media_UNSET Media_InterventionType = 0
+	Media_NONE  Media_InterventionType = 1
+	Media_NUDE  Media_InterventionType = 2
+)
+
+// Enum value maps for Media_InterventionType.
+var (
+	Media_InterventionType_name = map[int32]string{
+		0: "UNSET",
+		1: "NONE",
+		2: "NUDE",
+	}
+	Media_InterventionType_value = map[string]int32{
+		"UNSET": 0,
+		"NONE":  1,
+		"NUDE":  2,
+	}
+)
+
+func (x Media_InterventionType) Enum() *Media_InterventionType {
+	p := new(Media_InterventionType)
+	*p = x
+	return p
+}
+
+func (x Media_InterventionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Media_InterventionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes[1].Descriptor()
+}
+
+func (Media_InterventionType) Type() protoreflect.EnumType {
+	return &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes[1]
+}
+
+func (x Media_InterventionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Media_InterventionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Media_InterventionType(num)
+	return nil
+}
+
+// Deprecated: Use Media_InterventionType.Descriptor instead.
+func (Media_InterventionType) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{0, 0}
+}
+
+type Raven_ViewMode int32
+
+const (
+	Raven_RAVEN_VIEW_MODEL_UNSPECIFIED Raven_ViewMode = 0
+	Raven_RAVEN_VIEW_MODEL_ONCE        Raven_ViewMode = 1
+	Raven_RAVEN_VIEW_MODEL_REPLAYABLE  Raven_ViewMode = 2
+	Raven_RAVEN_VIEW_MODEL_PERMANENT   Raven_ViewMode = 3
+)
+
+// Enum value maps for Raven_ViewMode.
+var (
+	Raven_ViewMode_name = map[int32]string{
+		0: "RAVEN_VIEW_MODEL_UNSPECIFIED",
+		1: "RAVEN_VIEW_MODEL_ONCE",
+		2: "RAVEN_VIEW_MODEL_REPLAYABLE",
+		3: "RAVEN_VIEW_MODEL_PERMANENT",
+	}
+	Raven_ViewMode_value = map[string]int32{
+		"RAVEN_VIEW_MODEL_UNSPECIFIED": 0,
+		"RAVEN_VIEW_MODEL_ONCE":        1,
+		"RAVEN_VIEW_MODEL_REPLAYABLE":  2,
+		"RAVEN_VIEW_MODEL_PERMANENT":   3,
+	}
+)
+
+func (x Raven_ViewMode) Enum() *Raven_ViewMode {
+	p := new(Raven_ViewMode)
+	*p = x
+	return p
+}
+
+func (x Raven_ViewMode) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Raven_ViewMode) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes[2].Descriptor()
+}
+
+func (Raven_ViewMode) Type() protoreflect.EnumType {
+	return &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes[2]
+}
+
+func (x Raven_ViewMode) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Raven_ViewMode) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Raven_ViewMode(num)
+	return nil
+}
+
+// Deprecated: Use Raven_ViewMode.Descriptor instead.
+func (Raven_ViewMode) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{6, 0}
+}
+
+type Media struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to Media:
+	//
+	//	*Media_StaticPhoto
+	//	*Media_Voice
+	//	*Media_Video
+	//	*Media_Raven
+	//	*Media_Gif
+	//	*Media_AvatarSticker
+	Media         isMedia_Media `protobuf_oneof:"media"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Media) Reset() {
+	*x = Media{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Media) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Media) ProtoMessage() {}
+
+func (x *Media) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Media.ProtoReflect.Descriptor instead.
+func (*Media) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Media) GetMedia() isMedia_Media {
+	if x != nil {
+		return x.Media
+	}
+	return nil
+}
+
+func (x *Media) GetStaticPhoto() *StaticPhoto {
+	if x != nil {
+		if x, ok := x.Media.(*Media_StaticPhoto); ok {
+			return x.StaticPhoto
+		}
+	}
+	return nil
+}
+
+func (x *Media) GetVoice() *Voice {
+	if x != nil {
+		if x, ok := x.Media.(*Media_Voice); ok {
+			return x.Voice
+		}
+	}
+	return nil
+}
+
+func (x *Media) GetVideo() *Video {
+	if x != nil {
+		if x, ok := x.Media.(*Media_Video); ok {
+			return x.Video
+		}
+	}
+	return nil
+}
+
+func (x *Media) GetRaven() *Raven {
+	if x != nil {
+		if x, ok := x.Media.(*Media_Raven); ok {
+			return x.Raven
+		}
+	}
+	return nil
+}
+
+func (x *Media) GetGif() *Gif {
+	if x != nil {
+		if x, ok := x.Media.(*Media_Gif); ok {
+			return x.Gif
+		}
+	}
+	return nil
+}
+
+func (x *Media) GetAvatarSticker() *AvatarSticker {
+	if x != nil {
+		if x, ok := x.Media.(*Media_AvatarSticker); ok {
+			return x.AvatarSticker
+		}
+	}
+	return nil
+}
+
+type isMedia_Media interface {
+	isMedia_Media()
+}
+
+type Media_StaticPhoto struct {
+	StaticPhoto *StaticPhoto `protobuf:"bytes,1,opt,name=staticPhoto,oneof"`
+}
+
+type Media_Voice struct {
+	Voice *Voice `protobuf:"bytes,2,opt,name=voice,oneof"`
+}
+
+type Media_Video struct {
+	Video *Video `protobuf:"bytes,3,opt,name=video,oneof"`
+}
+
+type Media_Raven struct {
+	Raven *Raven `protobuf:"bytes,4,opt,name=raven,oneof"`
+}
+
+type Media_Gif struct {
+	Gif *Gif `protobuf:"bytes,5,opt,name=gif,oneof"`
+}
+
+type Media_AvatarSticker struct {
+	AvatarSticker *AvatarSticker `protobuf:"bytes,6,opt,name=avatarSticker,oneof"`
+}
+
+func (*Media_StaticPhoto) isMedia_Media() {}
+
+func (*Media_Voice) isMedia_Media() {}
+
+func (*Media_Video) isMedia_Media() {}
+
+func (*Media_Raven) isMedia_Media() {}
+
+func (*Media_Gif) isMedia_Media() {}
+
+func (*Media_AvatarSticker) isMedia_Media() {}
+
+type StaticPhoto struct {
+	state                  protoimpl.MessageState  `protogen:"open.v1"`
+	MediaTransport         *CommonMediaTransport   `protobuf:"bytes,1,opt,name=mediaTransport" json:"mediaTransport,omitempty"`
+	Height                 *int32                  `protobuf:"varint,2,opt,name=height" json:"height,omitempty"`
+	Width                  *int32                  `protobuf:"varint,3,opt,name=width" json:"width,omitempty"`
+	ScanLengths            []int32                 `protobuf:"varint,4,rep,packed,name=scanLengths" json:"scanLengths,omitempty"`
+	Thumbnail              *Thumbnail              `protobuf:"bytes,5,opt,name=thumbnail" json:"thumbnail,omitempty"`
+	PjpegScanConfiguration *PjpegScanConfiguration `protobuf:"varint,6,opt,name=pjpegScanConfiguration,enum=InstamadilloCoreTypeMedia.PjpegScanConfiguration" json:"pjpegScanConfiguration,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *StaticPhoto) Reset() {
+	*x = StaticPhoto{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *StaticPhoto) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StaticPhoto) ProtoMessage() {}
+
+func (x *StaticPhoto) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use StaticPhoto.ProtoReflect.Descriptor instead.
+func (*StaticPhoto) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *StaticPhoto) GetMediaTransport() *CommonMediaTransport {
+	if x != nil {
+		return x.MediaTransport
+	}
+	return nil
+}
+
+func (x *StaticPhoto) GetHeight() int32 {
+	if x != nil && x.Height != nil {
+		return *x.Height
+	}
+	return 0
+}
+
+func (x *StaticPhoto) GetWidth() int32 {
+	if x != nil && x.Width != nil {
+		return *x.Width
+	}
+	return 0
+}
+
+func (x *StaticPhoto) GetScanLengths() []int32 {
+	if x != nil {
+		return x.ScanLengths
+	}
+	return nil
+}
+
+func (x *StaticPhoto) GetThumbnail() *Thumbnail {
+	if x != nil {
+		return x.Thumbnail
+	}
+	return nil
+}
+
+func (x *StaticPhoto) GetPjpegScanConfiguration() PjpegScanConfiguration {
+	if x != nil && x.PjpegScanConfiguration != nil {
+		return *x.PjpegScanConfiguration
+	}
+	return PjpegScanConfiguration_PJPEG_SCAN_CONFIGURATION_UNSPECIFIED
+}
+
+type Voice struct {
+	state                       protoimpl.MessageState `protogen:"open.v1"`
+	MediaTransport              *CommonMediaTransport  `protobuf:"bytes,1,opt,name=mediaTransport" json:"mediaTransport,omitempty"`
+	Duration                    *int32                 `protobuf:"varint,2,opt,name=duration" json:"duration,omitempty"`
+	Waveforms                   []float32              `protobuf:"fixed32,3,rep,packed,name=waveforms" json:"waveforms,omitempty"`
+	WaveformSamplingFrequencyHz *int32                 `protobuf:"varint,4,opt,name=waveformSamplingFrequencyHz" json:"waveformSamplingFrequencyHz,omitempty"`
+	unknownFields               protoimpl.UnknownFields
+	sizeCache                   protoimpl.SizeCache
+}
+
+func (x *Voice) Reset() {
+	*x = Voice{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Voice) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Voice) ProtoMessage() {}
+
+func (x *Voice) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Voice.ProtoReflect.Descriptor instead.
+func (*Voice) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *Voice) GetMediaTransport() *CommonMediaTransport {
+	if x != nil {
+		return x.MediaTransport
+	}
+	return nil
+}
+
+func (x *Voice) GetDuration() int32 {
+	if x != nil && x.Duration != nil {
+		return *x.Duration
+	}
+	return 0
+}
+
+func (x *Voice) GetWaveforms() []float32 {
+	if x != nil {
+		return x.Waveforms
+	}
+	return nil
+}
+
+func (x *Voice) GetWaveformSamplingFrequencyHz() int32 {
+	if x != nil && x.WaveformSamplingFrequencyHz != nil {
+		return *x.WaveformSamplingFrequencyHz
+	}
+	return 0
+}
+
+type Video struct {
+	state              protoimpl.MessageState `protogen:"open.v1"`
+	MediaTransport     *CommonMediaTransport  `protobuf:"bytes,1,opt,name=mediaTransport" json:"mediaTransport,omitempty"`
+	Height             *int32                 `protobuf:"varint,2,opt,name=height" json:"height,omitempty"`
+	Width              *int32                 `protobuf:"varint,3,opt,name=width" json:"width,omitempty"`
+	Thumbnail          *Thumbnail             `protobuf:"bytes,4,opt,name=thumbnail" json:"thumbnail,omitempty"`
+	VideoExtraMetadata *VideoExtraMetadata    `protobuf:"bytes,5,opt,name=videoExtraMetadata" json:"videoExtraMetadata,omitempty"`
+	unknownFields      protoimpl.UnknownFields
+	sizeCache          protoimpl.SizeCache
+}
+
+func (x *Video) Reset() {
+	*x = Video{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Video) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Video) ProtoMessage() {}
+
+func (x *Video) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Video.ProtoReflect.Descriptor instead.
+func (*Video) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Video) GetMediaTransport() *CommonMediaTransport {
+	if x != nil {
+		return x.MediaTransport
+	}
+	return nil
+}
+
+func (x *Video) GetHeight() int32 {
+	if x != nil && x.Height != nil {
+		return *x.Height
+	}
+	return 0
+}
+
+func (x *Video) GetWidth() int32 {
+	if x != nil && x.Width != nil {
+		return *x.Width
+	}
+	return 0
+}
+
+func (x *Video) GetThumbnail() *Thumbnail {
+	if x != nil {
+		return x.Thumbnail
+	}
+	return nil
+}
+
+func (x *Video) GetVideoExtraMetadata() *VideoExtraMetadata {
+	if x != nil {
+		return x.VideoExtraMetadata
+	}
+	return nil
+}
+
+type Gif struct {
+	state          protoimpl.MessageState `protogen:"open.v1"`
+	MediaTransport *CommonMediaTransport  `protobuf:"bytes,1,opt,name=mediaTransport" json:"mediaTransport,omitempty"`
+	Height         *int32                 `protobuf:"varint,2,opt,name=height" json:"height,omitempty"`
+	Width          *int32                 `protobuf:"varint,3,opt,name=width" json:"width,omitempty"`
+	IsSticker      *bool                  `protobuf:"varint,4,opt,name=isSticker" json:"isSticker,omitempty"`
+	StickerID      *string                `protobuf:"bytes,5,opt,name=stickerID" json:"stickerID,omitempty"`
+	GifURL         *string                `protobuf:"bytes,6,opt,name=gifURL" json:"gifURL,omitempty"`
+	GifSize        *int32                 `protobuf:"varint,7,opt,name=gifSize" json:"gifSize,omitempty"`
+	IsRandom       *bool                  `protobuf:"varint,8,opt,name=isRandom" json:"isRandom,omitempty"`
+	unknownFields  protoimpl.UnknownFields
+	sizeCache      protoimpl.SizeCache
+}
+
+func (x *Gif) Reset() {
+	*x = Gif{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Gif) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Gif) ProtoMessage() {}
+
+func (x *Gif) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Gif.ProtoReflect.Descriptor instead.
+func (*Gif) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *Gif) GetMediaTransport() *CommonMediaTransport {
+	if x != nil {
+		return x.MediaTransport
+	}
+	return nil
+}
+
+func (x *Gif) GetHeight() int32 {
+	if x != nil && x.Height != nil {
+		return *x.Height
+	}
+	return 0
+}
+
+func (x *Gif) GetWidth() int32 {
+	if x != nil && x.Width != nil {
+		return *x.Width
+	}
+	return 0
+}
+
+func (x *Gif) GetIsSticker() bool {
+	if x != nil && x.IsSticker != nil {
+		return *x.IsSticker
+	}
+	return false
+}
+
+func (x *Gif) GetStickerID() string {
+	if x != nil && x.StickerID != nil {
+		return *x.StickerID
+	}
+	return ""
+}
+
+func (x *Gif) GetGifURL() string {
+	if x != nil && x.GifURL != nil {
+		return *x.GifURL
+	}
+	return ""
+}
+
+func (x *Gif) GetGifSize() int32 {
+	if x != nil && x.GifSize != nil {
+		return *x.GifSize
+	}
+	return 0
+}
+
+func (x *Gif) GetIsRandom() bool {
+	if x != nil && x.IsRandom != nil {
+		return *x.IsRandom
+	}
+	return false
+}
+
+type AvatarSticker struct {
+	state           protoimpl.MessageState `protogen:"open.v1"`
+	MediaTransport  *CommonMediaTransport  `protobuf:"bytes,1,opt,name=mediaTransport" json:"mediaTransport,omitempty"`
+	IsAnimated      *bool                  `protobuf:"varint,2,opt,name=isAnimated" json:"isAnimated,omitempty"`
+	StickerID       *string                `protobuf:"bytes,3,opt,name=stickerID" json:"stickerID,omitempty"`
+	StickerTemplate *string                `protobuf:"bytes,4,opt,name=stickerTemplate" json:"stickerTemplate,omitempty"`
+	NuxType         *int32                 `protobuf:"varint,5,opt,name=nuxType" json:"nuxType,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *AvatarSticker) Reset() {
+	*x = AvatarSticker{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AvatarSticker) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AvatarSticker) ProtoMessage() {}
+
+func (x *AvatarSticker) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AvatarSticker.ProtoReflect.Descriptor instead.
+func (*AvatarSticker) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *AvatarSticker) GetMediaTransport() *CommonMediaTransport {
+	if x != nil {
+		return x.MediaTransport
+	}
+	return nil
+}
+
+func (x *AvatarSticker) GetIsAnimated() bool {
+	if x != nil && x.IsAnimated != nil {
+		return *x.IsAnimated
+	}
+	return false
+}
+
+func (x *AvatarSticker) GetStickerID() string {
+	if x != nil && x.StickerID != nil {
+		return *x.StickerID
+	}
+	return ""
+}
+
+func (x *AvatarSticker) GetStickerTemplate() string {
+	if x != nil && x.StickerTemplate != nil {
+		return *x.StickerTemplate
+	}
+	return ""
+}
+
+func (x *AvatarSticker) GetNuxType() int32 {
+	if x != nil && x.NuxType != nil {
+		return *x.NuxType
+	}
+	return 0
+}
+
+type Raven struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	ViewMode      *Raven_ViewMode        `protobuf:"varint,1,opt,name=viewMode,enum=InstamadilloCoreTypeMedia.Raven_ViewMode" json:"viewMode,omitempty"`
+	Content       *RavenContent          `protobuf:"bytes,2,opt,name=content" json:"content,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Raven) Reset() {
+	*x = Raven{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Raven) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Raven) ProtoMessage() {}
+
+func (x *Raven) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Raven.ProtoReflect.Descriptor instead.
+func (*Raven) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *Raven) GetViewMode() Raven_ViewMode {
+	if x != nil && x.ViewMode != nil {
+		return *x.ViewMode
+	}
+	return Raven_RAVEN_VIEW_MODEL_UNSPECIFIED
+}
+
+func (x *Raven) GetContent() *RavenContent {
+	if x != nil {
+		return x.Content
+	}
+	return nil
+}
+
+type RavenContent struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to RavenContent:
+	//
+	//	*RavenContent_StaticPhoto
+	//	*RavenContent_Video
+	RavenContent  isRavenContent_RavenContent `protobuf_oneof:"ravenContent"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *RavenContent) Reset() {
+	*x = RavenContent{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *RavenContent) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RavenContent) ProtoMessage() {}
+
+func (x *RavenContent) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use RavenContent.ProtoReflect.Descriptor instead.
+func (*RavenContent) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *RavenContent) GetRavenContent() isRavenContent_RavenContent {
+	if x != nil {
+		return x.RavenContent
+	}
+	return nil
+}
+
+func (x *RavenContent) GetStaticPhoto() *StaticPhoto {
+	if x != nil {
+		if x, ok := x.RavenContent.(*RavenContent_StaticPhoto); ok {
+			return x.StaticPhoto
+		}
+	}
+	return nil
+}
+
+func (x *RavenContent) GetVideo() *Video {
+	if x != nil {
+		if x, ok := x.RavenContent.(*RavenContent_Video); ok {
+			return x.Video
+		}
+	}
+	return nil
+}
+
+type isRavenContent_RavenContent interface {
+	isRavenContent_RavenContent()
+}
+
+type RavenContent_StaticPhoto struct {
+	StaticPhoto *StaticPhoto `protobuf:"bytes,1,opt,name=staticPhoto,oneof"`
+}
+
+type RavenContent_Video struct {
+	Video *Video `protobuf:"bytes,2,opt,name=video,oneof"`
+}
+
+func (*RavenContent_StaticPhoto) isRavenContent_RavenContent() {}
+
+func (*RavenContent_Video) isRavenContent_RavenContent() {}
+
+type Thumbnail struct {
+	state          protoimpl.MessageState `protogen:"open.v1"`
+	MediaTransport *CommonMediaTransport  `protobuf:"bytes,1,opt,name=mediaTransport" json:"mediaTransport,omitempty"`
+	Height         *int32                 `protobuf:"varint,2,opt,name=height" json:"height,omitempty"`
+	Width          *int32                 `protobuf:"varint,3,opt,name=width" json:"width,omitempty"`
+	unknownFields  protoimpl.UnknownFields
+	sizeCache      protoimpl.SizeCache
+}
+
+func (x *Thumbnail) Reset() {
+	*x = Thumbnail{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Thumbnail) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Thumbnail) ProtoMessage() {}
+
+func (x *Thumbnail) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Thumbnail.ProtoReflect.Descriptor instead.
+func (*Thumbnail) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *Thumbnail) GetMediaTransport() *CommonMediaTransport {
+	if x != nil {
+		return x.MediaTransport
+	}
+	return nil
+}
+
+func (x *Thumbnail) GetHeight() int32 {
+	if x != nil && x.Height != nil {
+		return *x.Height
+	}
+	return 0
+}
+
+func (x *Thumbnail) GetWidth() int32 {
+	if x != nil && x.Width != nil {
+		return *x.Width
+	}
+	return 0
+}
+
+type CommonMediaTransport struct {
+	state             protoimpl.MessageState `protogen:"open.v1"`
+	MediaID           *string                `protobuf:"bytes,1,opt,name=mediaID" json:"mediaID,omitempty"`
+	FileSHA256        *string                `protobuf:"bytes,2,opt,name=fileSHA256" json:"fileSHA256,omitempty"`
+	MediaKey          *string                `protobuf:"bytes,3,opt,name=mediaKey" json:"mediaKey,omitempty"`
+	FileEncSHA256     *string                `protobuf:"bytes,4,opt,name=fileEncSHA256" json:"fileEncSHA256,omitempty"`
+	DirectPath        *string                `protobuf:"bytes,5,opt,name=directPath" json:"directPath,omitempty"`
+	MediaKeyTimestamp *string                `protobuf:"bytes,6,opt,name=mediaKeyTimestamp" json:"mediaKeyTimestamp,omitempty"`
+	Sidecar           *string                `protobuf:"bytes,7,opt,name=sidecar" json:"sidecar,omitempty"`
+	FileLength        *int32                 `protobuf:"varint,8,opt,name=fileLength" json:"fileLength,omitempty"`
+	Mimetype          *string                `protobuf:"bytes,9,opt,name=mimetype" json:"mimetype,omitempty"`
+	ObjectID          *string                `protobuf:"bytes,10,opt,name=objectID" json:"objectID,omitempty"`
+	unknownFields     protoimpl.UnknownFields
+	sizeCache         protoimpl.SizeCache
+}
+
+func (x *CommonMediaTransport) Reset() {
+	*x = CommonMediaTransport{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *CommonMediaTransport) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CommonMediaTransport) ProtoMessage() {}
+
+func (x *CommonMediaTransport) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CommonMediaTransport.ProtoReflect.Descriptor instead.
+func (*CommonMediaTransport) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *CommonMediaTransport) GetMediaID() string {
+	if x != nil && x.MediaID != nil {
+		return *x.MediaID
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetFileSHA256() string {
+	if x != nil && x.FileSHA256 != nil {
+		return *x.FileSHA256
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetMediaKey() string {
+	if x != nil && x.MediaKey != nil {
+		return *x.MediaKey
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetFileEncSHA256() string {
+	if x != nil && x.FileEncSHA256 != nil {
+		return *x.FileEncSHA256
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetDirectPath() string {
+	if x != nil && x.DirectPath != nil {
+		return *x.DirectPath
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetMediaKeyTimestamp() string {
+	if x != nil && x.MediaKeyTimestamp != nil {
+		return *x.MediaKeyTimestamp
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetSidecar() string {
+	if x != nil && x.Sidecar != nil {
+		return *x.Sidecar
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetFileLength() int32 {
+	if x != nil && x.FileLength != nil {
+		return *x.FileLength
+	}
+	return 0
+}
+
+func (x *CommonMediaTransport) GetMimetype() string {
+	if x != nil && x.Mimetype != nil {
+		return *x.Mimetype
+	}
+	return ""
+}
+
+func (x *CommonMediaTransport) GetObjectID() string {
+	if x != nil && x.ObjectID != nil {
+		return *x.ObjectID
+	}
+	return ""
+}
+
+type VideoExtraMetadata struct {
+	state                protoimpl.MessageState `protogen:"open.v1"`
+	UploadMosClientScore *float32               `protobuf:"fixed32,1,opt,name=uploadMosClientScore" json:"uploadMosClientScore,omitempty"`
+	unknownFields        protoimpl.UnknownFields
+	sizeCache            protoimpl.SizeCache
+}
+
+func (x *VideoExtraMetadata) Reset() {
+	*x = VideoExtraMetadata{}
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *VideoExtraMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*VideoExtraMetadata) ProtoMessage() {}
+
+func (x *VideoExtraMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use VideoExtraMetadata.ProtoReflect.Descriptor instead.
+func (*VideoExtraMetadata) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *VideoExtraMetadata) GetUploadMosClientScore() float32 {
+	if x != nil && x.UploadMosClientScore != nil {
+		return *x.UploadMosClientScore
+	}
+	return 0
+}
+
+var File_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto protoreflect.FileDescriptor
+
+const file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDesc = "" +
+	"\n" +
+	"9instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto\x12\x19InstamadilloCoreTypeMedia\"\xc3\x03\n" +
+	"\x05Media\x12J\n" +
+	"\vstaticPhoto\x18\x01 \x01(\v2&.InstamadilloCoreTypeMedia.StaticPhotoH\x00R\vstaticPhoto\x128\n" +
+	"\x05voice\x18\x02 \x01(\v2 .InstamadilloCoreTypeMedia.VoiceH\x00R\x05voice\x128\n" +
+	"\x05video\x18\x03 \x01(\v2 .InstamadilloCoreTypeMedia.VideoH\x00R\x05video\x128\n" +
+	"\x05raven\x18\x04 \x01(\v2 .InstamadilloCoreTypeMedia.RavenH\x00R\x05raven\x122\n" +
+	"\x03gif\x18\x05 \x01(\v2\x1e.InstamadilloCoreTypeMedia.GifH\x00R\x03gif\x12P\n" +
+	"\ravatarSticker\x18\x06 \x01(\v2(.InstamadilloCoreTypeMedia.AvatarStickerH\x00R\ravatarSticker\"1\n" +
+	"\x10InterventionType\x12\t\n" +
+	"\x05UNSET\x10\x00\x12\b\n" +
+	"\x04NONE\x10\x01\x12\b\n" +
+	"\x04NUDE\x10\x02B\a\n" +
+	"\x05media\"\xe9\x02\n" +
+	"\vStaticPhoto\x12W\n" +
+	"\x0emediaTransport\x18\x01 \x01(\v2/.InstamadilloCoreTypeMedia.CommonMediaTransportR\x0emediaTransport\x12\x16\n" +
+	"\x06height\x18\x02 \x01(\x05R\x06height\x12\x14\n" +
+	"\x05width\x18\x03 \x01(\x05R\x05width\x12$\n" +
+	"\vscanLengths\x18\x04 \x03(\x05B\x02\x10\x01R\vscanLengths\x12B\n" +
+	"\tthumbnail\x18\x05 \x01(\v2$.InstamadilloCoreTypeMedia.ThumbnailR\tthumbnail\x12i\n" +
+	"\x16pjpegScanConfiguration\x18\x06 \x01(\x0e21.InstamadilloCoreTypeMedia.PjpegScanConfigurationR\x16pjpegScanConfiguration\"\xe0\x01\n" +
+	"\x05Voice\x12W\n" +
+	"\x0emediaTransport\x18\x01 \x01(\v2/.InstamadilloCoreTypeMedia.CommonMediaTransportR\x0emediaTransport\x12\x1a\n" +
+	"\bduration\x18\x02 \x01(\x05R\bduration\x12 \n" +
+	"\twaveforms\x18\x03 \x03(\x02B\x02\x10\x01R\twaveforms\x12@\n" +
+	"\x1bwaveformSamplingFrequencyHz\x18\x04 \x01(\x05R\x1bwaveformSamplingFrequencyHz\"\xb1\x02\n" +
+	"\x05Video\x12W\n" +
+	"\x0emediaTransport\x18\x01 \x01(\v2/.InstamadilloCoreTypeMedia.CommonMediaTransportR\x0emediaTransport\x12\x16\n" +
+	"\x06height\x18\x02 \x01(\x05R\x06height\x12\x14\n" +
+	"\x05width\x18\x03 \x01(\x05R\x05width\x12B\n" +
+	"\tthumbnail\x18\x04 \x01(\v2$.InstamadilloCoreTypeMedia.ThumbnailR\tthumbnail\x12]\n" +
+	"\x12videoExtraMetadata\x18\x05 \x01(\v2-.InstamadilloCoreTypeMedia.VideoExtraMetadataR\x12videoExtraMetadata\"\x96\x02\n" +
+	"\x03Gif\x12W\n" +
+	"\x0emediaTransport\x18\x01 \x01(\v2/.InstamadilloCoreTypeMedia.CommonMediaTransportR\x0emediaTransport\x12\x16\n" +
+	"\x06height\x18\x02 \x01(\x05R\x06height\x12\x14\n" +
+	"\x05width\x18\x03 \x01(\x05R\x05width\x12\x1c\n" +
+	"\tisSticker\x18\x04 \x01(\bR\tisSticker\x12\x1c\n" +
+	"\tstickerID\x18\x05 \x01(\tR\tstickerID\x12\x16\n" +
+	"\x06gifURL\x18\x06 \x01(\tR\x06gifURL\x12\x18\n" +
+	"\agifSize\x18\a \x01(\x05R\agifSize\x12\x1a\n" +
+	"\bisRandom\x18\b \x01(\bR\bisRandom\"\xea\x01\n" +
+	"\rAvatarSticker\x12W\n" +
+	"\x0emediaTransport\x18\x01 \x01(\v2/.InstamadilloCoreTypeMedia.CommonMediaTransportR\x0emediaTransport\x12\x1e\n" +
+	"\n" +
+	"isAnimated\x18\x02 \x01(\bR\n" +
+	"isAnimated\x12\x1c\n" +
+	"\tstickerID\x18\x03 \x01(\tR\tstickerID\x12(\n" +
+	"\x0fstickerTemplate\x18\x04 \x01(\tR\x0fstickerTemplate\x12\x18\n" +
+	"\anuxType\x18\x05 \x01(\x05R\anuxType\"\x9c\x02\n" +
+	"\x05Raven\x12E\n" +
+	"\bviewMode\x18\x01 \x01(\x0e2).InstamadilloCoreTypeMedia.Raven.ViewModeR\bviewMode\x12A\n" +
+	"\acontent\x18\x02 \x01(\v2'.InstamadilloCoreTypeMedia.RavenContentR\acontent\"\x88\x01\n" +
+	"\bViewMode\x12 \n" +
+	"\x1cRAVEN_VIEW_MODEL_UNSPECIFIED\x10\x00\x12\x19\n" +
+	"\x15RAVEN_VIEW_MODEL_ONCE\x10\x01\x12\x1f\n" +
+	"\x1bRAVEN_VIEW_MODEL_REPLAYABLE\x10\x02\x12\x1e\n" +
+	"\x1aRAVEN_VIEW_MODEL_PERMANENT\x10\x03\"\xa4\x01\n" +
+	"\fRavenContent\x12J\n" +
+	"\vstaticPhoto\x18\x01 \x01(\v2&.InstamadilloCoreTypeMedia.StaticPhotoH\x00R\vstaticPhoto\x128\n" +
+	"\x05video\x18\x02 \x01(\v2 .InstamadilloCoreTypeMedia.VideoH\x00R\x05videoB\x0e\n" +
+	"\fravenContent\"\x92\x01\n" +
+	"\tThumbnail\x12W\n" +
+	"\x0emediaTransport\x18\x01 \x01(\v2/.InstamadilloCoreTypeMedia.CommonMediaTransportR\x0emediaTransport\x12\x16\n" +
+	"\x06height\x18\x02 \x01(\x05R\x06height\x12\x14\n" +
+	"\x05width\x18\x03 \x01(\x05R\x05width\"\xd2\x02\n" +
+	"\x14CommonMediaTransport\x12\x18\n" +
+	"\amediaID\x18\x01 \x01(\tR\amediaID\x12\x1e\n" +
+	"\n" +
+	"fileSHA256\x18\x02 \x01(\tR\n" +
+	"fileSHA256\x12\x1a\n" +
+	"\bmediaKey\x18\x03 \x01(\tR\bmediaKey\x12$\n" +
+	"\rfileEncSHA256\x18\x04 \x01(\tR\rfileEncSHA256\x12\x1e\n" +
+	"\n" +
+	"directPath\x18\x05 \x01(\tR\n" +
+	"directPath\x12,\n" +
+	"\x11mediaKeyTimestamp\x18\x06 \x01(\tR\x11mediaKeyTimestamp\x12\x18\n" +
+	"\asidecar\x18\a \x01(\tR\asidecar\x12\x1e\n" +
+	"\n" +
+	"fileLength\x18\b \x01(\x05R\n" +
+	"fileLength\x12\x1a\n" +
+	"\bmimetype\x18\t \x01(\tR\bmimetype\x12\x1a\n" +
+	"\bobjectID\x18\n" +
+	" \x01(\tR\bobjectID\"H\n" +
+	"\x12VideoExtraMetadata\x122\n" +
+	"\x14uploadMosClientScore\x18\x01 \x01(\x02R\x14uploadMosClientScore*\xa7\x01\n" +
+	"\x16PjpegScanConfiguration\x12(\n" +
+	"$PJPEG_SCAN_CONFIGURATION_UNSPECIFIED\x10\x00\x12\x1f\n" +
+	"\x1bPJPEG_SCAN_CONFIGURATION_WA\x10\x01\x12 \n" +
+	"\x1cPJPEG_SCAN_CONFIGURATION_E15\x10\x02\x12 \n" +
+	"\x1cPJPEG_SCAN_CONFIGURATION_E35\x10\x03B5Z3go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia"
+
+var (
+	file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescOnce sync.Once
+	file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescData []byte
+)
+
+func file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescGZIP() []byte {
+	file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescOnce.Do(func() {
+		file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDesc), len(file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDesc)))
+	})
+	return file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDescData
+}
+
+var file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
+var file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_goTypes = []any{
+	(PjpegScanConfiguration)(0),  // 0: InstamadilloCoreTypeMedia.PjpegScanConfiguration
+	(Media_InterventionType)(0),  // 1: InstamadilloCoreTypeMedia.Media.InterventionType
+	(Raven_ViewMode)(0),          // 2: InstamadilloCoreTypeMedia.Raven.ViewMode
+	(*Media)(nil),                // 3: InstamadilloCoreTypeMedia.Media
+	(*StaticPhoto)(nil),          // 4: InstamadilloCoreTypeMedia.StaticPhoto
+	(*Voice)(nil),                // 5: InstamadilloCoreTypeMedia.Voice
+	(*Video)(nil),                // 6: InstamadilloCoreTypeMedia.Video
+	(*Gif)(nil),                  // 7: InstamadilloCoreTypeMedia.Gif
+	(*AvatarSticker)(nil),        // 8: InstamadilloCoreTypeMedia.AvatarSticker
+	(*Raven)(nil),                // 9: InstamadilloCoreTypeMedia.Raven
+	(*RavenContent)(nil),         // 10: InstamadilloCoreTypeMedia.RavenContent
+	(*Thumbnail)(nil),            // 11: InstamadilloCoreTypeMedia.Thumbnail
+	(*CommonMediaTransport)(nil), // 12: InstamadilloCoreTypeMedia.CommonMediaTransport
+	(*VideoExtraMetadata)(nil),   // 13: InstamadilloCoreTypeMedia.VideoExtraMetadata
+}
+var file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_depIdxs = []int32{
+	4,  // 0: InstamadilloCoreTypeMedia.Media.staticPhoto:type_name -> InstamadilloCoreTypeMedia.StaticPhoto
+	5,  // 1: InstamadilloCoreTypeMedia.Media.voice:type_name -> InstamadilloCoreTypeMedia.Voice
+	6,  // 2: InstamadilloCoreTypeMedia.Media.video:type_name -> InstamadilloCoreTypeMedia.Video
+	9,  // 3: InstamadilloCoreTypeMedia.Media.raven:type_name -> InstamadilloCoreTypeMedia.Raven
+	7,  // 4: InstamadilloCoreTypeMedia.Media.gif:type_name -> InstamadilloCoreTypeMedia.Gif
+	8,  // 5: InstamadilloCoreTypeMedia.Media.avatarSticker:type_name -> InstamadilloCoreTypeMedia.AvatarSticker
+	12, // 6: InstamadilloCoreTypeMedia.StaticPhoto.mediaTransport:type_name -> InstamadilloCoreTypeMedia.CommonMediaTransport
+	11, // 7: InstamadilloCoreTypeMedia.StaticPhoto.thumbnail:type_name -> InstamadilloCoreTypeMedia.Thumbnail
+	0,  // 8: InstamadilloCoreTypeMedia.StaticPhoto.pjpegScanConfiguration:type_name -> InstamadilloCoreTypeMedia.PjpegScanConfiguration
+	12, // 9: InstamadilloCoreTypeMedia.Voice.mediaTransport:type_name -> InstamadilloCoreTypeMedia.CommonMediaTransport
+	12, // 10: InstamadilloCoreTypeMedia.Video.mediaTransport:type_name -> InstamadilloCoreTypeMedia.CommonMediaTransport
+	11, // 11: InstamadilloCoreTypeMedia.Video.thumbnail:type_name -> InstamadilloCoreTypeMedia.Thumbnail
+	13, // 12: InstamadilloCoreTypeMedia.Video.videoExtraMetadata:type_name -> InstamadilloCoreTypeMedia.VideoExtraMetadata
+	12, // 13: InstamadilloCoreTypeMedia.Gif.mediaTransport:type_name -> InstamadilloCoreTypeMedia.CommonMediaTransport
+	12, // 14: InstamadilloCoreTypeMedia.AvatarSticker.mediaTransport:type_name -> InstamadilloCoreTypeMedia.CommonMediaTransport
+	2,  // 15: InstamadilloCoreTypeMedia.Raven.viewMode:type_name -> InstamadilloCoreTypeMedia.Raven.ViewMode
+	10, // 16: InstamadilloCoreTypeMedia.Raven.content:type_name -> InstamadilloCoreTypeMedia.RavenContent
+	4,  // 17: InstamadilloCoreTypeMedia.RavenContent.staticPhoto:type_name -> InstamadilloCoreTypeMedia.StaticPhoto
+	6,  // 18: InstamadilloCoreTypeMedia.RavenContent.video:type_name -> InstamadilloCoreTypeMedia.Video
+	12, // 19: InstamadilloCoreTypeMedia.Thumbnail.mediaTransport:type_name -> InstamadilloCoreTypeMedia.CommonMediaTransport
+	20, // [20:20] is the sub-list for method output_type
+	20, // [20:20] is the sub-list for method input_type
+	20, // [20:20] is the sub-list for extension type_name
+	20, // [20:20] is the sub-list for extension extendee
+	0,  // [0:20] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_init() }
+func file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_init() {
+	if File_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto != nil {
+		return
+	}
+	file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[0].OneofWrappers = []any{
+		(*Media_StaticPhoto)(nil),
+		(*Media_Voice)(nil),
+		(*Media_Video)(nil),
+		(*Media_Raven)(nil),
+		(*Media_Gif)(nil),
+		(*Media_AvatarSticker)(nil),
+	}
+	file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes[7].OneofWrappers = []any{
+		(*RavenContent_StaticPhoto)(nil),
+		(*RavenContent_Video)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDesc), len(file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_rawDesc)),
+			NumEnums:      3,
+			NumMessages:   11,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_goTypes,
+		DependencyIndexes: file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_depIdxs,
+		EnumInfos:         file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_enumTypes,
+		MessageInfos:      file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_msgTypes,
+	}.Build()
+	File_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto = out.File
+	file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_goTypes = nil
+	file_instamadilloCoreTypeMedia_InstamadilloCoreTypeMedia_proto_depIdxs = nil
+}

+ 112 - 0
proto/instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto

@@ -0,0 +1,112 @@
+syntax = "proto2";
+package InstamadilloCoreTypeMedia;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia";
+
+enum PjpegScanConfiguration {
+	PJPEG_SCAN_CONFIGURATION_UNSPECIFIED = 0;
+	PJPEG_SCAN_CONFIGURATION_WA = 1;
+	PJPEG_SCAN_CONFIGURATION_E15 = 2;
+	PJPEG_SCAN_CONFIGURATION_E35 = 3;
+}
+
+message Media {
+	enum InterventionType {
+		UNSET = 0;
+		NONE = 1;
+		NUDE = 2;
+	}
+
+	oneof media {
+		StaticPhoto staticPhoto = 1;
+		Voice voice = 2;
+		Video video = 3;
+		Raven raven = 4;
+		Gif gif = 5;
+		AvatarSticker avatarSticker = 6;
+	}
+}
+
+message StaticPhoto {
+	optional CommonMediaTransport mediaTransport = 1;
+	optional int32 height = 2;
+	optional int32 width = 3;
+	repeated int32 scanLengths = 4 [packed=true];
+	optional Thumbnail thumbnail = 5;
+	optional PjpegScanConfiguration pjpegScanConfiguration = 6;
+}
+
+message Voice {
+	optional CommonMediaTransport mediaTransport = 1;
+	optional int32 duration = 2;
+	repeated float waveforms = 3 [packed=true];
+	optional int32 waveformSamplingFrequencyHz = 4;
+}
+
+message Video {
+	optional CommonMediaTransport mediaTransport = 1;
+	optional int32 height = 2;
+	optional int32 width = 3;
+	optional Thumbnail thumbnail = 4;
+	optional VideoExtraMetadata videoExtraMetadata = 5;
+}
+
+message Gif {
+	optional CommonMediaTransport mediaTransport = 1;
+	optional int32 height = 2;
+	optional int32 width = 3;
+	optional bool isSticker = 4;
+	optional string stickerID = 5;
+	optional string gifURL = 6;
+	optional int32 gifSize = 7;
+	optional bool isRandom = 8;
+}
+
+message AvatarSticker {
+	optional CommonMediaTransport mediaTransport = 1;
+	optional bool isAnimated = 2;
+	optional string stickerID = 3;
+	optional string stickerTemplate = 4;
+	optional int32 nuxType = 5;
+}
+
+message Raven {
+	enum ViewMode {
+		RAVEN_VIEW_MODEL_UNSPECIFIED = 0;
+		RAVEN_VIEW_MODEL_ONCE = 1;
+		RAVEN_VIEW_MODEL_REPLAYABLE = 2;
+		RAVEN_VIEW_MODEL_PERMANENT = 3;
+	}
+
+	optional ViewMode viewMode = 1;
+	optional RavenContent content = 2;
+}
+
+message RavenContent {
+	oneof ravenContent {
+		StaticPhoto staticPhoto = 1;
+		Video video = 2;
+	}
+}
+
+message Thumbnail {
+	optional CommonMediaTransport mediaTransport = 1;
+	optional int32 height = 2;
+	optional int32 width = 3;
+}
+
+message CommonMediaTransport {
+	optional string mediaID = 1;
+	optional string fileSHA256 = 2;
+	optional string mediaKey = 3;
+	optional string fileEncSHA256 = 4;
+	optional string directPath = 5;
+	optional string mediaKeyTimestamp = 6;
+	optional string sidecar = 7;
+	optional int32 fileLength = 8;
+	optional string mimetype = 9;
+	optional string objectID = 10;
+}
+
+message VideoExtraMetadata {
+	optional float uploadMosClientScore = 1;
+}

+ 514 - 0
proto/instamadilloCoreTypeText/InstamadilloCoreTypeText.pb.go

@@ -0,0 +1,514 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloCoreTypeText/InstamadilloCoreTypeText.proto
+
+package instamadilloCoreTypeText
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	instamadilloCoreTypeMedia "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Text_FormatStyle int32
+
+const (
+	Text_TEXT_FORMAT_STYLE_UNSPECIFIED   Text_FormatStyle = 0
+	Text_TEXT_FORMAT_STYLE_BOLD          Text_FormatStyle = 1
+	Text_TEXT_FORMAT_STYLE_ITALIC        Text_FormatStyle = 2
+	Text_TEXT_FORMAT_STYLE_STRIKETHROUGH Text_FormatStyle = 3
+	Text_TEXT_FORMAT_STYLE_UNDERLINE     Text_FormatStyle = 4
+	Text_TEXT_FORMAT_STYLE_INVALID       Text_FormatStyle = 5
+)
+
+// Enum value maps for Text_FormatStyle.
+var (
+	Text_FormatStyle_name = map[int32]string{
+		0: "TEXT_FORMAT_STYLE_UNSPECIFIED",
+		1: "TEXT_FORMAT_STYLE_BOLD",
+		2: "TEXT_FORMAT_STYLE_ITALIC",
+		3: "TEXT_FORMAT_STYLE_STRIKETHROUGH",
+		4: "TEXT_FORMAT_STYLE_UNDERLINE",
+		5: "TEXT_FORMAT_STYLE_INVALID",
+	}
+	Text_FormatStyle_value = map[string]int32{
+		"TEXT_FORMAT_STYLE_UNSPECIFIED":   0,
+		"TEXT_FORMAT_STYLE_BOLD":          1,
+		"TEXT_FORMAT_STYLE_ITALIC":        2,
+		"TEXT_FORMAT_STYLE_STRIKETHROUGH": 3,
+		"TEXT_FORMAT_STYLE_UNDERLINE":     4,
+		"TEXT_FORMAT_STYLE_INVALID":       5,
+	}
+)
+
+func (x Text_FormatStyle) Enum() *Text_FormatStyle {
+	p := new(Text_FormatStyle)
+	*p = x
+	return p
+}
+
+func (x Text_FormatStyle) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Text_FormatStyle) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_enumTypes[0].Descriptor()
+}
+
+func (Text_FormatStyle) Type() protoreflect.EnumType {
+	return &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_enumTypes[0]
+}
+
+func (x Text_FormatStyle) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Text_FormatStyle) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Text_FormatStyle(num)
+	return nil
+}
+
+// Deprecated: Use Text_FormatStyle.Descriptor instead.
+func (Text_FormatStyle) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescGZIP(), []int{0, 0}
+}
+
+type Text struct {
+	state                        protoimpl.MessageState         `protogen:"open.v1"`
+	Text                         *string                        `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"`
+	IsSuggestedReply             *bool                          `protobuf:"varint,2,opt,name=isSuggestedReply" json:"isSuggestedReply,omitempty"`
+	PostbackPayload              *string                        `protobuf:"bytes,3,opt,name=postbackPayload" json:"postbackPayload,omitempty"`
+	PowerUpData                  *PowerUpsData                  `protobuf:"bytes,4,opt,name=powerUpData" json:"powerUpData,omitempty"`
+	Commands                     []*CommandRangeData            `protobuf:"bytes,5,rep,name=commands" json:"commands,omitempty"`
+	AnimatedEmojiCharacterRanges []*AnimatedEmojiCharacterRange `protobuf:"bytes,6,rep,name=animatedEmojiCharacterRanges" json:"animatedEmojiCharacterRanges,omitempty"`
+	unknownFields                protoimpl.UnknownFields
+	sizeCache                    protoimpl.SizeCache
+}
+
+func (x *Text) Reset() {
+	*x = Text{}
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Text) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Text) ProtoMessage() {}
+
+func (x *Text) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Text.ProtoReflect.Descriptor instead.
+func (*Text) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Text) GetText() string {
+	if x != nil && x.Text != nil {
+		return *x.Text
+	}
+	return ""
+}
+
+func (x *Text) GetIsSuggestedReply() bool {
+	if x != nil && x.IsSuggestedReply != nil {
+		return *x.IsSuggestedReply
+	}
+	return false
+}
+
+func (x *Text) GetPostbackPayload() string {
+	if x != nil && x.PostbackPayload != nil {
+		return *x.PostbackPayload
+	}
+	return ""
+}
+
+func (x *Text) GetPowerUpData() *PowerUpsData {
+	if x != nil {
+		return x.PowerUpData
+	}
+	return nil
+}
+
+func (x *Text) GetCommands() []*CommandRangeData {
+	if x != nil {
+		return x.Commands
+	}
+	return nil
+}
+
+func (x *Text) GetAnimatedEmojiCharacterRanges() []*AnimatedEmojiCharacterRange {
+	if x != nil {
+		return x.AnimatedEmojiCharacterRanges
+	}
+	return nil
+}
+
+type PowerUpsData struct {
+	state           protoimpl.MessageState                          `protogen:"open.v1"`
+	Style           *int32                                          `protobuf:"varint,1,opt,name=style" json:"style,omitempty"`
+	MediaAttachment *instamadilloCoreTypeMedia.CommonMediaTransport `protobuf:"bytes,2,opt,name=mediaAttachment" json:"mediaAttachment,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *PowerUpsData) Reset() {
+	*x = PowerUpsData{}
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *PowerUpsData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PowerUpsData) ProtoMessage() {}
+
+func (x *PowerUpsData) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PowerUpsData.ProtoReflect.Descriptor instead.
+func (*PowerUpsData) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *PowerUpsData) GetStyle() int32 {
+	if x != nil && x.Style != nil {
+		return *x.Style
+	}
+	return 0
+}
+
+func (x *PowerUpsData) GetMediaAttachment() *instamadilloCoreTypeMedia.CommonMediaTransport {
+	if x != nil {
+		return x.MediaAttachment
+	}
+	return nil
+}
+
+type CommandRangeData struct {
+	state            protoimpl.MessageState `protogen:"open.v1"`
+	Offset           *int32                 `protobuf:"varint,1,opt,name=offset" json:"offset,omitempty"`
+	Length           *int32                 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"`
+	Type             *int32                 `protobuf:"varint,3,opt,name=type" json:"type,omitempty"`
+	FBID             *string                `protobuf:"bytes,4,opt,name=FBID" json:"FBID,omitempty"`
+	UserOrThreadFbid *string                `protobuf:"bytes,5,opt,name=userOrThreadFbid" json:"userOrThreadFbid,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *CommandRangeData) Reset() {
+	*x = CommandRangeData{}
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *CommandRangeData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CommandRangeData) ProtoMessage() {}
+
+func (x *CommandRangeData) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CommandRangeData.ProtoReflect.Descriptor instead.
+func (*CommandRangeData) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *CommandRangeData) GetOffset() int32 {
+	if x != nil && x.Offset != nil {
+		return *x.Offset
+	}
+	return 0
+}
+
+func (x *CommandRangeData) GetLength() int32 {
+	if x != nil && x.Length != nil {
+		return *x.Length
+	}
+	return 0
+}
+
+func (x *CommandRangeData) GetType() int32 {
+	if x != nil && x.Type != nil {
+		return *x.Type
+	}
+	return 0
+}
+
+func (x *CommandRangeData) GetFBID() string {
+	if x != nil && x.FBID != nil {
+		return *x.FBID
+	}
+	return ""
+}
+
+func (x *CommandRangeData) GetUserOrThreadFbid() string {
+	if x != nil && x.UserOrThreadFbid != nil {
+		return *x.UserOrThreadFbid
+	}
+	return ""
+}
+
+type FormattedText struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Offset        *int32                 `protobuf:"varint,1,opt,name=offset" json:"offset,omitempty"`
+	Length        *int32                 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"`
+	Style         *Text_FormatStyle      `protobuf:"varint,3,opt,name=style,enum=InstamadilloCoreTypeText.Text_FormatStyle" json:"style,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *FormattedText) Reset() {
+	*x = FormattedText{}
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *FormattedText) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FormattedText) ProtoMessage() {}
+
+func (x *FormattedText) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FormattedText.ProtoReflect.Descriptor instead.
+func (*FormattedText) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *FormattedText) GetOffset() int32 {
+	if x != nil && x.Offset != nil {
+		return *x.Offset
+	}
+	return 0
+}
+
+func (x *FormattedText) GetLength() int32 {
+	if x != nil && x.Length != nil {
+		return *x.Length
+	}
+	return 0
+}
+
+func (x *FormattedText) GetStyle() Text_FormatStyle {
+	if x != nil && x.Style != nil {
+		return *x.Style
+	}
+	return Text_TEXT_FORMAT_STYLE_UNSPECIFIED
+}
+
+type AnimatedEmojiCharacterRange struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Offset        *int32                 `protobuf:"varint,1,opt,name=offset" json:"offset,omitempty"`
+	Length        *int32                 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AnimatedEmojiCharacterRange) Reset() {
+	*x = AnimatedEmojiCharacterRange{}
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AnimatedEmojiCharacterRange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AnimatedEmojiCharacterRange) ProtoMessage() {}
+
+func (x *AnimatedEmojiCharacterRange) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AnimatedEmojiCharacterRange.ProtoReflect.Descriptor instead.
+func (*AnimatedEmojiCharacterRange) Descriptor() ([]byte, []int) {
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *AnimatedEmojiCharacterRange) GetOffset() int32 {
+	if x != nil && x.Offset != nil {
+		return *x.Offset
+	}
+	return 0
+}
+
+func (x *AnimatedEmojiCharacterRange) GetLength() int32 {
+	if x != nil && x.Length != nil {
+		return *x.Length
+	}
+	return 0
+}
+
+var File_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto protoreflect.FileDescriptor
+
+const file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDesc = "" +
+	"\n" +
+	"7instamadilloCoreTypeText/InstamadilloCoreTypeText.proto\x12\x18InstamadilloCoreTypeText\x1a9instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto\"\xcf\x04\n" +
+	"\x04Text\x12\x12\n" +
+	"\x04text\x18\x01 \x01(\tR\x04text\x12*\n" +
+	"\x10isSuggestedReply\x18\x02 \x01(\bR\x10isSuggestedReply\x12(\n" +
+	"\x0fpostbackPayload\x18\x03 \x01(\tR\x0fpostbackPayload\x12H\n" +
+	"\vpowerUpData\x18\x04 \x01(\v2&.InstamadilloCoreTypeText.PowerUpsDataR\vpowerUpData\x12F\n" +
+	"\bcommands\x18\x05 \x03(\v2*.InstamadilloCoreTypeText.CommandRangeDataR\bcommands\x12y\n" +
+	"\x1canimatedEmojiCharacterRanges\x18\x06 \x03(\v25.InstamadilloCoreTypeText.AnimatedEmojiCharacterRangeR\x1canimatedEmojiCharacterRanges\"\xcf\x01\n" +
+	"\vFormatStyle\x12!\n" +
+	"\x1dTEXT_FORMAT_STYLE_UNSPECIFIED\x10\x00\x12\x1a\n" +
+	"\x16TEXT_FORMAT_STYLE_BOLD\x10\x01\x12\x1c\n" +
+	"\x18TEXT_FORMAT_STYLE_ITALIC\x10\x02\x12#\n" +
+	"\x1fTEXT_FORMAT_STYLE_STRIKETHROUGH\x10\x03\x12\x1f\n" +
+	"\x1bTEXT_FORMAT_STYLE_UNDERLINE\x10\x04\x12\x1d\n" +
+	"\x19TEXT_FORMAT_STYLE_INVALID\x10\x05\"\x7f\n" +
+	"\fPowerUpsData\x12\x14\n" +
+	"\x05style\x18\x01 \x01(\x05R\x05style\x12Y\n" +
+	"\x0fmediaAttachment\x18\x02 \x01(\v2/.InstamadilloCoreTypeMedia.CommonMediaTransportR\x0fmediaAttachment\"\x96\x01\n" +
+	"\x10CommandRangeData\x12\x16\n" +
+	"\x06offset\x18\x01 \x01(\x05R\x06offset\x12\x16\n" +
+	"\x06length\x18\x02 \x01(\x05R\x06length\x12\x12\n" +
+	"\x04type\x18\x03 \x01(\x05R\x04type\x12\x12\n" +
+	"\x04FBID\x18\x04 \x01(\tR\x04FBID\x12*\n" +
+	"\x10userOrThreadFbid\x18\x05 \x01(\tR\x10userOrThreadFbid\"\x81\x01\n" +
+	"\rFormattedText\x12\x16\n" +
+	"\x06offset\x18\x01 \x01(\x05R\x06offset\x12\x16\n" +
+	"\x06length\x18\x02 \x01(\x05R\x06length\x12@\n" +
+	"\x05style\x18\x03 \x01(\x0e2*.InstamadilloCoreTypeText.Text.FormatStyleR\x05style\"M\n" +
+	"\x1bAnimatedEmojiCharacterRange\x12\x16\n" +
+	"\x06offset\x18\x01 \x01(\x05R\x06offset\x12\x16\n" +
+	"\x06length\x18\x02 \x01(\x05R\x06lengthB4Z2go.mau.fi/whatsmeow/proto/instamadilloCoreTypeText"
+
+var (
+	file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescOnce sync.Once
+	file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescData []byte
+)
+
+func file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescGZIP() []byte {
+	file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescOnce.Do(func() {
+		file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDesc), len(file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDesc)))
+	})
+	return file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDescData
+}
+
+var file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_goTypes = []any{
+	(Text_FormatStyle)(0),               // 0: InstamadilloCoreTypeText.Text.FormatStyle
+	(*Text)(nil),                        // 1: InstamadilloCoreTypeText.Text
+	(*PowerUpsData)(nil),                // 2: InstamadilloCoreTypeText.PowerUpsData
+	(*CommandRangeData)(nil),            // 3: InstamadilloCoreTypeText.CommandRangeData
+	(*FormattedText)(nil),               // 4: InstamadilloCoreTypeText.FormattedText
+	(*AnimatedEmojiCharacterRange)(nil), // 5: InstamadilloCoreTypeText.AnimatedEmojiCharacterRange
+	(*instamadilloCoreTypeMedia.CommonMediaTransport)(nil), // 6: InstamadilloCoreTypeMedia.CommonMediaTransport
+}
+var file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_depIdxs = []int32{
+	2, // 0: InstamadilloCoreTypeText.Text.powerUpData:type_name -> InstamadilloCoreTypeText.PowerUpsData
+	3, // 1: InstamadilloCoreTypeText.Text.commands:type_name -> InstamadilloCoreTypeText.CommandRangeData
+	5, // 2: InstamadilloCoreTypeText.Text.animatedEmojiCharacterRanges:type_name -> InstamadilloCoreTypeText.AnimatedEmojiCharacterRange
+	6, // 3: InstamadilloCoreTypeText.PowerUpsData.mediaAttachment:type_name -> InstamadilloCoreTypeMedia.CommonMediaTransport
+	0, // 4: InstamadilloCoreTypeText.FormattedText.style:type_name -> InstamadilloCoreTypeText.Text.FormatStyle
+	5, // [5:5] is the sub-list for method output_type
+	5, // [5:5] is the sub-list for method input_type
+	5, // [5:5] is the sub-list for extension type_name
+	5, // [5:5] is the sub-list for extension extendee
+	0, // [0:5] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_init() }
+func file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_init() {
+	if File_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDesc), len(file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_rawDesc)),
+			NumEnums:      1,
+			NumMessages:   5,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_goTypes,
+		DependencyIndexes: file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_depIdxs,
+		EnumInfos:         file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_enumTypes,
+		MessageInfos:      file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_msgTypes,
+	}.Build()
+	File_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto = out.File
+	file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_goTypes = nil
+	file_instamadilloCoreTypeText_InstamadilloCoreTypeText_proto_depIdxs = nil
+}

+ 47 - 0
proto/instamadilloCoreTypeText/InstamadilloCoreTypeText.proto

@@ -0,0 +1,47 @@
+syntax = "proto2";
+package InstamadilloCoreTypeText;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeText";
+
+import "instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto";
+
+message Text {
+	enum FormatStyle {
+		TEXT_FORMAT_STYLE_UNSPECIFIED = 0;
+		TEXT_FORMAT_STYLE_BOLD = 1;
+		TEXT_FORMAT_STYLE_ITALIC = 2;
+		TEXT_FORMAT_STYLE_STRIKETHROUGH = 3;
+		TEXT_FORMAT_STYLE_UNDERLINE = 4;
+		TEXT_FORMAT_STYLE_INVALID = 5;
+	}
+
+	optional string text = 1;
+	optional bool isSuggestedReply = 2;
+	optional string postbackPayload = 3;
+	optional PowerUpsData powerUpData = 4;
+	repeated CommandRangeData commands = 5;
+	repeated AnimatedEmojiCharacterRange animatedEmojiCharacterRanges = 6;
+}
+
+message PowerUpsData {
+	optional int32 style = 1;
+	optional InstamadilloCoreTypeMedia.CommonMediaTransport mediaAttachment = 2;
+}
+
+message CommandRangeData {
+	optional int32 offset = 1;
+	optional int32 length = 2;
+	optional int32 type = 3;
+	optional string FBID = 4;
+	optional string userOrThreadFbid = 5;
+}
+
+message FormattedText {
+	optional int32 offset = 1;
+	optional int32 length = 2;
+	optional Text.FormatStyle style = 3;
+}
+
+message AnimatedEmojiCharacterRange {
+	optional int32 offset = 1;
+	optional int32 length = 2;
+}

+ 123 - 0
proto/instamadilloDeleteMessage/InstamadilloDeleteMessage.pb.go

@@ -0,0 +1,123 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloDeleteMessage/InstamadilloDeleteMessage.proto
+
+package instamadilloDeleteMessage
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type DeleteMessagePayload struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	MessageOtid   *string                `protobuf:"bytes,1,opt,name=messageOtid" json:"messageOtid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *DeleteMessagePayload) Reset() {
+	*x = DeleteMessagePayload{}
+	mi := &file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteMessagePayload) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteMessagePayload) ProtoMessage() {}
+
+func (x *DeleteMessagePayload) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteMessagePayload.ProtoReflect.Descriptor instead.
+func (*DeleteMessagePayload) Descriptor() ([]byte, []int) {
+	return file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *DeleteMessagePayload) GetMessageOtid() string {
+	if x != nil && x.MessageOtid != nil {
+		return *x.MessageOtid
+	}
+	return ""
+}
+
+var File_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto protoreflect.FileDescriptor
+
+const file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDesc = "" +
+	"\n" +
+	"9instamadilloDeleteMessage/InstamadilloDeleteMessage.proto\x12\x19InstamadilloDeleteMessage\"8\n" +
+	"\x14DeleteMessagePayload\x12 \n" +
+	"\vmessageOtid\x18\x01 \x01(\tR\vmessageOtidB5Z3go.mau.fi/whatsmeow/proto/instamadilloDeleteMessage"
+
+var (
+	file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDescOnce sync.Once
+	file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDescData []byte
+)
+
+func file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDescGZIP() []byte {
+	file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDescOnce.Do(func() {
+		file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDesc), len(file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDesc)))
+	})
+	return file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDescData
+}
+
+var file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_goTypes = []any{
+	(*DeleteMessagePayload)(nil), // 0: InstamadilloDeleteMessage.DeleteMessagePayload
+}
+var file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_init() }
+func file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_init() {
+	if File_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDesc), len(file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_goTypes,
+		DependencyIndexes: file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_depIdxs,
+		MessageInfos:      file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_msgTypes,
+	}.Build()
+	File_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto = out.File
+	file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_goTypes = nil
+	file_instamadilloDeleteMessage_InstamadilloDeleteMessage_proto_depIdxs = nil
+}

+ 7 - 0
proto/instamadilloDeleteMessage/InstamadilloDeleteMessage.proto

@@ -0,0 +1,7 @@
+syntax = "proto2";
+package InstamadilloDeleteMessage;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloDeleteMessage";
+
+message DeleteMessagePayload {
+	optional string messageOtid = 1;
+}

+ 3 - 0
proto/instamadilloDeleteMessage/extra.go

@@ -0,0 +1,3 @@
+package instamadilloDeleteMessage
+
+func (*DeleteMessagePayload) IsMessageApplicationSub() {}

+ 720 - 0
proto/instamadilloSupplementMessage/InstamadilloSupplementMessage.pb.go

@@ -0,0 +1,720 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloSupplementMessage/InstamadilloSupplementMessage.proto
+
+package instamadilloSupplementMessage
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	instamadilloCoreTypeMedia "go.mau.fi/whatsmeow/proto/instamadilloCoreTypeMedia"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type SupplementMessagePayload struct {
+	state                          protoimpl.MessageState    `protogen:"open.v1"`
+	TargetMessageOtid              *string                   `protobuf:"bytes,1,opt,name=targetMessageOtid" json:"targetMessageOtid,omitempty"`
+	UniquingKeyForSupplementalData *string                   `protobuf:"bytes,2,opt,name=uniquingKeyForSupplementalData" json:"uniquingKeyForSupplementalData,omitempty"`
+	Content                        *SupplementMessageContent `protobuf:"bytes,3,opt,name=content" json:"content,omitempty"`
+	TargetMessageWaServerTimeSec   *string                   `protobuf:"bytes,4,opt,name=targetMessageWaServerTimeSec" json:"targetMessageWaServerTimeSec,omitempty"`
+	TargetWaThreadID               *string                   `protobuf:"bytes,5,opt,name=targetWaThreadID" json:"targetWaThreadID,omitempty"`
+	unknownFields                  protoimpl.UnknownFields
+	sizeCache                      protoimpl.SizeCache
+}
+
+func (x *SupplementMessagePayload) Reset() {
+	*x = SupplementMessagePayload{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SupplementMessagePayload) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SupplementMessagePayload) ProtoMessage() {}
+
+func (x *SupplementMessagePayload) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SupplementMessagePayload.ProtoReflect.Descriptor instead.
+func (*SupplementMessagePayload) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *SupplementMessagePayload) GetTargetMessageOtid() string {
+	if x != nil && x.TargetMessageOtid != nil {
+		return *x.TargetMessageOtid
+	}
+	return ""
+}
+
+func (x *SupplementMessagePayload) GetUniquingKeyForSupplementalData() string {
+	if x != nil && x.UniquingKeyForSupplementalData != nil {
+		return *x.UniquingKeyForSupplementalData
+	}
+	return ""
+}
+
+func (x *SupplementMessagePayload) GetContent() *SupplementMessageContent {
+	if x != nil {
+		return x.Content
+	}
+	return nil
+}
+
+func (x *SupplementMessagePayload) GetTargetMessageWaServerTimeSec() string {
+	if x != nil && x.TargetMessageWaServerTimeSec != nil {
+		return *x.TargetMessageWaServerTimeSec
+	}
+	return ""
+}
+
+func (x *SupplementMessagePayload) GetTargetWaThreadID() string {
+	if x != nil && x.TargetWaThreadID != nil {
+		return *x.TargetWaThreadID
+	}
+	return ""
+}
+
+type SupplementMessageContent struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to SupplementMessageContent:
+	//
+	//	*SupplementMessageContent_Reaction
+	//	*SupplementMessageContent_ContentView
+	//	*SupplementMessageContent_EditText
+	//	*SupplementMessageContent_MediaReaction
+	//	*SupplementMessageContent_OriginalTransportPayload
+	//	*SupplementMessageContent_MediaInterventions
+	SupplementMessageContent isSupplementMessageContent_SupplementMessageContent `protobuf_oneof:"supplementMessageContent"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *SupplementMessageContent) Reset() {
+	*x = SupplementMessageContent{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SupplementMessageContent) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SupplementMessageContent) ProtoMessage() {}
+
+func (x *SupplementMessageContent) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SupplementMessageContent.ProtoReflect.Descriptor instead.
+func (*SupplementMessageContent) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SupplementMessageContent) GetSupplementMessageContent() isSupplementMessageContent_SupplementMessageContent {
+	if x != nil {
+		return x.SupplementMessageContent
+	}
+	return nil
+}
+
+func (x *SupplementMessageContent) GetReaction() *Reaction {
+	if x != nil {
+		if x, ok := x.SupplementMessageContent.(*SupplementMessageContent_Reaction); ok {
+			return x.Reaction
+		}
+	}
+	return nil
+}
+
+func (x *SupplementMessageContent) GetContentView() *ContentView {
+	if x != nil {
+		if x, ok := x.SupplementMessageContent.(*SupplementMessageContent_ContentView); ok {
+			return x.ContentView
+		}
+	}
+	return nil
+}
+
+func (x *SupplementMessageContent) GetEditText() *EditText {
+	if x != nil {
+		if x, ok := x.SupplementMessageContent.(*SupplementMessageContent_EditText); ok {
+			return x.EditText
+		}
+	}
+	return nil
+}
+
+func (x *SupplementMessageContent) GetMediaReaction() *MediaReaction {
+	if x != nil {
+		if x, ok := x.SupplementMessageContent.(*SupplementMessageContent_MediaReaction); ok {
+			return x.MediaReaction
+		}
+	}
+	return nil
+}
+
+func (x *SupplementMessageContent) GetOriginalTransportPayload() *OriginalTransportPayload {
+	if x != nil {
+		if x, ok := x.SupplementMessageContent.(*SupplementMessageContent_OriginalTransportPayload); ok {
+			return x.OriginalTransportPayload
+		}
+	}
+	return nil
+}
+
+func (x *SupplementMessageContent) GetMediaInterventions() *MediaInterventions {
+	if x != nil {
+		if x, ok := x.SupplementMessageContent.(*SupplementMessageContent_MediaInterventions); ok {
+			return x.MediaInterventions
+		}
+	}
+	return nil
+}
+
+type isSupplementMessageContent_SupplementMessageContent interface {
+	isSupplementMessageContent_SupplementMessageContent()
+}
+
+type SupplementMessageContent_Reaction struct {
+	Reaction *Reaction `protobuf:"bytes,1,opt,name=reaction,oneof"`
+}
+
+type SupplementMessageContent_ContentView struct {
+	ContentView *ContentView `protobuf:"bytes,2,opt,name=contentView,oneof"`
+}
+
+type SupplementMessageContent_EditText struct {
+	EditText *EditText `protobuf:"bytes,3,opt,name=editText,oneof"`
+}
+
+type SupplementMessageContent_MediaReaction struct {
+	MediaReaction *MediaReaction `protobuf:"bytes,4,opt,name=mediaReaction,oneof"`
+}
+
+type SupplementMessageContent_OriginalTransportPayload struct {
+	OriginalTransportPayload *OriginalTransportPayload `protobuf:"bytes,5,opt,name=originalTransportPayload,oneof"`
+}
+
+type SupplementMessageContent_MediaInterventions struct {
+	MediaInterventions *MediaInterventions `protobuf:"bytes,6,opt,name=mediaInterventions,oneof"`
+}
+
+func (*SupplementMessageContent_Reaction) isSupplementMessageContent_SupplementMessageContent() {}
+
+func (*SupplementMessageContent_ContentView) isSupplementMessageContent_SupplementMessageContent() {}
+
+func (*SupplementMessageContent_EditText) isSupplementMessageContent_SupplementMessageContent() {}
+
+func (*SupplementMessageContent_MediaReaction) isSupplementMessageContent_SupplementMessageContent() {
+}
+
+func (*SupplementMessageContent_OriginalTransportPayload) isSupplementMessageContent_SupplementMessageContent() {
+}
+
+func (*SupplementMessageContent_MediaInterventions) isSupplementMessageContent_SupplementMessageContent() {
+}
+
+type MediaReaction struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	MediaID       *string                `protobuf:"bytes,1,opt,name=mediaID" json:"mediaID,omitempty"`
+	Reaction      *Reaction              `protobuf:"bytes,2,opt,name=reaction" json:"reaction,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *MediaReaction) Reset() {
+	*x = MediaReaction{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *MediaReaction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MediaReaction) ProtoMessage() {}
+
+func (x *MediaReaction) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MediaReaction.ProtoReflect.Descriptor instead.
+func (*MediaReaction) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *MediaReaction) GetMediaID() string {
+	if x != nil && x.MediaID != nil {
+		return *x.MediaID
+	}
+	return ""
+}
+
+func (x *MediaReaction) GetReaction() *Reaction {
+	if x != nil {
+		return x.Reaction
+	}
+	return nil
+}
+
+type Reaction struct {
+	state          protoimpl.MessageState `protogen:"open.v1"`
+	ReactionType   *string                `protobuf:"bytes,1,opt,name=reactionType" json:"reactionType,omitempty"`
+	ReactionStatus *string                `protobuf:"bytes,2,opt,name=reactionStatus" json:"reactionStatus,omitempty"`
+	Emoji          *string                `protobuf:"bytes,3,opt,name=emoji" json:"emoji,omitempty"`
+	SuperReactType *string                `protobuf:"bytes,4,opt,name=superReactType" json:"superReactType,omitempty"`
+	ActionLogOtid  *string                `protobuf:"bytes,5,opt,name=actionLogOtid" json:"actionLogOtid,omitempty"`
+	unknownFields  protoimpl.UnknownFields
+	sizeCache      protoimpl.SizeCache
+}
+
+func (x *Reaction) Reset() {
+	*x = Reaction{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Reaction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Reaction) ProtoMessage() {}
+
+func (x *Reaction) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Reaction.ProtoReflect.Descriptor instead.
+func (*Reaction) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Reaction) GetReactionType() string {
+	if x != nil && x.ReactionType != nil {
+		return *x.ReactionType
+	}
+	return ""
+}
+
+func (x *Reaction) GetReactionStatus() string {
+	if x != nil && x.ReactionStatus != nil {
+		return *x.ReactionStatus
+	}
+	return ""
+}
+
+func (x *Reaction) GetEmoji() string {
+	if x != nil && x.Emoji != nil {
+		return *x.Emoji
+	}
+	return ""
+}
+
+func (x *Reaction) GetSuperReactType() string {
+	if x != nil && x.SuperReactType != nil {
+		return *x.SuperReactType
+	}
+	return ""
+}
+
+func (x *Reaction) GetActionLogOtid() string {
+	if x != nil && x.ActionLogOtid != nil {
+		return *x.ActionLogOtid
+	}
+	return ""
+}
+
+type ContentView struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Seen          *bool                  `protobuf:"varint,1,opt,name=seen" json:"seen,omitempty"`
+	Screenshotted *bool                  `protobuf:"varint,2,opt,name=screenshotted" json:"screenshotted,omitempty"`
+	Replayed      *bool                  `protobuf:"varint,3,opt,name=replayed" json:"replayed,omitempty"`
+	Mimetype      *string                `protobuf:"bytes,4,opt,name=mimetype" json:"mimetype,omitempty"`
+	ObjectID      *string                `protobuf:"bytes,5,opt,name=objectID" json:"objectID,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ContentView) Reset() {
+	*x = ContentView{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ContentView) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ContentView) ProtoMessage() {}
+
+func (x *ContentView) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ContentView.ProtoReflect.Descriptor instead.
+func (*ContentView) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ContentView) GetSeen() bool {
+	if x != nil && x.Seen != nil {
+		return *x.Seen
+	}
+	return false
+}
+
+func (x *ContentView) GetScreenshotted() bool {
+	if x != nil && x.Screenshotted != nil {
+		return *x.Screenshotted
+	}
+	return false
+}
+
+func (x *ContentView) GetReplayed() bool {
+	if x != nil && x.Replayed != nil {
+		return *x.Replayed
+	}
+	return false
+}
+
+func (x *ContentView) GetMimetype() string {
+	if x != nil && x.Mimetype != nil {
+		return *x.Mimetype
+	}
+	return ""
+}
+
+func (x *ContentView) GetObjectID() string {
+	if x != nil && x.ObjectID != nil {
+		return *x.ObjectID
+	}
+	return ""
+}
+
+type EditText struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	NewContent    *string                `protobuf:"bytes,1,opt,name=newContent" json:"newContent,omitempty"`
+	EditCount     *int32                 `protobuf:"varint,2,opt,name=editCount" json:"editCount,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *EditText) Reset() {
+	*x = EditText{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *EditText) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EditText) ProtoMessage() {}
+
+func (x *EditText) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use EditText.ProtoReflect.Descriptor instead.
+func (*EditText) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *EditText) GetNewContent() string {
+	if x != nil && x.NewContent != nil {
+		return *x.NewContent
+	}
+	return ""
+}
+
+func (x *EditText) GetEditCount() int32 {
+	if x != nil && x.EditCount != nil {
+		return *x.EditCount
+	}
+	return 0
+}
+
+type OriginalTransportPayload struct {
+	state                    protoimpl.MessageState `protogen:"open.v1"`
+	OriginalTransportPayload []byte                 `protobuf:"bytes,1,opt,name=originalTransportPayload" json:"originalTransportPayload,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *OriginalTransportPayload) Reset() {
+	*x = OriginalTransportPayload{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *OriginalTransportPayload) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OriginalTransportPayload) ProtoMessage() {}
+
+func (x *OriginalTransportPayload) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use OriginalTransportPayload.ProtoReflect.Descriptor instead.
+func (*OriginalTransportPayload) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *OriginalTransportPayload) GetOriginalTransportPayload() []byte {
+	if x != nil {
+		return x.OriginalTransportPayload
+	}
+	return nil
+}
+
+type MediaInterventions struct {
+	state            protoimpl.MessageState                            `protogen:"open.v1"`
+	MediaID          *string                                           `protobuf:"bytes,1,opt,name=mediaID" json:"mediaID,omitempty"`
+	InterventionType *instamadilloCoreTypeMedia.Media_InterventionType `protobuf:"varint,2,opt,name=interventionType,enum=InstamadilloCoreTypeMedia.Media_InterventionType" json:"interventionType,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *MediaInterventions) Reset() {
+	*x = MediaInterventions{}
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *MediaInterventions) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MediaInterventions) ProtoMessage() {}
+
+func (x *MediaInterventions) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MediaInterventions.ProtoReflect.Descriptor instead.
+func (*MediaInterventions) Descriptor() ([]byte, []int) {
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *MediaInterventions) GetMediaID() string {
+	if x != nil && x.MediaID != nil {
+		return *x.MediaID
+	}
+	return ""
+}
+
+func (x *MediaInterventions) GetInterventionType() instamadilloCoreTypeMedia.Media_InterventionType {
+	if x != nil && x.InterventionType != nil {
+		return *x.InterventionType
+	}
+	return instamadilloCoreTypeMedia.Media_InterventionType(0)
+}
+
+var File_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto protoreflect.FileDescriptor
+
+const file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDesc = "" +
+	"\n" +
+	"AinstamadilloSupplementMessage/InstamadilloSupplementMessage.proto\x12\x1dInstamadilloSupplementMessage\x1a9instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto\"\xd3\x02\n" +
+	"\x18SupplementMessagePayload\x12,\n" +
+	"\x11targetMessageOtid\x18\x01 \x01(\tR\x11targetMessageOtid\x12F\n" +
+	"\x1euniquingKeyForSupplementalData\x18\x02 \x01(\tR\x1euniquingKeyForSupplementalData\x12Q\n" +
+	"\acontent\x18\x03 \x01(\v27.InstamadilloSupplementMessage.SupplementMessageContentR\acontent\x12B\n" +
+	"\x1ctargetMessageWaServerTimeSec\x18\x04 \x01(\tR\x1ctargetMessageWaServerTimeSec\x12*\n" +
+	"\x10targetWaThreadID\x18\x05 \x01(\tR\x10targetWaThreadID\"\xc6\x04\n" +
+	"\x18SupplementMessageContent\x12E\n" +
+	"\breaction\x18\x01 \x01(\v2'.InstamadilloSupplementMessage.ReactionH\x00R\breaction\x12N\n" +
+	"\vcontentView\x18\x02 \x01(\v2*.InstamadilloSupplementMessage.ContentViewH\x00R\vcontentView\x12E\n" +
+	"\beditText\x18\x03 \x01(\v2'.InstamadilloSupplementMessage.EditTextH\x00R\beditText\x12T\n" +
+	"\rmediaReaction\x18\x04 \x01(\v2,.InstamadilloSupplementMessage.MediaReactionH\x00R\rmediaReaction\x12u\n" +
+	"\x18originalTransportPayload\x18\x05 \x01(\v27.InstamadilloSupplementMessage.OriginalTransportPayloadH\x00R\x18originalTransportPayload\x12c\n" +
+	"\x12mediaInterventions\x18\x06 \x01(\v21.InstamadilloSupplementMessage.MediaInterventionsH\x00R\x12mediaInterventionsB\x1a\n" +
+	"\x18supplementMessageContent\"n\n" +
+	"\rMediaReaction\x12\x18\n" +
+	"\amediaID\x18\x01 \x01(\tR\amediaID\x12C\n" +
+	"\breaction\x18\x02 \x01(\v2'.InstamadilloSupplementMessage.ReactionR\breaction\"\xba\x01\n" +
+	"\bReaction\x12\"\n" +
+	"\freactionType\x18\x01 \x01(\tR\freactionType\x12&\n" +
+	"\x0ereactionStatus\x18\x02 \x01(\tR\x0ereactionStatus\x12\x14\n" +
+	"\x05emoji\x18\x03 \x01(\tR\x05emoji\x12&\n" +
+	"\x0esuperReactType\x18\x04 \x01(\tR\x0esuperReactType\x12$\n" +
+	"\ractionLogOtid\x18\x05 \x01(\tR\ractionLogOtid\"\x9b\x01\n" +
+	"\vContentView\x12\x12\n" +
+	"\x04seen\x18\x01 \x01(\bR\x04seen\x12$\n" +
+	"\rscreenshotted\x18\x02 \x01(\bR\rscreenshotted\x12\x1a\n" +
+	"\breplayed\x18\x03 \x01(\bR\breplayed\x12\x1a\n" +
+	"\bmimetype\x18\x04 \x01(\tR\bmimetype\x12\x1a\n" +
+	"\bobjectID\x18\x05 \x01(\tR\bobjectID\"H\n" +
+	"\bEditText\x12\x1e\n" +
+	"\n" +
+	"newContent\x18\x01 \x01(\tR\n" +
+	"newContent\x12\x1c\n" +
+	"\teditCount\x18\x02 \x01(\x05R\teditCount\"V\n" +
+	"\x18OriginalTransportPayload\x12:\n" +
+	"\x18originalTransportPayload\x18\x01 \x01(\fR\x18originalTransportPayload\"\x8d\x01\n" +
+	"\x12MediaInterventions\x12\x18\n" +
+	"\amediaID\x18\x01 \x01(\tR\amediaID\x12]\n" +
+	"\x10interventionType\x18\x02 \x01(\x0e21.InstamadilloCoreTypeMedia.Media.InterventionTypeR\x10interventionTypeB9Z7go.mau.fi/whatsmeow/proto/instamadilloSupplementMessage"
+
+var (
+	file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescOnce sync.Once
+	file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescData []byte
+)
+
+func file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescGZIP() []byte {
+	file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescOnce.Do(func() {
+		file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDesc), len(file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDesc)))
+	})
+	return file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDescData
+}
+
+var file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
+var file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_goTypes = []any{
+	(*SupplementMessagePayload)(nil),                      // 0: InstamadilloSupplementMessage.SupplementMessagePayload
+	(*SupplementMessageContent)(nil),                      // 1: InstamadilloSupplementMessage.SupplementMessageContent
+	(*MediaReaction)(nil),                                 // 2: InstamadilloSupplementMessage.MediaReaction
+	(*Reaction)(nil),                                      // 3: InstamadilloSupplementMessage.Reaction
+	(*ContentView)(nil),                                   // 4: InstamadilloSupplementMessage.ContentView
+	(*EditText)(nil),                                      // 5: InstamadilloSupplementMessage.EditText
+	(*OriginalTransportPayload)(nil),                      // 6: InstamadilloSupplementMessage.OriginalTransportPayload
+	(*MediaInterventions)(nil),                            // 7: InstamadilloSupplementMessage.MediaInterventions
+	(instamadilloCoreTypeMedia.Media_InterventionType)(0), // 8: InstamadilloCoreTypeMedia.Media.InterventionType
+}
+var file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_depIdxs = []int32{
+	1, // 0: InstamadilloSupplementMessage.SupplementMessagePayload.content:type_name -> InstamadilloSupplementMessage.SupplementMessageContent
+	3, // 1: InstamadilloSupplementMessage.SupplementMessageContent.reaction:type_name -> InstamadilloSupplementMessage.Reaction
+	4, // 2: InstamadilloSupplementMessage.SupplementMessageContent.contentView:type_name -> InstamadilloSupplementMessage.ContentView
+	5, // 3: InstamadilloSupplementMessage.SupplementMessageContent.editText:type_name -> InstamadilloSupplementMessage.EditText
+	2, // 4: InstamadilloSupplementMessage.SupplementMessageContent.mediaReaction:type_name -> InstamadilloSupplementMessage.MediaReaction
+	6, // 5: InstamadilloSupplementMessage.SupplementMessageContent.originalTransportPayload:type_name -> InstamadilloSupplementMessage.OriginalTransportPayload
+	7, // 6: InstamadilloSupplementMessage.SupplementMessageContent.mediaInterventions:type_name -> InstamadilloSupplementMessage.MediaInterventions
+	3, // 7: InstamadilloSupplementMessage.MediaReaction.reaction:type_name -> InstamadilloSupplementMessage.Reaction
+	8, // 8: InstamadilloSupplementMessage.MediaInterventions.interventionType:type_name -> InstamadilloCoreTypeMedia.Media.InterventionType
+	9, // [9:9] is the sub-list for method output_type
+	9, // [9:9] is the sub-list for method input_type
+	9, // [9:9] is the sub-list for extension type_name
+	9, // [9:9] is the sub-list for extension extendee
+	0, // [0:9] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_init() }
+func file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_init() {
+	if File_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto != nil {
+		return
+	}
+	file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes[1].OneofWrappers = []any{
+		(*SupplementMessageContent_Reaction)(nil),
+		(*SupplementMessageContent_ContentView)(nil),
+		(*SupplementMessageContent_EditText)(nil),
+		(*SupplementMessageContent_MediaReaction)(nil),
+		(*SupplementMessageContent_OriginalTransportPayload)(nil),
+		(*SupplementMessageContent_MediaInterventions)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDesc), len(file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   8,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_goTypes,
+		DependencyIndexes: file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_depIdxs,
+		MessageInfos:      file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_msgTypes,
+	}.Build()
+	File_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto = out.File
+	file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_goTypes = nil
+	file_instamadilloSupplementMessage_InstamadilloSupplementMessage_proto_depIdxs = nil
+}

+ 59 - 0
proto/instamadilloSupplementMessage/InstamadilloSupplementMessage.proto

@@ -0,0 +1,59 @@
+syntax = "proto2";
+package InstamadilloSupplementMessage;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloSupplementMessage";
+
+import "instamadilloCoreTypeMedia/InstamadilloCoreTypeMedia.proto";
+
+message SupplementMessagePayload {
+	optional string targetMessageOtid = 1;
+	optional string uniquingKeyForSupplementalData = 2;
+	optional SupplementMessageContent content = 3;
+	optional string targetMessageWaServerTimeSec = 4;
+	optional string targetWaThreadID = 5;
+}
+
+message SupplementMessageContent {
+	oneof supplementMessageContent {
+		Reaction reaction = 1;
+		ContentView contentView = 2;
+		EditText editText = 3;
+		MediaReaction mediaReaction = 4;
+		OriginalTransportPayload originalTransportPayload = 5;
+		MediaInterventions mediaInterventions = 6;
+	}
+}
+
+message MediaReaction {
+	optional string mediaID = 1;
+	optional Reaction reaction = 2;
+}
+
+message Reaction {
+	optional string reactionType = 1;
+	optional string reactionStatus = 2;
+	optional string emoji = 3;
+	optional string superReactType = 4;
+	optional string actionLogOtid = 5;
+}
+
+message ContentView {
+	optional bool seen = 1;
+	optional bool screenshotted = 2;
+	optional bool replayed = 3;
+	optional string mimetype = 4;
+	optional string objectID = 5;
+}
+
+message EditText {
+	optional string newContent = 1;
+	optional int32 editCount = 2;
+}
+
+message OriginalTransportPayload {
+	optional bytes originalTransportPayload = 1;
+}
+
+message MediaInterventions {
+	optional string mediaID = 1;
+	optional InstamadilloCoreTypeMedia.Media.InterventionType interventionType = 2;
+}

+ 3 - 0
proto/instamadilloSupplementMessage/extra.go

@@ -0,0 +1,3 @@
+package instamadilloSupplementMessage
+
+func (*SupplementMessagePayload) IsMessageApplicationSub() {}

+ 365 - 0
proto/instamadilloTransportPayload/InstamadilloTransportPayload.pb.go

@@ -0,0 +1,365 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloTransportPayload/InstamadilloTransportPayload.proto
+
+package instamadilloTransportPayload
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	instamadilloAddMessage "go.mau.fi/whatsmeow/proto/instamadilloAddMessage"
+	instamadilloDeleteMessage "go.mau.fi/whatsmeow/proto/instamadilloDeleteMessage"
+	instamadilloSupplementMessage "go.mau.fi/whatsmeow/proto/instamadilloSupplementMessage"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type PayloadCreator int32
+
+const (
+	PayloadCreator_PAYLOAD_CREATOR_UNSPECIFIED PayloadCreator = 0
+	PayloadCreator_PAYLOAD_CREATOR_IGIOS       PayloadCreator = 1
+	PayloadCreator_PAYLOAD_CREATOR_IG4A        PayloadCreator = 2
+	PayloadCreator_PAYLOAD_CREATOR_WWW         PayloadCreator = 3
+	PayloadCreator_PAYLOAD_CREATOR_IGLITE      PayloadCreator = 4
+)
+
+// Enum value maps for PayloadCreator.
+var (
+	PayloadCreator_name = map[int32]string{
+		0: "PAYLOAD_CREATOR_UNSPECIFIED",
+		1: "PAYLOAD_CREATOR_IGIOS",
+		2: "PAYLOAD_CREATOR_IG4A",
+		3: "PAYLOAD_CREATOR_WWW",
+		4: "PAYLOAD_CREATOR_IGLITE",
+	}
+	PayloadCreator_value = map[string]int32{
+		"PAYLOAD_CREATOR_UNSPECIFIED": 0,
+		"PAYLOAD_CREATOR_IGIOS":       1,
+		"PAYLOAD_CREATOR_IG4A":        2,
+		"PAYLOAD_CREATOR_WWW":         3,
+		"PAYLOAD_CREATOR_IGLITE":      4,
+	}
+)
+
+func (x PayloadCreator) Enum() *PayloadCreator {
+	p := new(PayloadCreator)
+	*p = x
+	return p
+}
+
+func (x PayloadCreator) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (PayloadCreator) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_enumTypes[0].Descriptor()
+}
+
+func (PayloadCreator) Type() protoreflect.EnumType {
+	return &file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_enumTypes[0]
+}
+
+func (x PayloadCreator) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *PayloadCreator) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = PayloadCreator(num)
+	return nil
+}
+
+// Deprecated: Use PayloadCreator.Descriptor instead.
+func (PayloadCreator) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescGZIP(), []int{0}
+}
+
+type TransportPayload struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to TransportPayload:
+	//
+	//	*TransportPayload_Add
+	//	*TransportPayload_Delete
+	//	*TransportPayload_Supplement
+	TransportPayload isTransportPayload_TransportPayload `protobuf_oneof:"transportPayload"`
+	Franking         *Franking                           `protobuf:"bytes,4,opt,name=franking" json:"franking,omitempty"`
+	OpenEb           *bool                               `protobuf:"varint,5,opt,name=openEb" json:"openEb,omitempty"`
+	IsE2EeAttributed *bool                               `protobuf:"varint,6,opt,name=isE2EeAttributed" json:"isE2EeAttributed,omitempty"`
+	PayloadCreator   *PayloadCreator                     `protobuf:"varint,7,opt,name=payloadCreator,enum=InstamadilloTransportPayload.PayloadCreator" json:"payloadCreator,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *TransportPayload) Reset() {
+	*x = TransportPayload{}
+	mi := &file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *TransportPayload) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TransportPayload) ProtoMessage() {}
+
+func (x *TransportPayload) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TransportPayload.ProtoReflect.Descriptor instead.
+func (*TransportPayload) Descriptor() ([]byte, []int) {
+	return file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TransportPayload) GetTransportPayload() isTransportPayload_TransportPayload {
+	if x != nil {
+		return x.TransportPayload
+	}
+	return nil
+}
+
+func (x *TransportPayload) GetAdd() *instamadilloAddMessage.AddMessagePayload {
+	if x != nil {
+		if x, ok := x.TransportPayload.(*TransportPayload_Add); ok {
+			return x.Add
+		}
+	}
+	return nil
+}
+
+func (x *TransportPayload) GetDelete() *instamadilloDeleteMessage.DeleteMessagePayload {
+	if x != nil {
+		if x, ok := x.TransportPayload.(*TransportPayload_Delete); ok {
+			return x.Delete
+		}
+	}
+	return nil
+}
+
+func (x *TransportPayload) GetSupplement() *instamadilloSupplementMessage.SupplementMessagePayload {
+	if x != nil {
+		if x, ok := x.TransportPayload.(*TransportPayload_Supplement); ok {
+			return x.Supplement
+		}
+	}
+	return nil
+}
+
+func (x *TransportPayload) GetFranking() *Franking {
+	if x != nil {
+		return x.Franking
+	}
+	return nil
+}
+
+func (x *TransportPayload) GetOpenEb() bool {
+	if x != nil && x.OpenEb != nil {
+		return *x.OpenEb
+	}
+	return false
+}
+
+func (x *TransportPayload) GetIsE2EeAttributed() bool {
+	if x != nil && x.IsE2EeAttributed != nil {
+		return *x.IsE2EeAttributed
+	}
+	return false
+}
+
+func (x *TransportPayload) GetPayloadCreator() PayloadCreator {
+	if x != nil && x.PayloadCreator != nil {
+		return *x.PayloadCreator
+	}
+	return PayloadCreator_PAYLOAD_CREATOR_UNSPECIFIED
+}
+
+type isTransportPayload_TransportPayload interface {
+	isTransportPayload_TransportPayload()
+}
+
+type TransportPayload_Add struct {
+	Add *instamadilloAddMessage.AddMessagePayload `protobuf:"bytes,1,opt,name=add,oneof"`
+}
+
+type TransportPayload_Delete struct {
+	Delete *instamadilloDeleteMessage.DeleteMessagePayload `protobuf:"bytes,2,opt,name=delete,oneof"`
+}
+
+type TransportPayload_Supplement struct {
+	Supplement *instamadilloSupplementMessage.SupplementMessagePayload `protobuf:"bytes,3,opt,name=supplement,oneof"`
+}
+
+func (*TransportPayload_Add) isTransportPayload_TransportPayload() {}
+
+func (*TransportPayload_Delete) isTransportPayload_TransportPayload() {}
+
+func (*TransportPayload_Supplement) isTransportPayload_TransportPayload() {}
+
+type Franking struct {
+	state           protoimpl.MessageState `protogen:"open.v1"`
+	FrankingKey     []byte                 `protobuf:"bytes,1,opt,name=frankingKey" json:"frankingKey,omitempty"`
+	FrankingVersion *int32                 `protobuf:"varint,2,opt,name=frankingVersion" json:"frankingVersion,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *Franking) Reset() {
+	*x = Franking{}
+	mi := &file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Franking) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Franking) ProtoMessage() {}
+
+func (x *Franking) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Franking.ProtoReflect.Descriptor instead.
+func (*Franking) Descriptor() ([]byte, []int) {
+	return file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Franking) GetFrankingKey() []byte {
+	if x != nil {
+		return x.FrankingKey
+	}
+	return nil
+}
+
+func (x *Franking) GetFrankingVersion() int32 {
+	if x != nil && x.FrankingVersion != nil {
+		return *x.FrankingVersion
+	}
+	return 0
+}
+
+var File_instamadilloTransportPayload_InstamadilloTransportPayload_proto protoreflect.FileDescriptor
+
+const file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDesc = "" +
+	"\n" +
+	"?instamadilloTransportPayload/InstamadilloTransportPayload.proto\x12\x1cInstamadilloTransportPayload\x1a3instamadilloAddMessage/InstamadilloAddMessage.proto\x1a9instamadilloDeleteMessage/InstamadilloDeleteMessage.proto\x1aAinstamadilloSupplementMessage/InstamadilloSupplementMessage.proto\"\xe9\x03\n" +
+	"\x10TransportPayload\x12=\n" +
+	"\x03add\x18\x01 \x01(\v2).InstamadilloAddMessage.AddMessagePayloadH\x00R\x03add\x12I\n" +
+	"\x06delete\x18\x02 \x01(\v2/.InstamadilloDeleteMessage.DeleteMessagePayloadH\x00R\x06delete\x12Y\n" +
+	"\n" +
+	"supplement\x18\x03 \x01(\v27.InstamadilloSupplementMessage.SupplementMessagePayloadH\x00R\n" +
+	"supplement\x12B\n" +
+	"\bfranking\x18\x04 \x01(\v2&.InstamadilloTransportPayload.FrankingR\bfranking\x12\x16\n" +
+	"\x06openEb\x18\x05 \x01(\bR\x06openEb\x12*\n" +
+	"\x10isE2EeAttributed\x18\x06 \x01(\bR\x10isE2EeAttributed\x12T\n" +
+	"\x0epayloadCreator\x18\a \x01(\x0e2,.InstamadilloTransportPayload.PayloadCreatorR\x0epayloadCreatorB\x12\n" +
+	"\x10transportPayload\"V\n" +
+	"\bFranking\x12 \n" +
+	"\vfrankingKey\x18\x01 \x01(\fR\vfrankingKey\x12(\n" +
+	"\x0ffrankingVersion\x18\x02 \x01(\x05R\x0ffrankingVersion*\x9b\x01\n" +
+	"\x0ePayloadCreator\x12\x1f\n" +
+	"\x1bPAYLOAD_CREATOR_UNSPECIFIED\x10\x00\x12\x19\n" +
+	"\x15PAYLOAD_CREATOR_IGIOS\x10\x01\x12\x18\n" +
+	"\x14PAYLOAD_CREATOR_IG4A\x10\x02\x12\x17\n" +
+	"\x13PAYLOAD_CREATOR_WWW\x10\x03\x12\x1a\n" +
+	"\x16PAYLOAD_CREATOR_IGLITE\x10\x04B8Z6go.mau.fi/whatsmeow/proto/instamadilloTransportPayload"
+
+var (
+	file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescOnce sync.Once
+	file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescData []byte
+)
+
+func file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescGZIP() []byte {
+	file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescOnce.Do(func() {
+		file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDesc), len(file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDesc)))
+	})
+	return file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDescData
+}
+
+var file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_goTypes = []any{
+	(PayloadCreator)(0),                                            // 0: InstamadilloTransportPayload.PayloadCreator
+	(*TransportPayload)(nil),                                       // 1: InstamadilloTransportPayload.TransportPayload
+	(*Franking)(nil),                                               // 2: InstamadilloTransportPayload.Franking
+	(*instamadilloAddMessage.AddMessagePayload)(nil),               // 3: InstamadilloAddMessage.AddMessagePayload
+	(*instamadilloDeleteMessage.DeleteMessagePayload)(nil),         // 4: InstamadilloDeleteMessage.DeleteMessagePayload
+	(*instamadilloSupplementMessage.SupplementMessagePayload)(nil), // 5: InstamadilloSupplementMessage.SupplementMessagePayload
+}
+var file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_depIdxs = []int32{
+	3, // 0: InstamadilloTransportPayload.TransportPayload.add:type_name -> InstamadilloAddMessage.AddMessagePayload
+	4, // 1: InstamadilloTransportPayload.TransportPayload.delete:type_name -> InstamadilloDeleteMessage.DeleteMessagePayload
+	5, // 2: InstamadilloTransportPayload.TransportPayload.supplement:type_name -> InstamadilloSupplementMessage.SupplementMessagePayload
+	2, // 3: InstamadilloTransportPayload.TransportPayload.franking:type_name -> InstamadilloTransportPayload.Franking
+	0, // 4: InstamadilloTransportPayload.TransportPayload.payloadCreator:type_name -> InstamadilloTransportPayload.PayloadCreator
+	5, // [5:5] is the sub-list for method output_type
+	5, // [5:5] is the sub-list for method input_type
+	5, // [5:5] is the sub-list for extension type_name
+	5, // [5:5] is the sub-list for extension extendee
+	0, // [0:5] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_init() }
+func file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_init() {
+	if File_instamadilloTransportPayload_InstamadilloTransportPayload_proto != nil {
+		return
+	}
+	file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_msgTypes[0].OneofWrappers = []any{
+		(*TransportPayload_Add)(nil),
+		(*TransportPayload_Delete)(nil),
+		(*TransportPayload_Supplement)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDesc), len(file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_rawDesc)),
+			NumEnums:      1,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_goTypes,
+		DependencyIndexes: file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_depIdxs,
+		EnumInfos:         file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_enumTypes,
+		MessageInfos:      file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_msgTypes,
+	}.Build()
+	File_instamadilloTransportPayload_InstamadilloTransportPayload_proto = out.File
+	file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_goTypes = nil
+	file_instamadilloTransportPayload_InstamadilloTransportPayload_proto_depIdxs = nil
+}

+ 33 - 0
proto/instamadilloTransportPayload/InstamadilloTransportPayload.proto

@@ -0,0 +1,33 @@
+syntax = "proto2";
+package InstamadilloTransportPayload;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloTransportPayload";
+
+import "instamadilloAddMessage/InstamadilloAddMessage.proto";
+import "instamadilloDeleteMessage/InstamadilloDeleteMessage.proto";
+import "instamadilloSupplementMessage/InstamadilloSupplementMessage.proto";
+
+enum PayloadCreator {
+	PAYLOAD_CREATOR_UNSPECIFIED = 0;
+	PAYLOAD_CREATOR_IGIOS = 1;
+	PAYLOAD_CREATOR_IG4A = 2;
+	PAYLOAD_CREATOR_WWW = 3;
+	PAYLOAD_CREATOR_IGLITE = 4;
+}
+
+message TransportPayload {
+	oneof transportPayload {
+		InstamadilloAddMessage.AddMessagePayload add = 1;
+		InstamadilloDeleteMessage.DeleteMessagePayload delete = 2;
+		InstamadilloSupplementMessage.SupplementMessagePayload supplement = 3;
+	}
+
+	optional Franking franking = 4;
+	optional bool openEb = 5;
+	optional bool isE2EeAttributed = 6;
+	optional PayloadCreator payloadCreator = 7;
+}
+
+message Franking {
+	optional bytes frankingKey = 1;
+	optional int32 frankingVersion = 2;
+}

+ 1238 - 0
proto/instamadilloXmaContentRef/InstamadilloXmaContentRef.pb.go

@@ -0,0 +1,1238 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: instamadilloXmaContentRef/InstamadilloXmaContentRef.proto
+
+package instamadilloXmaContentRef
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type XmaActionType int32
+
+const (
+	XmaActionType_XMA_ACTION_TYPE_UNSPECIFIED XmaActionType = 0
+	XmaActionType_XMA_ACTION_TYPE_SHARE       XmaActionType = 1
+	XmaActionType_XMA_ACTION_TYPE_REPLY       XmaActionType = 2
+	XmaActionType_XMA_ACTION_TYPE_REACT       XmaActionType = 3
+	XmaActionType_XMA_ACTION_TYPE_MENTION     XmaActionType = 4
+)
+
+// Enum value maps for XmaActionType.
+var (
+	XmaActionType_name = map[int32]string{
+		0: "XMA_ACTION_TYPE_UNSPECIFIED",
+		1: "XMA_ACTION_TYPE_SHARE",
+		2: "XMA_ACTION_TYPE_REPLY",
+		3: "XMA_ACTION_TYPE_REACT",
+		4: "XMA_ACTION_TYPE_MENTION",
+	}
+	XmaActionType_value = map[string]int32{
+		"XMA_ACTION_TYPE_UNSPECIFIED": 0,
+		"XMA_ACTION_TYPE_SHARE":       1,
+		"XMA_ACTION_TYPE_REPLY":       2,
+		"XMA_ACTION_TYPE_REACT":       3,
+		"XMA_ACTION_TYPE_MENTION":     4,
+	}
+)
+
+func (x XmaActionType) Enum() *XmaActionType {
+	p := new(XmaActionType)
+	*p = x
+	return p
+}
+
+func (x XmaActionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (XmaActionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes[0].Descriptor()
+}
+
+func (XmaActionType) Type() protoreflect.EnumType {
+	return &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes[0]
+}
+
+func (x XmaActionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *XmaActionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = XmaActionType(num)
+	return nil
+}
+
+// Deprecated: Use XmaActionType.Descriptor instead.
+func (XmaActionType) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{0}
+}
+
+type ReceiverFetchContentType int32
+
+const (
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_UNSPECIFIED     ReceiverFetchContentType = 0
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_NOTE            ReceiverFetchContentType = 1
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_STORY           ReceiverFetchContentType = 2
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_PROFILE         ReceiverFetchContentType = 3
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_CLIP            ReceiverFetchContentType = 4
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_FEED            ReceiverFetchContentType = 5
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_LIVE            ReceiverFetchContentType = 6
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_COMMENT         ReceiverFetchContentType = 7
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_LOCATION_SHARE  ReceiverFetchContentType = 8
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_REELS_AUDIO     ReceiverFetchContentType = 9
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_MEDIA_NOTE      ReceiverFetchContentType = 10
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_STORY_HIGHLIGHT ReceiverFetchContentType = 11
+	ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_SOCIAL_CONTEXT  ReceiverFetchContentType = 12
+)
+
+// Enum value maps for ReceiverFetchContentType.
+var (
+	ReceiverFetchContentType_name = map[int32]string{
+		0:  "RECEIVER_FETCH_CONTENT_TYPE_UNSPECIFIED",
+		1:  "RECEIVER_FETCH_CONTENT_TYPE_NOTE",
+		2:  "RECEIVER_FETCH_CONTENT_TYPE_STORY",
+		3:  "RECEIVER_FETCH_CONTENT_TYPE_PROFILE",
+		4:  "RECEIVER_FETCH_CONTENT_TYPE_CLIP",
+		5:  "RECEIVER_FETCH_CONTENT_TYPE_FEED",
+		6:  "RECEIVER_FETCH_CONTENT_TYPE_LIVE",
+		7:  "RECEIVER_FETCH_CONTENT_TYPE_COMMENT",
+		8:  "RECEIVER_FETCH_CONTENT_TYPE_LOCATION_SHARE",
+		9:  "RECEIVER_FETCH_CONTENT_TYPE_REELS_AUDIO",
+		10: "RECEIVER_FETCH_CONTENT_TYPE_MEDIA_NOTE",
+		11: "RECEIVER_FETCH_CONTENT_TYPE_STORY_HIGHLIGHT",
+		12: "RECEIVER_FETCH_CONTENT_TYPE_SOCIAL_CONTEXT",
+	}
+	ReceiverFetchContentType_value = map[string]int32{
+		"RECEIVER_FETCH_CONTENT_TYPE_UNSPECIFIED":     0,
+		"RECEIVER_FETCH_CONTENT_TYPE_NOTE":            1,
+		"RECEIVER_FETCH_CONTENT_TYPE_STORY":           2,
+		"RECEIVER_FETCH_CONTENT_TYPE_PROFILE":         3,
+		"RECEIVER_FETCH_CONTENT_TYPE_CLIP":            4,
+		"RECEIVER_FETCH_CONTENT_TYPE_FEED":            5,
+		"RECEIVER_FETCH_CONTENT_TYPE_LIVE":            6,
+		"RECEIVER_FETCH_CONTENT_TYPE_COMMENT":         7,
+		"RECEIVER_FETCH_CONTENT_TYPE_LOCATION_SHARE":  8,
+		"RECEIVER_FETCH_CONTENT_TYPE_REELS_AUDIO":     9,
+		"RECEIVER_FETCH_CONTENT_TYPE_MEDIA_NOTE":      10,
+		"RECEIVER_FETCH_CONTENT_TYPE_STORY_HIGHLIGHT": 11,
+		"RECEIVER_FETCH_CONTENT_TYPE_SOCIAL_CONTEXT":  12,
+	}
+)
+
+func (x ReceiverFetchContentType) Enum() *ReceiverFetchContentType {
+	p := new(ReceiverFetchContentType)
+	*p = x
+	return p
+}
+
+func (x ReceiverFetchContentType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ReceiverFetchContentType) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes[1].Descriptor()
+}
+
+func (ReceiverFetchContentType) Type() protoreflect.EnumType {
+	return &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes[1]
+}
+
+func (x ReceiverFetchContentType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *ReceiverFetchContentType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = ReceiverFetchContentType(num)
+	return nil
+}
+
+// Deprecated: Use ReceiverFetchContentType.Descriptor instead.
+func (ReceiverFetchContentType) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{1}
+}
+
+type MediaNoteFetchParamsMessageType int32
+
+const (
+	MediaNoteFetchParamsMessageType_MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_UNSPECIFIED MediaNoteFetchParamsMessageType = 0
+	MediaNoteFetchParamsMessageType_MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_MENTION     MediaNoteFetchParamsMessageType = 1
+	MediaNoteFetchParamsMessageType_MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_REPLY       MediaNoteFetchParamsMessageType = 2
+)
+
+// Enum value maps for MediaNoteFetchParamsMessageType.
+var (
+	MediaNoteFetchParamsMessageType_name = map[int32]string{
+		0: "MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_UNSPECIFIED",
+		1: "MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_MENTION",
+		2: "MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_REPLY",
+	}
+	MediaNoteFetchParamsMessageType_value = map[string]int32{
+		"MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_UNSPECIFIED": 0,
+		"MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_MENTION":     1,
+		"MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_REPLY":       2,
+	}
+)
+
+func (x MediaNoteFetchParamsMessageType) Enum() *MediaNoteFetchParamsMessageType {
+	p := new(MediaNoteFetchParamsMessageType)
+	*p = x
+	return p
+}
+
+func (x MediaNoteFetchParamsMessageType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (MediaNoteFetchParamsMessageType) Descriptor() protoreflect.EnumDescriptor {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes[2].Descriptor()
+}
+
+func (MediaNoteFetchParamsMessageType) Type() protoreflect.EnumType {
+	return &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes[2]
+}
+
+func (x MediaNoteFetchParamsMessageType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *MediaNoteFetchParamsMessageType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = MediaNoteFetchParamsMessageType(num)
+	return nil
+}
+
+// Deprecated: Use MediaNoteFetchParamsMessageType.Descriptor instead.
+func (MediaNoteFetchParamsMessageType) EnumDescriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{2}
+}
+
+type XmaContentRef struct {
+	state         protoimpl.MessageState       `protogen:"open.v1"`
+	ActionType    *XmaActionType               `protobuf:"varint,1,opt,name=actionType,enum=InstamadilloXmaContentRef.XmaActionType" json:"actionType,omitempty"`
+	ContentType   *ReceiverFetchContentType    `protobuf:"varint,2,opt,name=contentType,enum=InstamadilloXmaContentRef.ReceiverFetchContentType" json:"contentType,omitempty"`
+	TargetURL     *string                      `protobuf:"bytes,3,opt,name=targetURL" json:"targetURL,omitempty"`
+	UserName      *string                      `protobuf:"bytes,4,opt,name=userName" json:"userName,omitempty"`
+	OwnerFbid     *string                      `protobuf:"bytes,5,opt,name=ownerFbid" json:"ownerFbid,omitempty"`
+	FetchParams   *ReceiverFetchXmaFetchParams `protobuf:"bytes,6,opt,name=fetchParams" json:"fetchParams,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *XmaContentRef) Reset() {
+	*x = XmaContentRef{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *XmaContentRef) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*XmaContentRef) ProtoMessage() {}
+
+func (x *XmaContentRef) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use XmaContentRef.ProtoReflect.Descriptor instead.
+func (*XmaContentRef) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *XmaContentRef) GetActionType() XmaActionType {
+	if x != nil && x.ActionType != nil {
+		return *x.ActionType
+	}
+	return XmaActionType_XMA_ACTION_TYPE_UNSPECIFIED
+}
+
+func (x *XmaContentRef) GetContentType() ReceiverFetchContentType {
+	if x != nil && x.ContentType != nil {
+		return *x.ContentType
+	}
+	return ReceiverFetchContentType_RECEIVER_FETCH_CONTENT_TYPE_UNSPECIFIED
+}
+
+func (x *XmaContentRef) GetTargetURL() string {
+	if x != nil && x.TargetURL != nil {
+		return *x.TargetURL
+	}
+	return ""
+}
+
+func (x *XmaContentRef) GetUserName() string {
+	if x != nil && x.UserName != nil {
+		return *x.UserName
+	}
+	return ""
+}
+
+func (x *XmaContentRef) GetOwnerFbid() string {
+	if x != nil && x.OwnerFbid != nil {
+		return *x.OwnerFbid
+	}
+	return ""
+}
+
+func (x *XmaContentRef) GetFetchParams() *ReceiverFetchXmaFetchParams {
+	if x != nil {
+		return x.FetchParams
+	}
+	return nil
+}
+
+type ReceiverFetchXmaFetchParams struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to ReceiverFetchXmaFetchParams:
+	//
+	//	*ReceiverFetchXmaFetchParams_NoteFetchParams
+	//	*ReceiverFetchXmaFetchParams_StoryFetchParams
+	//	*ReceiverFetchXmaFetchParams_ProfileFetchParams
+	//	*ReceiverFetchXmaFetchParams_ClipFetchParams
+	//	*ReceiverFetchXmaFetchParams_FeedFetchParams
+	//	*ReceiverFetchXmaFetchParams_LiveFetchParams
+	//	*ReceiverFetchXmaFetchParams_CommentFetchParams
+	//	*ReceiverFetchXmaFetchParams_LocationShareFetchParams
+	//	*ReceiverFetchXmaFetchParams_ReelsAudioFetchParams
+	//	*ReceiverFetchXmaFetchParams_MediaNoteFetchParams
+	//	*ReceiverFetchXmaFetchParams_SocialContextFetchParams
+	ReceiverFetchXmaFetchParams isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams `protobuf_oneof:"receiverFetchXmaFetchParams"`
+	unknownFields               protoimpl.UnknownFields
+	sizeCache                   protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaFetchParams) Reset() {
+	*x = ReceiverFetchXmaFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetReceiverFetchXmaFetchParams() isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams {
+	if x != nil {
+		return x.ReceiverFetchXmaFetchParams
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetNoteFetchParams() *ReceiverFetchXmaNoteFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_NoteFetchParams); ok {
+			return x.NoteFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetStoryFetchParams() *ReceiverFetchXmaStoryFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_StoryFetchParams); ok {
+			return x.StoryFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetProfileFetchParams() *ReceiverFetchXmaProfileFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_ProfileFetchParams); ok {
+			return x.ProfileFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetClipFetchParams() *ReceiverFetchXmaClipFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_ClipFetchParams); ok {
+			return x.ClipFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetFeedFetchParams() *ReceiverFetchXmaFeedFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_FeedFetchParams); ok {
+			return x.FeedFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetLiveFetchParams() *ReceiverFetchXmaLiveFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_LiveFetchParams); ok {
+			return x.LiveFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetCommentFetchParams() *ReceiverFetchXmaCommentFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_CommentFetchParams); ok {
+			return x.CommentFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetLocationShareFetchParams() *ReceiverFetchXmaLocationShareFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_LocationShareFetchParams); ok {
+			return x.LocationShareFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetReelsAudioFetchParams() *ReceiverFetchXmaReelsAudioFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_ReelsAudioFetchParams); ok {
+			return x.ReelsAudioFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetMediaNoteFetchParams() *ReceiverFetchXmaMediaNoteFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_MediaNoteFetchParams); ok {
+			return x.MediaNoteFetchParams
+		}
+	}
+	return nil
+}
+
+func (x *ReceiverFetchXmaFetchParams) GetSocialContextFetchParams() *ReceiverFetchXmaSocialContextFetchParams {
+	if x != nil {
+		if x, ok := x.ReceiverFetchXmaFetchParams.(*ReceiverFetchXmaFetchParams_SocialContextFetchParams); ok {
+			return x.SocialContextFetchParams
+		}
+	}
+	return nil
+}
+
+type isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams interface {
+	isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams()
+}
+
+type ReceiverFetchXmaFetchParams_NoteFetchParams struct {
+	NoteFetchParams *ReceiverFetchXmaNoteFetchParams `protobuf:"bytes,1,opt,name=noteFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_StoryFetchParams struct {
+	StoryFetchParams *ReceiverFetchXmaStoryFetchParams `protobuf:"bytes,2,opt,name=storyFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_ProfileFetchParams struct {
+	ProfileFetchParams *ReceiverFetchXmaProfileFetchParams `protobuf:"bytes,3,opt,name=profileFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_ClipFetchParams struct {
+	ClipFetchParams *ReceiverFetchXmaClipFetchParams `protobuf:"bytes,4,opt,name=clipFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_FeedFetchParams struct {
+	FeedFetchParams *ReceiverFetchXmaFeedFetchParams `protobuf:"bytes,5,opt,name=feedFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_LiveFetchParams struct {
+	LiveFetchParams *ReceiverFetchXmaLiveFetchParams `protobuf:"bytes,6,opt,name=liveFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_CommentFetchParams struct {
+	CommentFetchParams *ReceiverFetchXmaCommentFetchParams `protobuf:"bytes,7,opt,name=commentFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_LocationShareFetchParams struct {
+	LocationShareFetchParams *ReceiverFetchXmaLocationShareFetchParams `protobuf:"bytes,8,opt,name=locationShareFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_ReelsAudioFetchParams struct {
+	ReelsAudioFetchParams *ReceiverFetchXmaReelsAudioFetchParams `protobuf:"bytes,9,opt,name=reelsAudioFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_MediaNoteFetchParams struct {
+	MediaNoteFetchParams *ReceiverFetchXmaMediaNoteFetchParams `protobuf:"bytes,10,opt,name=mediaNoteFetchParams,oneof"`
+}
+
+type ReceiverFetchXmaFetchParams_SocialContextFetchParams struct {
+	SocialContextFetchParams *ReceiverFetchXmaSocialContextFetchParams `protobuf:"bytes,11,opt,name=socialContextFetchParams,oneof"`
+}
+
+func (*ReceiverFetchXmaFetchParams_NoteFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_StoryFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_ProfileFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_ClipFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_FeedFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_LiveFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_CommentFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_LocationShareFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_ReelsAudioFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_MediaNoteFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+func (*ReceiverFetchXmaFetchParams_SocialContextFetchParams) isReceiverFetchXmaFetchParams_ReceiverFetchXmaFetchParams() {
+}
+
+type ReceiverFetchXmaNoteFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	NoteIgid      *string                `protobuf:"bytes,1,opt,name=noteIgid" json:"noteIgid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaNoteFetchParams) Reset() {
+	*x = ReceiverFetchXmaNoteFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaNoteFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaNoteFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaNoteFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaNoteFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaNoteFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ReceiverFetchXmaNoteFetchParams) GetNoteIgid() string {
+	if x != nil && x.NoteIgid != nil {
+		return *x.NoteIgid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaStoryFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	StoryIgid     *string                `protobuf:"bytes,1,opt,name=storyIgid" json:"storyIgid,omitempty"`
+	ReelID        *string                `protobuf:"bytes,2,opt,name=reelID" json:"reelID,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaStoryFetchParams) Reset() {
+	*x = ReceiverFetchXmaStoryFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaStoryFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaStoryFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaStoryFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaStoryFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaStoryFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ReceiverFetchXmaStoryFetchParams) GetStoryIgid() string {
+	if x != nil && x.StoryIgid != nil {
+		return *x.StoryIgid
+	}
+	return ""
+}
+
+func (x *ReceiverFetchXmaStoryFetchParams) GetReelID() string {
+	if x != nil && x.ReelID != nil {
+		return *x.ReelID
+	}
+	return ""
+}
+
+type ReceiverFetchXmaProfileFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	ProfileIgid   *string                `protobuf:"bytes,1,opt,name=profileIgid" json:"profileIgid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaProfileFetchParams) Reset() {
+	*x = ReceiverFetchXmaProfileFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaProfileFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaProfileFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaProfileFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaProfileFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaProfileFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ReceiverFetchXmaProfileFetchParams) GetProfileIgid() string {
+	if x != nil && x.ProfileIgid != nil {
+		return *x.ProfileIgid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaClipFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	MediaIgid     *string                `protobuf:"bytes,1,opt,name=mediaIgid" json:"mediaIgid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaClipFetchParams) Reset() {
+	*x = ReceiverFetchXmaClipFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaClipFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaClipFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaClipFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaClipFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaClipFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ReceiverFetchXmaClipFetchParams) GetMediaIgid() string {
+	if x != nil && x.MediaIgid != nil {
+		return *x.MediaIgid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaFeedFetchParams struct {
+	state                       protoimpl.MessageState `protogen:"open.v1"`
+	MediaIgid                   *string                `protobuf:"bytes,1,opt,name=mediaIgid" json:"mediaIgid,omitempty"`
+	CarouselShareChildMediaIgid *string                `protobuf:"bytes,2,opt,name=carouselShareChildMediaIgid" json:"carouselShareChildMediaIgid,omitempty"`
+	unknownFields               protoimpl.UnknownFields
+	sizeCache                   protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaFeedFetchParams) Reset() {
+	*x = ReceiverFetchXmaFeedFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaFeedFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaFeedFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaFeedFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaFeedFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaFeedFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ReceiverFetchXmaFeedFetchParams) GetMediaIgid() string {
+	if x != nil && x.MediaIgid != nil {
+		return *x.MediaIgid
+	}
+	return ""
+}
+
+func (x *ReceiverFetchXmaFeedFetchParams) GetCarouselShareChildMediaIgid() string {
+	if x != nil && x.CarouselShareChildMediaIgid != nil {
+		return *x.CarouselShareChildMediaIgid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaLiveFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	LiveIgid      *string                `protobuf:"bytes,1,opt,name=liveIgid" json:"liveIgid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaLiveFetchParams) Reset() {
+	*x = ReceiverFetchXmaLiveFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaLiveFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaLiveFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaLiveFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaLiveFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaLiveFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *ReceiverFetchXmaLiveFetchParams) GetLiveIgid() string {
+	if x != nil && x.LiveIgid != nil {
+		return *x.LiveIgid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaCommentFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	CommentFbid   *string                `protobuf:"bytes,1,opt,name=commentFbid" json:"commentFbid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaCommentFetchParams) Reset() {
+	*x = ReceiverFetchXmaCommentFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaCommentFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaCommentFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaCommentFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaCommentFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaCommentFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *ReceiverFetchXmaCommentFetchParams) GetCommentFbid() string {
+	if x != nil && x.CommentFbid != nil {
+		return *x.CommentFbid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaLocationShareFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	LocationIgid  *string                `protobuf:"bytes,1,opt,name=locationIgid" json:"locationIgid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaLocationShareFetchParams) Reset() {
+	*x = ReceiverFetchXmaLocationShareFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaLocationShareFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaLocationShareFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaLocationShareFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaLocationShareFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaLocationShareFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *ReceiverFetchXmaLocationShareFetchParams) GetLocationIgid() string {
+	if x != nil && x.LocationIgid != nil {
+		return *x.LocationIgid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaReelsAudioFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	AudioIgid     *string                `protobuf:"bytes,1,opt,name=audioIgid" json:"audioIgid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaReelsAudioFetchParams) Reset() {
+	*x = ReceiverFetchXmaReelsAudioFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaReelsAudioFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaReelsAudioFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaReelsAudioFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaReelsAudioFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaReelsAudioFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *ReceiverFetchXmaReelsAudioFetchParams) GetAudioIgid() string {
+	if x != nil && x.AudioIgid != nil {
+		return *x.AudioIgid
+	}
+	return ""
+}
+
+type ReceiverFetchXmaMediaNoteFetchParams struct {
+	state         protoimpl.MessageState           `protogen:"open.v1"`
+	MediaNoteIgid *string                          `protobuf:"bytes,1,opt,name=mediaNoteIgid" json:"mediaNoteIgid,omitempty"`
+	MessageType   *MediaNoteFetchParamsMessageType `protobuf:"varint,2,opt,name=messageType,enum=InstamadilloXmaContentRef.MediaNoteFetchParamsMessageType" json:"messageType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaMediaNoteFetchParams) Reset() {
+	*x = ReceiverFetchXmaMediaNoteFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaMediaNoteFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaMediaNoteFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaMediaNoteFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaMediaNoteFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaMediaNoteFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *ReceiverFetchXmaMediaNoteFetchParams) GetMediaNoteIgid() string {
+	if x != nil && x.MediaNoteIgid != nil {
+		return *x.MediaNoteIgid
+	}
+	return ""
+}
+
+func (x *ReceiverFetchXmaMediaNoteFetchParams) GetMessageType() MediaNoteFetchParamsMessageType {
+	if x != nil && x.MessageType != nil {
+		return *x.MessageType
+	}
+	return MediaNoteFetchParamsMessageType_MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_UNSPECIFIED
+}
+
+type ReceiverFetchXmaSocialContextFetchParams struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	MediaIgid     *string                `protobuf:"bytes,1,opt,name=mediaIgid" json:"mediaIgid,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ReceiverFetchXmaSocialContextFetchParams) Reset() {
+	*x = ReceiverFetchXmaSocialContextFetchParams{}
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[12]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ReceiverFetchXmaSocialContextFetchParams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReceiverFetchXmaSocialContextFetchParams) ProtoMessage() {}
+
+func (x *ReceiverFetchXmaSocialContextFetchParams) ProtoReflect() protoreflect.Message {
+	mi := &file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[12]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReceiverFetchXmaSocialContextFetchParams.ProtoReflect.Descriptor instead.
+func (*ReceiverFetchXmaSocialContextFetchParams) Descriptor() ([]byte, []int) {
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *ReceiverFetchXmaSocialContextFetchParams) GetMediaIgid() string {
+	if x != nil && x.MediaIgid != nil {
+		return *x.MediaIgid
+	}
+	return ""
+}
+
+var File_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto protoreflect.FileDescriptor
+
+const file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDesc = "" +
+	"\n" +
+	"9instamadilloXmaContentRef/InstamadilloXmaContentRef.proto\x12\x19InstamadilloXmaContentRef\"\xe2\x02\n" +
+	"\rXmaContentRef\x12H\n" +
+	"\n" +
+	"actionType\x18\x01 \x01(\x0e2(.InstamadilloXmaContentRef.XmaActionTypeR\n" +
+	"actionType\x12U\n" +
+	"\vcontentType\x18\x02 \x01(\x0e23.InstamadilloXmaContentRef.ReceiverFetchContentTypeR\vcontentType\x12\x1c\n" +
+	"\ttargetURL\x18\x03 \x01(\tR\ttargetURL\x12\x1a\n" +
+	"\buserName\x18\x04 \x01(\tR\buserName\x12\x1c\n" +
+	"\townerFbid\x18\x05 \x01(\tR\townerFbid\x12X\n" +
+	"\vfetchParams\x18\x06 \x01(\v26.InstamadilloXmaContentRef.ReceiverFetchXmaFetchParamsR\vfetchParams\"\xa2\n" +
+	"\n" +
+	"\x1bReceiverFetchXmaFetchParams\x12f\n" +
+	"\x0fnoteFetchParams\x18\x01 \x01(\v2:.InstamadilloXmaContentRef.ReceiverFetchXmaNoteFetchParamsH\x00R\x0fnoteFetchParams\x12i\n" +
+	"\x10storyFetchParams\x18\x02 \x01(\v2;.InstamadilloXmaContentRef.ReceiverFetchXmaStoryFetchParamsH\x00R\x10storyFetchParams\x12o\n" +
+	"\x12profileFetchParams\x18\x03 \x01(\v2=.InstamadilloXmaContentRef.ReceiverFetchXmaProfileFetchParamsH\x00R\x12profileFetchParams\x12f\n" +
+	"\x0fclipFetchParams\x18\x04 \x01(\v2:.InstamadilloXmaContentRef.ReceiverFetchXmaClipFetchParamsH\x00R\x0fclipFetchParams\x12f\n" +
+	"\x0ffeedFetchParams\x18\x05 \x01(\v2:.InstamadilloXmaContentRef.ReceiverFetchXmaFeedFetchParamsH\x00R\x0ffeedFetchParams\x12f\n" +
+	"\x0fliveFetchParams\x18\x06 \x01(\v2:.InstamadilloXmaContentRef.ReceiverFetchXmaLiveFetchParamsH\x00R\x0fliveFetchParams\x12o\n" +
+	"\x12commentFetchParams\x18\a \x01(\v2=.InstamadilloXmaContentRef.ReceiverFetchXmaCommentFetchParamsH\x00R\x12commentFetchParams\x12\x81\x01\n" +
+	"\x18locationShareFetchParams\x18\b \x01(\v2C.InstamadilloXmaContentRef.ReceiverFetchXmaLocationShareFetchParamsH\x00R\x18locationShareFetchParams\x12x\n" +
+	"\x15reelsAudioFetchParams\x18\t \x01(\v2@.InstamadilloXmaContentRef.ReceiverFetchXmaReelsAudioFetchParamsH\x00R\x15reelsAudioFetchParams\x12u\n" +
+	"\x14mediaNoteFetchParams\x18\n" +
+	" \x01(\v2?.InstamadilloXmaContentRef.ReceiverFetchXmaMediaNoteFetchParamsH\x00R\x14mediaNoteFetchParams\x12\x81\x01\n" +
+	"\x18socialContextFetchParams\x18\v \x01(\v2C.InstamadilloXmaContentRef.ReceiverFetchXmaSocialContextFetchParamsH\x00R\x18socialContextFetchParamsB\x1d\n" +
+	"\x1breceiverFetchXmaFetchParams\"=\n" +
+	"\x1fReceiverFetchXmaNoteFetchParams\x12\x1a\n" +
+	"\bnoteIgid\x18\x01 \x01(\tR\bnoteIgid\"X\n" +
+	" ReceiverFetchXmaStoryFetchParams\x12\x1c\n" +
+	"\tstoryIgid\x18\x01 \x01(\tR\tstoryIgid\x12\x16\n" +
+	"\x06reelID\x18\x02 \x01(\tR\x06reelID\"F\n" +
+	"\"ReceiverFetchXmaProfileFetchParams\x12 \n" +
+	"\vprofileIgid\x18\x01 \x01(\tR\vprofileIgid\"?\n" +
+	"\x1fReceiverFetchXmaClipFetchParams\x12\x1c\n" +
+	"\tmediaIgid\x18\x01 \x01(\tR\tmediaIgid\"\x81\x01\n" +
+	"\x1fReceiverFetchXmaFeedFetchParams\x12\x1c\n" +
+	"\tmediaIgid\x18\x01 \x01(\tR\tmediaIgid\x12@\n" +
+	"\x1bcarouselShareChildMediaIgid\x18\x02 \x01(\tR\x1bcarouselShareChildMediaIgid\"=\n" +
+	"\x1fReceiverFetchXmaLiveFetchParams\x12\x1a\n" +
+	"\bliveIgid\x18\x01 \x01(\tR\bliveIgid\"F\n" +
+	"\"ReceiverFetchXmaCommentFetchParams\x12 \n" +
+	"\vcommentFbid\x18\x01 \x01(\tR\vcommentFbid\"N\n" +
+	"(ReceiverFetchXmaLocationShareFetchParams\x12\"\n" +
+	"\flocationIgid\x18\x01 \x01(\tR\flocationIgid\"E\n" +
+	"%ReceiverFetchXmaReelsAudioFetchParams\x12\x1c\n" +
+	"\taudioIgid\x18\x01 \x01(\tR\taudioIgid\"\xaa\x01\n" +
+	"$ReceiverFetchXmaMediaNoteFetchParams\x12$\n" +
+	"\rmediaNoteIgid\x18\x01 \x01(\tR\rmediaNoteIgid\x12\\\n" +
+	"\vmessageType\x18\x02 \x01(\x0e2:.InstamadilloXmaContentRef.MediaNoteFetchParamsMessageTypeR\vmessageType\"H\n" +
+	"(ReceiverFetchXmaSocialContextFetchParams\x12\x1c\n" +
+	"\tmediaIgid\x18\x01 \x01(\tR\tmediaIgid*\x9e\x01\n" +
+	"\rXmaActionType\x12\x1f\n" +
+	"\x1bXMA_ACTION_TYPE_UNSPECIFIED\x10\x00\x12\x19\n" +
+	"\x15XMA_ACTION_TYPE_SHARE\x10\x01\x12\x19\n" +
+	"\x15XMA_ACTION_TYPE_REPLY\x10\x02\x12\x19\n" +
+	"\x15XMA_ACTION_TYPE_REACT\x10\x03\x12\x1b\n" +
+	"\x17XMA_ACTION_TYPE_MENTION\x10\x04*\xc2\x04\n" +
+	"\x18ReceiverFetchContentType\x12+\n" +
+	"'RECEIVER_FETCH_CONTENT_TYPE_UNSPECIFIED\x10\x00\x12$\n" +
+	" RECEIVER_FETCH_CONTENT_TYPE_NOTE\x10\x01\x12%\n" +
+	"!RECEIVER_FETCH_CONTENT_TYPE_STORY\x10\x02\x12'\n" +
+	"#RECEIVER_FETCH_CONTENT_TYPE_PROFILE\x10\x03\x12$\n" +
+	" RECEIVER_FETCH_CONTENT_TYPE_CLIP\x10\x04\x12$\n" +
+	" RECEIVER_FETCH_CONTENT_TYPE_FEED\x10\x05\x12$\n" +
+	" RECEIVER_FETCH_CONTENT_TYPE_LIVE\x10\x06\x12'\n" +
+	"#RECEIVER_FETCH_CONTENT_TYPE_COMMENT\x10\a\x12.\n" +
+	"*RECEIVER_FETCH_CONTENT_TYPE_LOCATION_SHARE\x10\b\x12+\n" +
+	"'RECEIVER_FETCH_CONTENT_TYPE_REELS_AUDIO\x10\t\x12*\n" +
+	"&RECEIVER_FETCH_CONTENT_TYPE_MEDIA_NOTE\x10\n" +
+	"\x12/\n" +
+	"+RECEIVER_FETCH_CONTENT_TYPE_STORY_HIGHLIGHT\x10\v\x12.\n" +
+	"*RECEIVER_FETCH_CONTENT_TYPE_SOCIAL_CONTEXT\x10\f*\xb9\x01\n" +
+	"\x1fMediaNoteFetchParamsMessageType\x124\n" +
+	"0MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_UNSPECIFIED\x10\x00\x120\n" +
+	",MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_MENTION\x10\x01\x12.\n" +
+	"*MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_REPLY\x10\x02B5Z3go.mau.fi/whatsmeow/proto/instamadilloXmaContentRef"
+
+var (
+	file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescOnce sync.Once
+	file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescData []byte
+)
+
+func file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescGZIP() []byte {
+	file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescOnce.Do(func() {
+		file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDesc), len(file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDesc)))
+	})
+	return file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDescData
+}
+
+var file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
+var file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_goTypes = []any{
+	(XmaActionType)(0),                               // 0: InstamadilloXmaContentRef.XmaActionType
+	(ReceiverFetchContentType)(0),                    // 1: InstamadilloXmaContentRef.ReceiverFetchContentType
+	(MediaNoteFetchParamsMessageType)(0),             // 2: InstamadilloXmaContentRef.MediaNoteFetchParamsMessageType
+	(*XmaContentRef)(nil),                            // 3: InstamadilloXmaContentRef.XmaContentRef
+	(*ReceiverFetchXmaFetchParams)(nil),              // 4: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams
+	(*ReceiverFetchXmaNoteFetchParams)(nil),          // 5: InstamadilloXmaContentRef.ReceiverFetchXmaNoteFetchParams
+	(*ReceiverFetchXmaStoryFetchParams)(nil),         // 6: InstamadilloXmaContentRef.ReceiverFetchXmaStoryFetchParams
+	(*ReceiverFetchXmaProfileFetchParams)(nil),       // 7: InstamadilloXmaContentRef.ReceiverFetchXmaProfileFetchParams
+	(*ReceiverFetchXmaClipFetchParams)(nil),          // 8: InstamadilloXmaContentRef.ReceiverFetchXmaClipFetchParams
+	(*ReceiverFetchXmaFeedFetchParams)(nil),          // 9: InstamadilloXmaContentRef.ReceiverFetchXmaFeedFetchParams
+	(*ReceiverFetchXmaLiveFetchParams)(nil),          // 10: InstamadilloXmaContentRef.ReceiverFetchXmaLiveFetchParams
+	(*ReceiverFetchXmaCommentFetchParams)(nil),       // 11: InstamadilloXmaContentRef.ReceiverFetchXmaCommentFetchParams
+	(*ReceiverFetchXmaLocationShareFetchParams)(nil), // 12: InstamadilloXmaContentRef.ReceiverFetchXmaLocationShareFetchParams
+	(*ReceiverFetchXmaReelsAudioFetchParams)(nil),    // 13: InstamadilloXmaContentRef.ReceiverFetchXmaReelsAudioFetchParams
+	(*ReceiverFetchXmaMediaNoteFetchParams)(nil),     // 14: InstamadilloXmaContentRef.ReceiverFetchXmaMediaNoteFetchParams
+	(*ReceiverFetchXmaSocialContextFetchParams)(nil), // 15: InstamadilloXmaContentRef.ReceiverFetchXmaSocialContextFetchParams
+}
+var file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_depIdxs = []int32{
+	0,  // 0: InstamadilloXmaContentRef.XmaContentRef.actionType:type_name -> InstamadilloXmaContentRef.XmaActionType
+	1,  // 1: InstamadilloXmaContentRef.XmaContentRef.contentType:type_name -> InstamadilloXmaContentRef.ReceiverFetchContentType
+	4,  // 2: InstamadilloXmaContentRef.XmaContentRef.fetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams
+	5,  // 3: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.noteFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaNoteFetchParams
+	6,  // 4: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.storyFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaStoryFetchParams
+	7,  // 5: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.profileFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaProfileFetchParams
+	8,  // 6: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.clipFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaClipFetchParams
+	9,  // 7: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.feedFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaFeedFetchParams
+	10, // 8: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.liveFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaLiveFetchParams
+	11, // 9: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.commentFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaCommentFetchParams
+	12, // 10: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.locationShareFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaLocationShareFetchParams
+	13, // 11: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.reelsAudioFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaReelsAudioFetchParams
+	14, // 12: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.mediaNoteFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaMediaNoteFetchParams
+	15, // 13: InstamadilloXmaContentRef.ReceiverFetchXmaFetchParams.socialContextFetchParams:type_name -> InstamadilloXmaContentRef.ReceiverFetchXmaSocialContextFetchParams
+	2,  // 14: InstamadilloXmaContentRef.ReceiverFetchXmaMediaNoteFetchParams.messageType:type_name -> InstamadilloXmaContentRef.MediaNoteFetchParamsMessageType
+	15, // [15:15] is the sub-list for method output_type
+	15, // [15:15] is the sub-list for method input_type
+	15, // [15:15] is the sub-list for extension type_name
+	15, // [15:15] is the sub-list for extension extendee
+	0,  // [0:15] is the sub-list for field type_name
+}
+
+func init() { file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_init() }
+func file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_init() {
+	if File_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto != nil {
+		return
+	}
+	file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes[1].OneofWrappers = []any{
+		(*ReceiverFetchXmaFetchParams_NoteFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_StoryFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_ProfileFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_ClipFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_FeedFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_LiveFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_CommentFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_LocationShareFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_ReelsAudioFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_MediaNoteFetchParams)(nil),
+		(*ReceiverFetchXmaFetchParams_SocialContextFetchParams)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDesc), len(file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_rawDesc)),
+			NumEnums:      3,
+			NumMessages:   13,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_goTypes,
+		DependencyIndexes: file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_depIdxs,
+		EnumInfos:         file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_enumTypes,
+		MessageInfos:      file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_msgTypes,
+	}.Build()
+	File_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto = out.File
+	file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_goTypes = nil
+	file_instamadilloXmaContentRef_InstamadilloXmaContentRef_proto_depIdxs = nil
+}

+ 105 - 0
proto/instamadilloXmaContentRef/InstamadilloXmaContentRef.proto

@@ -0,0 +1,105 @@
+syntax = "proto2";
+package InstamadilloXmaContentRef;
+option go_package = "go.mau.fi/whatsmeow/proto/instamadilloXmaContentRef";
+
+enum XmaActionType {
+	XMA_ACTION_TYPE_UNSPECIFIED = 0;
+	XMA_ACTION_TYPE_SHARE = 1;
+	XMA_ACTION_TYPE_REPLY = 2;
+	XMA_ACTION_TYPE_REACT = 3;
+	XMA_ACTION_TYPE_MENTION = 4;
+}
+
+enum ReceiverFetchContentType {
+	RECEIVER_FETCH_CONTENT_TYPE_UNSPECIFIED = 0;
+	RECEIVER_FETCH_CONTENT_TYPE_NOTE = 1;
+	RECEIVER_FETCH_CONTENT_TYPE_STORY = 2;
+	RECEIVER_FETCH_CONTENT_TYPE_PROFILE = 3;
+	RECEIVER_FETCH_CONTENT_TYPE_CLIP = 4;
+	RECEIVER_FETCH_CONTENT_TYPE_FEED = 5;
+	RECEIVER_FETCH_CONTENT_TYPE_LIVE = 6;
+	RECEIVER_FETCH_CONTENT_TYPE_COMMENT = 7;
+	RECEIVER_FETCH_CONTENT_TYPE_LOCATION_SHARE = 8;
+	RECEIVER_FETCH_CONTENT_TYPE_REELS_AUDIO = 9;
+	RECEIVER_FETCH_CONTENT_TYPE_MEDIA_NOTE = 10;
+	RECEIVER_FETCH_CONTENT_TYPE_STORY_HIGHLIGHT = 11;
+	RECEIVER_FETCH_CONTENT_TYPE_SOCIAL_CONTEXT = 12;
+}
+
+enum MediaNoteFetchParamsMessageType {
+	MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_UNSPECIFIED = 0;
+	MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_MENTION = 1;
+	MEDIA_NOTE_FETCH_PARAMS_MESSAGE_TYPE_REPLY = 2;
+}
+
+message XmaContentRef {
+	optional XmaActionType actionType = 1;
+	optional ReceiverFetchContentType contentType = 2;
+	optional string targetURL = 3;
+	optional string userName = 4;
+	optional string ownerFbid = 5;
+	optional ReceiverFetchXmaFetchParams fetchParams = 6;
+}
+
+message ReceiverFetchXmaFetchParams {
+	oneof receiverFetchXmaFetchParams {
+		ReceiverFetchXmaNoteFetchParams noteFetchParams = 1;
+		ReceiverFetchXmaStoryFetchParams storyFetchParams = 2;
+		ReceiverFetchXmaProfileFetchParams profileFetchParams = 3;
+		ReceiverFetchXmaClipFetchParams clipFetchParams = 4;
+		ReceiverFetchXmaFeedFetchParams feedFetchParams = 5;
+		ReceiverFetchXmaLiveFetchParams liveFetchParams = 6;
+		ReceiverFetchXmaCommentFetchParams commentFetchParams = 7;
+		ReceiverFetchXmaLocationShareFetchParams locationShareFetchParams = 8;
+		ReceiverFetchXmaReelsAudioFetchParams reelsAudioFetchParams = 9;
+		ReceiverFetchXmaMediaNoteFetchParams mediaNoteFetchParams = 10;
+		ReceiverFetchXmaSocialContextFetchParams socialContextFetchParams = 11;
+	}
+}
+
+message ReceiverFetchXmaNoteFetchParams {
+	optional string noteIgid = 1;
+}
+
+message ReceiverFetchXmaStoryFetchParams {
+	optional string storyIgid = 1;
+	optional string reelID = 2;
+}
+
+message ReceiverFetchXmaProfileFetchParams {
+	optional string profileIgid = 1;
+}
+
+message ReceiverFetchXmaClipFetchParams {
+	optional string mediaIgid = 1;
+}
+
+message ReceiverFetchXmaFeedFetchParams {
+	optional string mediaIgid = 1;
+	optional string carouselShareChildMediaIgid = 2;
+}
+
+message ReceiverFetchXmaLiveFetchParams {
+	optional string liveIgid = 1;
+}
+
+message ReceiverFetchXmaCommentFetchParams {
+	optional string commentFbid = 1;
+}
+
+message ReceiverFetchXmaLocationShareFetchParams {
+	optional string locationIgid = 1;
+}
+
+message ReceiverFetchXmaReelsAudioFetchParams {
+	optional string audioIgid = 1;
+}
+
+message ReceiverFetchXmaMediaNoteFetchParams {
+	optional string mediaNoteIgid = 1;
+	optional MediaNoteFetchParamsMessageType messageType = 2;
+}
+
+message ReceiverFetchXmaSocialContextFetchParams {
+	optional string mediaIgid = 1;
+}

+ 8756 - 0
proto/waAICommon/WAAICommon.pb.go

@@ -0,0 +1,8756 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: waAICommon/WAAICommon.proto
+
+package waAICommon
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	waCommon "go.mau.fi/whatsmeow/proto/waCommon"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type BotMetricsEntryPoint int32
+
+const (
+	BotMetricsEntryPoint_UNDEFINED_ENTRY_POINT               BotMetricsEntryPoint = 0
+	BotMetricsEntryPoint_FAVICON                             BotMetricsEntryPoint = 1
+	BotMetricsEntryPoint_CHATLIST                            BotMetricsEntryPoint = 2
+	BotMetricsEntryPoint_AISEARCH_NULL_STATE_PAPER_PLANE     BotMetricsEntryPoint = 3
+	BotMetricsEntryPoint_AISEARCH_NULL_STATE_SUGGESTION      BotMetricsEntryPoint = 4
+	BotMetricsEntryPoint_AISEARCH_TYPE_AHEAD_SUGGESTION      BotMetricsEntryPoint = 5
+	BotMetricsEntryPoint_AISEARCH_TYPE_AHEAD_PAPER_PLANE     BotMetricsEntryPoint = 6
+	BotMetricsEntryPoint_AISEARCH_TYPE_AHEAD_RESULT_CHATLIST BotMetricsEntryPoint = 7
+	BotMetricsEntryPoint_AISEARCH_TYPE_AHEAD_RESULT_MESSAGES BotMetricsEntryPoint = 8
+	BotMetricsEntryPoint_AIVOICE_SEARCH_BAR                  BotMetricsEntryPoint = 9
+	BotMetricsEntryPoint_AIVOICE_FAVICON                     BotMetricsEntryPoint = 10
+	BotMetricsEntryPoint_AISTUDIO                            BotMetricsEntryPoint = 11
+	BotMetricsEntryPoint_DEEPLINK                            BotMetricsEntryPoint = 12
+	BotMetricsEntryPoint_NOTIFICATION                        BotMetricsEntryPoint = 13
+	BotMetricsEntryPoint_PROFILE_MESSAGE_BUTTON              BotMetricsEntryPoint = 14
+	BotMetricsEntryPoint_FORWARD                             BotMetricsEntryPoint = 15
+	BotMetricsEntryPoint_APP_SHORTCUT                        BotMetricsEntryPoint = 16
+	BotMetricsEntryPoint_FF_FAMILY                           BotMetricsEntryPoint = 17
+	BotMetricsEntryPoint_AI_TAB                              BotMetricsEntryPoint = 18
+	BotMetricsEntryPoint_AI_HOME                             BotMetricsEntryPoint = 19
+	BotMetricsEntryPoint_AI_DEEPLINK_IMMERSIVE               BotMetricsEntryPoint = 20
+	BotMetricsEntryPoint_AI_DEEPLINK                         BotMetricsEntryPoint = 21
+	BotMetricsEntryPoint_META_AI_CHAT_SHORTCUT_AI_STUDIO     BotMetricsEntryPoint = 22
+	BotMetricsEntryPoint_UGC_CHAT_SHORTCUT_AI_STUDIO         BotMetricsEntryPoint = 23
+	BotMetricsEntryPoint_NEW_CHAT_AI_STUDIO                  BotMetricsEntryPoint = 24
+	BotMetricsEntryPoint_AIVOICE_FAVICON_CALL_HISTORY        BotMetricsEntryPoint = 25
+	BotMetricsEntryPoint_ASK_META_AI_CONTEXT_MENU            BotMetricsEntryPoint = 26
+	BotMetricsEntryPoint_ASK_META_AI_CONTEXT_MENU_1ON1       BotMetricsEntryPoint = 27
+	BotMetricsEntryPoint_ASK_META_AI_CONTEXT_MENU_GROUP      BotMetricsEntryPoint = 28
+	BotMetricsEntryPoint_INVOKE_META_AI_1ON1                 BotMetricsEntryPoint = 29
+	BotMetricsEntryPoint_INVOKE_META_AI_GROUP                BotMetricsEntryPoint = 30
+	BotMetricsEntryPoint_META_AI_FORWARD                     BotMetricsEntryPoint = 31
+	BotMetricsEntryPoint_NEW_CHAT_AI_CONTACT                 BotMetricsEntryPoint = 32
+	BotMetricsEntryPoint_MESSAGE_QUICK_ACTION_1_ON_1_CHAT    BotMetricsEntryPoint = 33
+	BotMetricsEntryPoint_MESSAGE_QUICK_ACTION_GROUP_CHAT     BotMetricsEntryPoint = 34
+	BotMetricsEntryPoint_ATTACHMENT_TRAY_1_ON_1_CHAT         BotMetricsEntryPoint = 35
+	BotMetricsEntryPoint_ATTACHMENT_TRAY_GROUP_CHAT          BotMetricsEntryPoint = 36
+	BotMetricsEntryPoint_ASK_META_AI_MEDIA_VIEWER_1ON1       BotMetricsEntryPoint = 37
+	BotMetricsEntryPoint_ASK_META_AI_MEDIA_VIEWER_GROUP      BotMetricsEntryPoint = 38
+)
+
+// Enum value maps for BotMetricsEntryPoint.
+var (
+	BotMetricsEntryPoint_name = map[int32]string{
+		0:  "UNDEFINED_ENTRY_POINT",
+		1:  "FAVICON",
+		2:  "CHATLIST",
+		3:  "AISEARCH_NULL_STATE_PAPER_PLANE",
+		4:  "AISEARCH_NULL_STATE_SUGGESTION",
+		5:  "AISEARCH_TYPE_AHEAD_SUGGESTION",
+		6:  "AISEARCH_TYPE_AHEAD_PAPER_PLANE",
+		7:  "AISEARCH_TYPE_AHEAD_RESULT_CHATLIST",
+		8:  "AISEARCH_TYPE_AHEAD_RESULT_MESSAGES",
+		9:  "AIVOICE_SEARCH_BAR",
+		10: "AIVOICE_FAVICON",
+		11: "AISTUDIO",
+		12: "DEEPLINK",
+		13: "NOTIFICATION",
+		14: "PROFILE_MESSAGE_BUTTON",
+		15: "FORWARD",
+		16: "APP_SHORTCUT",
+		17: "FF_FAMILY",
+		18: "AI_TAB",
+		19: "AI_HOME",
+		20: "AI_DEEPLINK_IMMERSIVE",
+		21: "AI_DEEPLINK",
+		22: "META_AI_CHAT_SHORTCUT_AI_STUDIO",
+		23: "UGC_CHAT_SHORTCUT_AI_STUDIO",
+		24: "NEW_CHAT_AI_STUDIO",
+		25: "AIVOICE_FAVICON_CALL_HISTORY",
+		26: "ASK_META_AI_CONTEXT_MENU",
+		27: "ASK_META_AI_CONTEXT_MENU_1ON1",
+		28: "ASK_META_AI_CONTEXT_MENU_GROUP",
+		29: "INVOKE_META_AI_1ON1",
+		30: "INVOKE_META_AI_GROUP",
+		31: "META_AI_FORWARD",
+		32: "NEW_CHAT_AI_CONTACT",
+		33: "MESSAGE_QUICK_ACTION_1_ON_1_CHAT",
+		34: "MESSAGE_QUICK_ACTION_GROUP_CHAT",
+		35: "ATTACHMENT_TRAY_1_ON_1_CHAT",
+		36: "ATTACHMENT_TRAY_GROUP_CHAT",
+		37: "ASK_META_AI_MEDIA_VIEWER_1ON1",
+		38: "ASK_META_AI_MEDIA_VIEWER_GROUP",
+	}
+	BotMetricsEntryPoint_value = map[string]int32{
+		"UNDEFINED_ENTRY_POINT":               0,
+		"FAVICON":                             1,
+		"CHATLIST":                            2,
+		"AISEARCH_NULL_STATE_PAPER_PLANE":     3,
+		"AISEARCH_NULL_STATE_SUGGESTION":      4,
+		"AISEARCH_TYPE_AHEAD_SUGGESTION":      5,
+		"AISEARCH_TYPE_AHEAD_PAPER_PLANE":     6,
+		"AISEARCH_TYPE_AHEAD_RESULT_CHATLIST": 7,
+		"AISEARCH_TYPE_AHEAD_RESULT_MESSAGES": 8,
+		"AIVOICE_SEARCH_BAR":                  9,
+		"AIVOICE_FAVICON":                     10,
+		"AISTUDIO":                            11,
+		"DEEPLINK":                            12,
+		"NOTIFICATION":                        13,
+		"PROFILE_MESSAGE_BUTTON":              14,
+		"FORWARD":                             15,
+		"APP_SHORTCUT":                        16,
+		"FF_FAMILY":                           17,
+		"AI_TAB":                              18,
+		"AI_HOME":                             19,
+		"AI_DEEPLINK_IMMERSIVE":               20,
+		"AI_DEEPLINK":                         21,
+		"META_AI_CHAT_SHORTCUT_AI_STUDIO":     22,
+		"UGC_CHAT_SHORTCUT_AI_STUDIO":         23,
+		"NEW_CHAT_AI_STUDIO":                  24,
+		"AIVOICE_FAVICON_CALL_HISTORY":        25,
+		"ASK_META_AI_CONTEXT_MENU":            26,
+		"ASK_META_AI_CONTEXT_MENU_1ON1":       27,
+		"ASK_META_AI_CONTEXT_MENU_GROUP":      28,
+		"INVOKE_META_AI_1ON1":                 29,
+		"INVOKE_META_AI_GROUP":                30,
+		"META_AI_FORWARD":                     31,
+		"NEW_CHAT_AI_CONTACT":                 32,
+		"MESSAGE_QUICK_ACTION_1_ON_1_CHAT":    33,
+		"MESSAGE_QUICK_ACTION_GROUP_CHAT":     34,
+		"ATTACHMENT_TRAY_1_ON_1_CHAT":         35,
+		"ATTACHMENT_TRAY_GROUP_CHAT":          36,
+		"ASK_META_AI_MEDIA_VIEWER_1ON1":       37,
+		"ASK_META_AI_MEDIA_VIEWER_GROUP":      38,
+	}
+)
+
+func (x BotMetricsEntryPoint) Enum() *BotMetricsEntryPoint {
+	p := new(BotMetricsEntryPoint)
+	*p = x
+	return p
+}
+
+func (x BotMetricsEntryPoint) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotMetricsEntryPoint) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[0].Descriptor()
+}
+
+func (BotMetricsEntryPoint) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[0]
+}
+
+func (x BotMetricsEntryPoint) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotMetricsEntryPoint) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotMetricsEntryPoint(num)
+	return nil
+}
+
+// Deprecated: Use BotMetricsEntryPoint.Descriptor instead.
+func (BotMetricsEntryPoint) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{0}
+}
+
+type BotMetricsThreadEntryPoint int32
+
+const (
+	BotMetricsThreadEntryPoint_AI_TAB_THREAD                   BotMetricsThreadEntryPoint = 1
+	BotMetricsThreadEntryPoint_AI_HOME_THREAD                  BotMetricsThreadEntryPoint = 2
+	BotMetricsThreadEntryPoint_AI_DEEPLINK_IMMERSIVE_THREAD    BotMetricsThreadEntryPoint = 3
+	BotMetricsThreadEntryPoint_AI_DEEPLINK_THREAD              BotMetricsThreadEntryPoint = 4
+	BotMetricsThreadEntryPoint_ASK_META_AI_CONTEXT_MENU_THREAD BotMetricsThreadEntryPoint = 5
+)
+
+// Enum value maps for BotMetricsThreadEntryPoint.
+var (
+	BotMetricsThreadEntryPoint_name = map[int32]string{
+		1: "AI_TAB_THREAD",
+		2: "AI_HOME_THREAD",
+		3: "AI_DEEPLINK_IMMERSIVE_THREAD",
+		4: "AI_DEEPLINK_THREAD",
+		5: "ASK_META_AI_CONTEXT_MENU_THREAD",
+	}
+	BotMetricsThreadEntryPoint_value = map[string]int32{
+		"AI_TAB_THREAD":                   1,
+		"AI_HOME_THREAD":                  2,
+		"AI_DEEPLINK_IMMERSIVE_THREAD":    3,
+		"AI_DEEPLINK_THREAD":              4,
+		"ASK_META_AI_CONTEXT_MENU_THREAD": 5,
+	}
+)
+
+func (x BotMetricsThreadEntryPoint) Enum() *BotMetricsThreadEntryPoint {
+	p := new(BotMetricsThreadEntryPoint)
+	*p = x
+	return p
+}
+
+func (x BotMetricsThreadEntryPoint) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotMetricsThreadEntryPoint) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[1].Descriptor()
+}
+
+func (BotMetricsThreadEntryPoint) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[1]
+}
+
+func (x BotMetricsThreadEntryPoint) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotMetricsThreadEntryPoint) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotMetricsThreadEntryPoint(num)
+	return nil
+}
+
+// Deprecated: Use BotMetricsThreadEntryPoint.Descriptor instead.
+func (BotMetricsThreadEntryPoint) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{1}
+}
+
+type BotSessionSource int32
+
+const (
+	BotSessionSource_NONE               BotSessionSource = 0
+	BotSessionSource_NULL_STATE         BotSessionSource = 1
+	BotSessionSource_TYPEAHEAD          BotSessionSource = 2
+	BotSessionSource_USER_INPUT         BotSessionSource = 3
+	BotSessionSource_EMU_FLASH          BotSessionSource = 4
+	BotSessionSource_EMU_FLASH_FOLLOWUP BotSessionSource = 5
+	BotSessionSource_VOICE              BotSessionSource = 6
+)
+
+// Enum value maps for BotSessionSource.
+var (
+	BotSessionSource_name = map[int32]string{
+		0: "NONE",
+		1: "NULL_STATE",
+		2: "TYPEAHEAD",
+		3: "USER_INPUT",
+		4: "EMU_FLASH",
+		5: "EMU_FLASH_FOLLOWUP",
+		6: "VOICE",
+	}
+	BotSessionSource_value = map[string]int32{
+		"NONE":               0,
+		"NULL_STATE":         1,
+		"TYPEAHEAD":          2,
+		"USER_INPUT":         3,
+		"EMU_FLASH":          4,
+		"EMU_FLASH_FOLLOWUP": 5,
+		"VOICE":              6,
+	}
+)
+
+func (x BotSessionSource) Enum() *BotSessionSource {
+	p := new(BotSessionSource)
+	*p = x
+	return p
+}
+
+func (x BotSessionSource) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotSessionSource) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[2].Descriptor()
+}
+
+func (BotSessionSource) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[2]
+}
+
+func (x BotSessionSource) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotSessionSource) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotSessionSource(num)
+	return nil
+}
+
+// Deprecated: Use BotSessionSource.Descriptor instead.
+func (BotSessionSource) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{2}
+}
+
+type AIRichResponseMessageType int32
+
+const (
+	AIRichResponseMessageType_AI_RICH_RESPONSE_TYPE_UNKNOWN  AIRichResponseMessageType = 0
+	AIRichResponseMessageType_AI_RICH_RESPONSE_TYPE_STANDARD AIRichResponseMessageType = 1
+)
+
+// Enum value maps for AIRichResponseMessageType.
+var (
+	AIRichResponseMessageType_name = map[int32]string{
+		0: "AI_RICH_RESPONSE_TYPE_UNKNOWN",
+		1: "AI_RICH_RESPONSE_TYPE_STANDARD",
+	}
+	AIRichResponseMessageType_value = map[string]int32{
+		"AI_RICH_RESPONSE_TYPE_UNKNOWN":  0,
+		"AI_RICH_RESPONSE_TYPE_STANDARD": 1,
+	}
+)
+
+func (x AIRichResponseMessageType) Enum() *AIRichResponseMessageType {
+	p := new(AIRichResponseMessageType)
+	*p = x
+	return p
+}
+
+func (x AIRichResponseMessageType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIRichResponseMessageType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[3].Descriptor()
+}
+
+func (AIRichResponseMessageType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[3]
+}
+
+func (x AIRichResponseMessageType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIRichResponseMessageType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIRichResponseMessageType(num)
+	return nil
+}
+
+// Deprecated: Use AIRichResponseMessageType.Descriptor instead.
+func (AIRichResponseMessageType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{3}
+}
+
+type AIRichResponseSubMessageType int32
+
+const (
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_UNKNOWN       AIRichResponseSubMessageType = 0
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_GRID_IMAGE    AIRichResponseSubMessageType = 1
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_TEXT          AIRichResponseSubMessageType = 2
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_INLINE_IMAGE  AIRichResponseSubMessageType = 3
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_TABLE         AIRichResponseSubMessageType = 4
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_CODE          AIRichResponseSubMessageType = 5
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_DYNAMIC       AIRichResponseSubMessageType = 6
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_MAP           AIRichResponseSubMessageType = 7
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_LATEX         AIRichResponseSubMessageType = 8
+	AIRichResponseSubMessageType_AI_RICH_RESPONSE_CONTENT_ITEMS AIRichResponseSubMessageType = 9
+)
+
+// Enum value maps for AIRichResponseSubMessageType.
+var (
+	AIRichResponseSubMessageType_name = map[int32]string{
+		0: "AI_RICH_RESPONSE_UNKNOWN",
+		1: "AI_RICH_RESPONSE_GRID_IMAGE",
+		2: "AI_RICH_RESPONSE_TEXT",
+		3: "AI_RICH_RESPONSE_INLINE_IMAGE",
+		4: "AI_RICH_RESPONSE_TABLE",
+		5: "AI_RICH_RESPONSE_CODE",
+		6: "AI_RICH_RESPONSE_DYNAMIC",
+		7: "AI_RICH_RESPONSE_MAP",
+		8: "AI_RICH_RESPONSE_LATEX",
+		9: "AI_RICH_RESPONSE_CONTENT_ITEMS",
+	}
+	AIRichResponseSubMessageType_value = map[string]int32{
+		"AI_RICH_RESPONSE_UNKNOWN":       0,
+		"AI_RICH_RESPONSE_GRID_IMAGE":    1,
+		"AI_RICH_RESPONSE_TEXT":          2,
+		"AI_RICH_RESPONSE_INLINE_IMAGE":  3,
+		"AI_RICH_RESPONSE_TABLE":         4,
+		"AI_RICH_RESPONSE_CODE":          5,
+		"AI_RICH_RESPONSE_DYNAMIC":       6,
+		"AI_RICH_RESPONSE_MAP":           7,
+		"AI_RICH_RESPONSE_LATEX":         8,
+		"AI_RICH_RESPONSE_CONTENT_ITEMS": 9,
+	}
+)
+
+func (x AIRichResponseSubMessageType) Enum() *AIRichResponseSubMessageType {
+	p := new(AIRichResponseSubMessageType)
+	*p = x
+	return p
+}
+
+func (x AIRichResponseSubMessageType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIRichResponseSubMessageType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[4].Descriptor()
+}
+
+func (AIRichResponseSubMessageType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[4]
+}
+
+func (x AIRichResponseSubMessageType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIRichResponseSubMessageType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIRichResponseSubMessageType(num)
+	return nil
+}
+
+// Deprecated: Use AIRichResponseSubMessageType.Descriptor instead.
+func (AIRichResponseSubMessageType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{4}
+}
+
+type SessionTransparencyType int32
+
+const (
+	SessionTransparencyType_UNKNOWN_TYPE            SessionTransparencyType = 0
+	SessionTransparencyType_NY_AI_SAFETY_DISCLAIMER SessionTransparencyType = 1
+)
+
+// Enum value maps for SessionTransparencyType.
+var (
+	SessionTransparencyType_name = map[int32]string{
+		0: "UNKNOWN_TYPE",
+		1: "NY_AI_SAFETY_DISCLAIMER",
+	}
+	SessionTransparencyType_value = map[string]int32{
+		"UNKNOWN_TYPE":            0,
+		"NY_AI_SAFETY_DISCLAIMER": 1,
+	}
+)
+
+func (x SessionTransparencyType) Enum() *SessionTransparencyType {
+	p := new(SessionTransparencyType)
+	*p = x
+	return p
+}
+
+func (x SessionTransparencyType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SessionTransparencyType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[5].Descriptor()
+}
+
+func (SessionTransparencyType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[5]
+}
+
+func (x SessionTransparencyType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *SessionTransparencyType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = SessionTransparencyType(num)
+	return nil
+}
+
+// Deprecated: Use SessionTransparencyType.Descriptor instead.
+func (SessionTransparencyType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{5}
+}
+
+type BotPluginMetadata_PluginType int32
+
+const (
+	BotPluginMetadata_UNKNOWN_PLUGIN BotPluginMetadata_PluginType = 0
+	BotPluginMetadata_REELS          BotPluginMetadata_PluginType = 1
+	BotPluginMetadata_SEARCH         BotPluginMetadata_PluginType = 2
+)
+
+// Enum value maps for BotPluginMetadata_PluginType.
+var (
+	BotPluginMetadata_PluginType_name = map[int32]string{
+		0: "UNKNOWN_PLUGIN",
+		1: "REELS",
+		2: "SEARCH",
+	}
+	BotPluginMetadata_PluginType_value = map[string]int32{
+		"UNKNOWN_PLUGIN": 0,
+		"REELS":          1,
+		"SEARCH":         2,
+	}
+)
+
+func (x BotPluginMetadata_PluginType) Enum() *BotPluginMetadata_PluginType {
+	p := new(BotPluginMetadata_PluginType)
+	*p = x
+	return p
+}
+
+func (x BotPluginMetadata_PluginType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotPluginMetadata_PluginType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[6].Descriptor()
+}
+
+func (BotPluginMetadata_PluginType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[6]
+}
+
+func (x BotPluginMetadata_PluginType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotPluginMetadata_PluginType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotPluginMetadata_PluginType(num)
+	return nil
+}
+
+// Deprecated: Use BotPluginMetadata_PluginType.Descriptor instead.
+func (BotPluginMetadata_PluginType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{0, 0}
+}
+
+type BotPluginMetadata_SearchProvider int32
+
+const (
+	BotPluginMetadata_UNKNOWN BotPluginMetadata_SearchProvider = 0
+	BotPluginMetadata_BING    BotPluginMetadata_SearchProvider = 1
+	BotPluginMetadata_GOOGLE  BotPluginMetadata_SearchProvider = 2
+	BotPluginMetadata_SUPPORT BotPluginMetadata_SearchProvider = 3
+)
+
+// Enum value maps for BotPluginMetadata_SearchProvider.
+var (
+	BotPluginMetadata_SearchProvider_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "BING",
+		2: "GOOGLE",
+		3: "SUPPORT",
+	}
+	BotPluginMetadata_SearchProvider_value = map[string]int32{
+		"UNKNOWN": 0,
+		"BING":    1,
+		"GOOGLE":  2,
+		"SUPPORT": 3,
+	}
+)
+
+func (x BotPluginMetadata_SearchProvider) Enum() *BotPluginMetadata_SearchProvider {
+	p := new(BotPluginMetadata_SearchProvider)
+	*p = x
+	return p
+}
+
+func (x BotPluginMetadata_SearchProvider) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotPluginMetadata_SearchProvider) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[7].Descriptor()
+}
+
+func (BotPluginMetadata_SearchProvider) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[7]
+}
+
+func (x BotPluginMetadata_SearchProvider) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotPluginMetadata_SearchProvider) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotPluginMetadata_SearchProvider(num)
+	return nil
+}
+
+// Deprecated: Use BotPluginMetadata_SearchProvider.Descriptor instead.
+func (BotPluginMetadata_SearchProvider) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{0, 1}
+}
+
+type BotLinkedAccount_BotLinkedAccountType int32
+
+const (
+	BotLinkedAccount_BOT_LINKED_ACCOUNT_TYPE_1P BotLinkedAccount_BotLinkedAccountType = 0
+)
+
+// Enum value maps for BotLinkedAccount_BotLinkedAccountType.
+var (
+	BotLinkedAccount_BotLinkedAccountType_name = map[int32]string{
+		0: "BOT_LINKED_ACCOUNT_TYPE_1P",
+	}
+	BotLinkedAccount_BotLinkedAccountType_value = map[string]int32{
+		"BOT_LINKED_ACCOUNT_TYPE_1P": 0,
+	}
+)
+
+func (x BotLinkedAccount_BotLinkedAccountType) Enum() *BotLinkedAccount_BotLinkedAccountType {
+	p := new(BotLinkedAccount_BotLinkedAccountType)
+	*p = x
+	return p
+}
+
+func (x BotLinkedAccount_BotLinkedAccountType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotLinkedAccount_BotLinkedAccountType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[8].Descriptor()
+}
+
+func (BotLinkedAccount_BotLinkedAccountType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[8]
+}
+
+func (x BotLinkedAccount_BotLinkedAccountType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotLinkedAccount_BotLinkedAccountType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotLinkedAccount_BotLinkedAccountType(num)
+	return nil
+}
+
+// Deprecated: Use BotLinkedAccount_BotLinkedAccountType.Descriptor instead.
+func (BotLinkedAccount_BotLinkedAccountType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{1, 0}
+}
+
+type BotSignatureVerificationUseCaseProof_BotSignatureUseCase int32
+
+const (
+	BotSignatureVerificationUseCaseProof_UNSPECIFIED BotSignatureVerificationUseCaseProof_BotSignatureUseCase = 0
+	BotSignatureVerificationUseCaseProof_WA_BOT_MSG  BotSignatureVerificationUseCaseProof_BotSignatureUseCase = 1
+)
+
+// Enum value maps for BotSignatureVerificationUseCaseProof_BotSignatureUseCase.
+var (
+	BotSignatureVerificationUseCaseProof_BotSignatureUseCase_name = map[int32]string{
+		0: "UNSPECIFIED",
+		1: "WA_BOT_MSG",
+	}
+	BotSignatureVerificationUseCaseProof_BotSignatureUseCase_value = map[string]int32{
+		"UNSPECIFIED": 0,
+		"WA_BOT_MSG":  1,
+	}
+)
+
+func (x BotSignatureVerificationUseCaseProof_BotSignatureUseCase) Enum() *BotSignatureVerificationUseCaseProof_BotSignatureUseCase {
+	p := new(BotSignatureVerificationUseCaseProof_BotSignatureUseCase)
+	*p = x
+	return p
+}
+
+func (x BotSignatureVerificationUseCaseProof_BotSignatureUseCase) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotSignatureVerificationUseCaseProof_BotSignatureUseCase) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[9].Descriptor()
+}
+
+func (BotSignatureVerificationUseCaseProof_BotSignatureUseCase) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[9]
+}
+
+func (x BotSignatureVerificationUseCaseProof_BotSignatureUseCase) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotSignatureVerificationUseCaseProof_BotSignatureUseCase) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotSignatureVerificationUseCaseProof_BotSignatureUseCase(num)
+	return nil
+}
+
+// Deprecated: Use BotSignatureVerificationUseCaseProof_BotSignatureUseCase.Descriptor instead.
+func (BotSignatureVerificationUseCaseProof_BotSignatureUseCase) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{2, 0}
+}
+
+type BotPromotionMessageMetadata_BotPromotionType int32
+
+const (
+	BotPromotionMessageMetadata_UNKNOWN_TYPE    BotPromotionMessageMetadata_BotPromotionType = 0
+	BotPromotionMessageMetadata_C50             BotPromotionMessageMetadata_BotPromotionType = 1
+	BotPromotionMessageMetadata_SURVEY_PLATFORM BotPromotionMessageMetadata_BotPromotionType = 2
+)
+
+// Enum value maps for BotPromotionMessageMetadata_BotPromotionType.
+var (
+	BotPromotionMessageMetadata_BotPromotionType_name = map[int32]string{
+		0: "UNKNOWN_TYPE",
+		1: "C50",
+		2: "SURVEY_PLATFORM",
+	}
+	BotPromotionMessageMetadata_BotPromotionType_value = map[string]int32{
+		"UNKNOWN_TYPE":    0,
+		"C50":             1,
+		"SURVEY_PLATFORM": 2,
+	}
+)
+
+func (x BotPromotionMessageMetadata_BotPromotionType) Enum() *BotPromotionMessageMetadata_BotPromotionType {
+	p := new(BotPromotionMessageMetadata_BotPromotionType)
+	*p = x
+	return p
+}
+
+func (x BotPromotionMessageMetadata_BotPromotionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotPromotionMessageMetadata_BotPromotionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[10].Descriptor()
+}
+
+func (BotPromotionMessageMetadata_BotPromotionType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[10]
+}
+
+func (x BotPromotionMessageMetadata_BotPromotionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotPromotionMessageMetadata_BotPromotionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotPromotionMessageMetadata_BotPromotionType(num)
+	return nil
+}
+
+// Deprecated: Use BotPromotionMessageMetadata_BotPromotionType.Descriptor instead.
+func (BotPromotionMessageMetadata_BotPromotionType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{3, 0}
+}
+
+type BotMediaMetadata_OrientationType int32
+
+const (
+	BotMediaMetadata_CENTER BotMediaMetadata_OrientationType = 1
+	BotMediaMetadata_LEFT   BotMediaMetadata_OrientationType = 2
+	BotMediaMetadata_RIGHT  BotMediaMetadata_OrientationType = 3
+)
+
+// Enum value maps for BotMediaMetadata_OrientationType.
+var (
+	BotMediaMetadata_OrientationType_name = map[int32]string{
+		1: "CENTER",
+		2: "LEFT",
+		3: "RIGHT",
+	}
+	BotMediaMetadata_OrientationType_value = map[string]int32{
+		"CENTER": 1,
+		"LEFT":   2,
+		"RIGHT":  3,
+	}
+)
+
+func (x BotMediaMetadata_OrientationType) Enum() *BotMediaMetadata_OrientationType {
+	p := new(BotMediaMetadata_OrientationType)
+	*p = x
+	return p
+}
+
+func (x BotMediaMetadata_OrientationType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotMediaMetadata_OrientationType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[11].Descriptor()
+}
+
+func (BotMediaMetadata_OrientationType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[11]
+}
+
+func (x BotMediaMetadata_OrientationType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotMediaMetadata_OrientationType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotMediaMetadata_OrientationType(num)
+	return nil
+}
+
+// Deprecated: Use BotMediaMetadata_OrientationType.Descriptor instead.
+func (BotMediaMetadata_OrientationType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{4, 0}
+}
+
+type BotReminderMetadata_ReminderFrequency int32
+
+const (
+	BotReminderMetadata_ONCE     BotReminderMetadata_ReminderFrequency = 1
+	BotReminderMetadata_DAILY    BotReminderMetadata_ReminderFrequency = 2
+	BotReminderMetadata_WEEKLY   BotReminderMetadata_ReminderFrequency = 3
+	BotReminderMetadata_BIWEEKLY BotReminderMetadata_ReminderFrequency = 4
+	BotReminderMetadata_MONTHLY  BotReminderMetadata_ReminderFrequency = 5
+)
+
+// Enum value maps for BotReminderMetadata_ReminderFrequency.
+var (
+	BotReminderMetadata_ReminderFrequency_name = map[int32]string{
+		1: "ONCE",
+		2: "DAILY",
+		3: "WEEKLY",
+		4: "BIWEEKLY",
+		5: "MONTHLY",
+	}
+	BotReminderMetadata_ReminderFrequency_value = map[string]int32{
+		"ONCE":     1,
+		"DAILY":    2,
+		"WEEKLY":   3,
+		"BIWEEKLY": 4,
+		"MONTHLY":  5,
+	}
+)
+
+func (x BotReminderMetadata_ReminderFrequency) Enum() *BotReminderMetadata_ReminderFrequency {
+	p := new(BotReminderMetadata_ReminderFrequency)
+	*p = x
+	return p
+}
+
+func (x BotReminderMetadata_ReminderFrequency) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotReminderMetadata_ReminderFrequency) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[12].Descriptor()
+}
+
+func (BotReminderMetadata_ReminderFrequency) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[12]
+}
+
+func (x BotReminderMetadata_ReminderFrequency) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotReminderMetadata_ReminderFrequency) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotReminderMetadata_ReminderFrequency(num)
+	return nil
+}
+
+// Deprecated: Use BotReminderMetadata_ReminderFrequency.Descriptor instead.
+func (BotReminderMetadata_ReminderFrequency) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{5, 0}
+}
+
+type BotReminderMetadata_ReminderAction int32
+
+const (
+	BotReminderMetadata_NOTIFY BotReminderMetadata_ReminderAction = 1
+	BotReminderMetadata_CREATE BotReminderMetadata_ReminderAction = 2
+	BotReminderMetadata_DELETE BotReminderMetadata_ReminderAction = 3
+	BotReminderMetadata_UPDATE BotReminderMetadata_ReminderAction = 4
+)
+
+// Enum value maps for BotReminderMetadata_ReminderAction.
+var (
+	BotReminderMetadata_ReminderAction_name = map[int32]string{
+		1: "NOTIFY",
+		2: "CREATE",
+		3: "DELETE",
+		4: "UPDATE",
+	}
+	BotReminderMetadata_ReminderAction_value = map[string]int32{
+		"NOTIFY": 1,
+		"CREATE": 2,
+		"DELETE": 3,
+		"UPDATE": 4,
+	}
+)
+
+func (x BotReminderMetadata_ReminderAction) Enum() *BotReminderMetadata_ReminderAction {
+	p := new(BotReminderMetadata_ReminderAction)
+	*p = x
+	return p
+}
+
+func (x BotReminderMetadata_ReminderAction) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotReminderMetadata_ReminderAction) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[13].Descriptor()
+}
+
+func (BotReminderMetadata_ReminderAction) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[13]
+}
+
+func (x BotReminderMetadata_ReminderAction) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotReminderMetadata_ReminderAction) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotReminderMetadata_ReminderAction(num)
+	return nil
+}
+
+// Deprecated: Use BotReminderMetadata_ReminderAction.Descriptor instead.
+func (BotReminderMetadata_ReminderAction) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{5, 1}
+}
+
+type BotModelMetadata_PremiumModelStatus int32
+
+const (
+	BotModelMetadata_UNKNOWN_STATUS     BotModelMetadata_PremiumModelStatus = 0
+	BotModelMetadata_AVAILABLE          BotModelMetadata_PremiumModelStatus = 1
+	BotModelMetadata_QUOTA_EXCEED_LIMIT BotModelMetadata_PremiumModelStatus = 2
+)
+
+// Enum value maps for BotModelMetadata_PremiumModelStatus.
+var (
+	BotModelMetadata_PremiumModelStatus_name = map[int32]string{
+		0: "UNKNOWN_STATUS",
+		1: "AVAILABLE",
+		2: "QUOTA_EXCEED_LIMIT",
+	}
+	BotModelMetadata_PremiumModelStatus_value = map[string]int32{
+		"UNKNOWN_STATUS":     0,
+		"AVAILABLE":          1,
+		"QUOTA_EXCEED_LIMIT": 2,
+	}
+)
+
+func (x BotModelMetadata_PremiumModelStatus) Enum() *BotModelMetadata_PremiumModelStatus {
+	p := new(BotModelMetadata_PremiumModelStatus)
+	*p = x
+	return p
+}
+
+func (x BotModelMetadata_PremiumModelStatus) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotModelMetadata_PremiumModelStatus) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[14].Descriptor()
+}
+
+func (BotModelMetadata_PremiumModelStatus) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[14]
+}
+
+func (x BotModelMetadata_PremiumModelStatus) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotModelMetadata_PremiumModelStatus) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotModelMetadata_PremiumModelStatus(num)
+	return nil
+}
+
+// Deprecated: Use BotModelMetadata_PremiumModelStatus.Descriptor instead.
+func (BotModelMetadata_PremiumModelStatus) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{6, 0}
+}
+
+type BotModelMetadata_ModelType int32
+
+const (
+	BotModelMetadata_UNKNOWN_TYPE       BotModelMetadata_ModelType = 0
+	BotModelMetadata_LLAMA_PROD         BotModelMetadata_ModelType = 1
+	BotModelMetadata_LLAMA_PROD_PREMIUM BotModelMetadata_ModelType = 2
+)
+
+// Enum value maps for BotModelMetadata_ModelType.
+var (
+	BotModelMetadata_ModelType_name = map[int32]string{
+		0: "UNKNOWN_TYPE",
+		1: "LLAMA_PROD",
+		2: "LLAMA_PROD_PREMIUM",
+	}
+	BotModelMetadata_ModelType_value = map[string]int32{
+		"UNKNOWN_TYPE":       0,
+		"LLAMA_PROD":         1,
+		"LLAMA_PROD_PREMIUM": 2,
+	}
+)
+
+func (x BotModelMetadata_ModelType) Enum() *BotModelMetadata_ModelType {
+	p := new(BotModelMetadata_ModelType)
+	*p = x
+	return p
+}
+
+func (x BotModelMetadata_ModelType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotModelMetadata_ModelType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[15].Descriptor()
+}
+
+func (BotModelMetadata_ModelType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[15]
+}
+
+func (x BotModelMetadata_ModelType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotModelMetadata_ModelType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotModelMetadata_ModelType(num)
+	return nil
+}
+
+// Deprecated: Use BotModelMetadata_ModelType.Descriptor instead.
+func (BotModelMetadata_ModelType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{6, 1}
+}
+
+type BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider int32
+
+const (
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_UNKNOWN_PROVIDER BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider = 0
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_OTHER            BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider = 1
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_GOOGLE           BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider = 2
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BING             BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider = 3
+)
+
+// Enum value maps for BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider.
+var (
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider_name = map[int32]string{
+		0: "UNKNOWN_PROVIDER",
+		1: "OTHER",
+		2: "GOOGLE",
+		3: "BING",
+	}
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider_value = map[string]int32{
+		"UNKNOWN_PROVIDER": 0,
+		"OTHER":            1,
+		"GOOGLE":           2,
+		"BING":             3,
+	}
+)
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider) Enum() *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider {
+	p := new(BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider)
+	*p = x
+	return p
+}
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[16].Descriptor()
+}
+
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[16]
+}
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider(num)
+	return nil
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider.Descriptor instead.
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7, 0, 0}
+}
+
+type BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus int32
+
+const (
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_UNKNOWN   BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus = 0
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_PLANNED   BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus = 1
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_EXECUTING BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus = 2
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_FINISHED  BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus = 3
+)
+
+// Enum value maps for BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus.
+var (
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "PLANNED",
+		2: "EXECUTING",
+		3: "FINISHED",
+	}
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus_value = map[string]int32{
+		"UNKNOWN":   0,
+		"PLANNED":   1,
+		"EXECUTING": 2,
+		"FINISHED":  3,
+	}
+)
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus) Enum() *BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus {
+	p := new(BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus)
+	*p = x
+	return p
+}
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[17].Descriptor()
+}
+
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[17]
+}
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus(num)
+	return nil
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus.Descriptor instead.
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7, 0, 1}
+}
+
+type BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider int32
+
+const (
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_UNKNOWN BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider = 0
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_OTHER   BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider = 1
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_GOOGLE  BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider = 2
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BING    BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider = 3
+)
+
+// Enum value maps for BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider.
+var (
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "OTHER",
+		2: "GOOGLE",
+		3: "BING",
+	}
+	BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider_value = map[string]int32{
+		"UNKNOWN": 0,
+		"OTHER":   1,
+		"GOOGLE":  2,
+		"BING":    3,
+	}
+)
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider) Enum() *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider {
+	p := new(BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider)
+	*p = x
+	return p
+}
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[18].Descriptor()
+}
+
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[18]
+}
+
+func (x BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider(num)
+	return nil
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider.Descriptor instead.
+func (BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7, 0, 0, 0}
+}
+
+type BotCapabilityMetadata_BotCapabilityType int32
+
+const (
+	BotCapabilityMetadata_UNKNOWN                                BotCapabilityMetadata_BotCapabilityType = 0
+	BotCapabilityMetadata_PROGRESS_INDICATOR                     BotCapabilityMetadata_BotCapabilityType = 1
+	BotCapabilityMetadata_RICH_RESPONSE_HEADING                  BotCapabilityMetadata_BotCapabilityType = 2
+	BotCapabilityMetadata_RICH_RESPONSE_NESTED_LIST              BotCapabilityMetadata_BotCapabilityType = 3
+	BotCapabilityMetadata_AI_MEMORY                              BotCapabilityMetadata_BotCapabilityType = 4
+	BotCapabilityMetadata_RICH_RESPONSE_THREAD_SURFING           BotCapabilityMetadata_BotCapabilityType = 5
+	BotCapabilityMetadata_RICH_RESPONSE_TABLE                    BotCapabilityMetadata_BotCapabilityType = 6
+	BotCapabilityMetadata_RICH_RESPONSE_CODE                     BotCapabilityMetadata_BotCapabilityType = 7
+	BotCapabilityMetadata_RICH_RESPONSE_STRUCTURED_RESPONSE      BotCapabilityMetadata_BotCapabilityType = 8
+	BotCapabilityMetadata_RICH_RESPONSE_INLINE_IMAGE             BotCapabilityMetadata_BotCapabilityType = 9
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_CONTROL        BotCapabilityMetadata_BotCapabilityType = 10
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_1       BotCapabilityMetadata_BotCapabilityType = 11
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_2       BotCapabilityMetadata_BotCapabilityType = 12
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_3       BotCapabilityMetadata_BotCapabilityType = 13
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_4       BotCapabilityMetadata_BotCapabilityType = 14
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_5       BotCapabilityMetadata_BotCapabilityType = 15
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_6       BotCapabilityMetadata_BotCapabilityType = 16
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_7       BotCapabilityMetadata_BotCapabilityType = 17
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_8       BotCapabilityMetadata_BotCapabilityType = 18
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_9       BotCapabilityMetadata_BotCapabilityType = 19
+	BotCapabilityMetadata_WA_IG_1P_PLUGIN_RANKING_UPDATE_10      BotCapabilityMetadata_BotCapabilityType = 20
+	BotCapabilityMetadata_RICH_RESPONSE_SUB_HEADING              BotCapabilityMetadata_BotCapabilityType = 21
+	BotCapabilityMetadata_RICH_RESPONSE_GRID_IMAGE               BotCapabilityMetadata_BotCapabilityType = 22
+	BotCapabilityMetadata_AI_STUDIO_UGC_MEMORY                   BotCapabilityMetadata_BotCapabilityType = 23
+	BotCapabilityMetadata_RICH_RESPONSE_LATEX                    BotCapabilityMetadata_BotCapabilityType = 24
+	BotCapabilityMetadata_RICH_RESPONSE_MAPS                     BotCapabilityMetadata_BotCapabilityType = 25
+	BotCapabilityMetadata_RICH_RESPONSE_INLINE_REELS             BotCapabilityMetadata_BotCapabilityType = 26
+	BotCapabilityMetadata_AGENTIC_PLANNING                       BotCapabilityMetadata_BotCapabilityType = 27
+	BotCapabilityMetadata_ACCOUNT_LINKING                        BotCapabilityMetadata_BotCapabilityType = 28
+	BotCapabilityMetadata_STREAMING_DISAGGREGATION               BotCapabilityMetadata_BotCapabilityType = 29
+	BotCapabilityMetadata_RICH_RESPONSE_GRID_IMAGE_3P            BotCapabilityMetadata_BotCapabilityType = 30
+	BotCapabilityMetadata_RICH_RESPONSE_LATEX_INLINE             BotCapabilityMetadata_BotCapabilityType = 31
+	BotCapabilityMetadata_QUERY_PLAN                             BotCapabilityMetadata_BotCapabilityType = 32
+	BotCapabilityMetadata_PROACTIVE_MESSAGE                      BotCapabilityMetadata_BotCapabilityType = 33
+	BotCapabilityMetadata_RICH_RESPONSE_UNIFIED_RESPONSE         BotCapabilityMetadata_BotCapabilityType = 34
+	BotCapabilityMetadata_PROMOTION_MESSAGE                      BotCapabilityMetadata_BotCapabilityType = 35
+	BotCapabilityMetadata_SIMPLIFIED_PROFILE_PAGE                BotCapabilityMetadata_BotCapabilityType = 36
+	BotCapabilityMetadata_RICH_RESPONSE_SOURCES_IN_MESSAGE       BotCapabilityMetadata_BotCapabilityType = 37
+	BotCapabilityMetadata_RICH_RESPONSE_SIDE_BY_SIDE_SURVEY      BotCapabilityMetadata_BotCapabilityType = 38
+	BotCapabilityMetadata_RICH_RESPONSE_UNIFIED_TEXT_COMPONENT   BotCapabilityMetadata_BotCapabilityType = 39
+	BotCapabilityMetadata_AI_SHARED_MEMORY                       BotCapabilityMetadata_BotCapabilityType = 40
+	BotCapabilityMetadata_RICH_RESPONSE_UNIFIED_SOURCES          BotCapabilityMetadata_BotCapabilityType = 41
+	BotCapabilityMetadata_RICH_RESPONSE_UNIFIED_DOMAIN_CITATIONS BotCapabilityMetadata_BotCapabilityType = 42
+	BotCapabilityMetadata_RICH_RESPONSE_UR_INLINE_REELS_ENABLED  BotCapabilityMetadata_BotCapabilityType = 43
+	BotCapabilityMetadata_RICH_RESPONSE_UR_MEDIA_GRID_ENABLED    BotCapabilityMetadata_BotCapabilityType = 44
+	BotCapabilityMetadata_RICH_RESPONSE_UR_TIMESTAMP_PLACEHOLDER BotCapabilityMetadata_BotCapabilityType = 45
+	BotCapabilityMetadata_RICH_RESPONSE_IN_APP_SURVEY            BotCapabilityMetadata_BotCapabilityType = 46
+	BotCapabilityMetadata_AI_RESPONSE_MODEL_BRANDING             BotCapabilityMetadata_BotCapabilityType = 47
+	BotCapabilityMetadata_SESSION_TRANSPARENCY_SYSTEM_MESSAGE    BotCapabilityMetadata_BotCapabilityType = 48
+	BotCapabilityMetadata_RICH_RESPONSE_UR_REASONING             BotCapabilityMetadata_BotCapabilityType = 49
+)
+
+// Enum value maps for BotCapabilityMetadata_BotCapabilityType.
+var (
+	BotCapabilityMetadata_BotCapabilityType_name = map[int32]string{
+		0:  "UNKNOWN",
+		1:  "PROGRESS_INDICATOR",
+		2:  "RICH_RESPONSE_HEADING",
+		3:  "RICH_RESPONSE_NESTED_LIST",
+		4:  "AI_MEMORY",
+		5:  "RICH_RESPONSE_THREAD_SURFING",
+		6:  "RICH_RESPONSE_TABLE",
+		7:  "RICH_RESPONSE_CODE",
+		8:  "RICH_RESPONSE_STRUCTURED_RESPONSE",
+		9:  "RICH_RESPONSE_INLINE_IMAGE",
+		10: "WA_IG_1P_PLUGIN_RANKING_CONTROL",
+		11: "WA_IG_1P_PLUGIN_RANKING_UPDATE_1",
+		12: "WA_IG_1P_PLUGIN_RANKING_UPDATE_2",
+		13: "WA_IG_1P_PLUGIN_RANKING_UPDATE_3",
+		14: "WA_IG_1P_PLUGIN_RANKING_UPDATE_4",
+		15: "WA_IG_1P_PLUGIN_RANKING_UPDATE_5",
+		16: "WA_IG_1P_PLUGIN_RANKING_UPDATE_6",
+		17: "WA_IG_1P_PLUGIN_RANKING_UPDATE_7",
+		18: "WA_IG_1P_PLUGIN_RANKING_UPDATE_8",
+		19: "WA_IG_1P_PLUGIN_RANKING_UPDATE_9",
+		20: "WA_IG_1P_PLUGIN_RANKING_UPDATE_10",
+		21: "RICH_RESPONSE_SUB_HEADING",
+		22: "RICH_RESPONSE_GRID_IMAGE",
+		23: "AI_STUDIO_UGC_MEMORY",
+		24: "RICH_RESPONSE_LATEX",
+		25: "RICH_RESPONSE_MAPS",
+		26: "RICH_RESPONSE_INLINE_REELS",
+		27: "AGENTIC_PLANNING",
+		28: "ACCOUNT_LINKING",
+		29: "STREAMING_DISAGGREGATION",
+		30: "RICH_RESPONSE_GRID_IMAGE_3P",
+		31: "RICH_RESPONSE_LATEX_INLINE",
+		32: "QUERY_PLAN",
+		33: "PROACTIVE_MESSAGE",
+		34: "RICH_RESPONSE_UNIFIED_RESPONSE",
+		35: "PROMOTION_MESSAGE",
+		36: "SIMPLIFIED_PROFILE_PAGE",
+		37: "RICH_RESPONSE_SOURCES_IN_MESSAGE",
+		38: "RICH_RESPONSE_SIDE_BY_SIDE_SURVEY",
+		39: "RICH_RESPONSE_UNIFIED_TEXT_COMPONENT",
+		40: "AI_SHARED_MEMORY",
+		41: "RICH_RESPONSE_UNIFIED_SOURCES",
+		42: "RICH_RESPONSE_UNIFIED_DOMAIN_CITATIONS",
+		43: "RICH_RESPONSE_UR_INLINE_REELS_ENABLED",
+		44: "RICH_RESPONSE_UR_MEDIA_GRID_ENABLED",
+		45: "RICH_RESPONSE_UR_TIMESTAMP_PLACEHOLDER",
+		46: "RICH_RESPONSE_IN_APP_SURVEY",
+		47: "AI_RESPONSE_MODEL_BRANDING",
+		48: "SESSION_TRANSPARENCY_SYSTEM_MESSAGE",
+		49: "RICH_RESPONSE_UR_REASONING",
+	}
+	BotCapabilityMetadata_BotCapabilityType_value = map[string]int32{
+		"UNKNOWN":                                0,
+		"PROGRESS_INDICATOR":                     1,
+		"RICH_RESPONSE_HEADING":                  2,
+		"RICH_RESPONSE_NESTED_LIST":              3,
+		"AI_MEMORY":                              4,
+		"RICH_RESPONSE_THREAD_SURFING":           5,
+		"RICH_RESPONSE_TABLE":                    6,
+		"RICH_RESPONSE_CODE":                     7,
+		"RICH_RESPONSE_STRUCTURED_RESPONSE":      8,
+		"RICH_RESPONSE_INLINE_IMAGE":             9,
+		"WA_IG_1P_PLUGIN_RANKING_CONTROL":        10,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_1":       11,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_2":       12,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_3":       13,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_4":       14,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_5":       15,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_6":       16,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_7":       17,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_8":       18,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_9":       19,
+		"WA_IG_1P_PLUGIN_RANKING_UPDATE_10":      20,
+		"RICH_RESPONSE_SUB_HEADING":              21,
+		"RICH_RESPONSE_GRID_IMAGE":               22,
+		"AI_STUDIO_UGC_MEMORY":                   23,
+		"RICH_RESPONSE_LATEX":                    24,
+		"RICH_RESPONSE_MAPS":                     25,
+		"RICH_RESPONSE_INLINE_REELS":             26,
+		"AGENTIC_PLANNING":                       27,
+		"ACCOUNT_LINKING":                        28,
+		"STREAMING_DISAGGREGATION":               29,
+		"RICH_RESPONSE_GRID_IMAGE_3P":            30,
+		"RICH_RESPONSE_LATEX_INLINE":             31,
+		"QUERY_PLAN":                             32,
+		"PROACTIVE_MESSAGE":                      33,
+		"RICH_RESPONSE_UNIFIED_RESPONSE":         34,
+		"PROMOTION_MESSAGE":                      35,
+		"SIMPLIFIED_PROFILE_PAGE":                36,
+		"RICH_RESPONSE_SOURCES_IN_MESSAGE":       37,
+		"RICH_RESPONSE_SIDE_BY_SIDE_SURVEY":      38,
+		"RICH_RESPONSE_UNIFIED_TEXT_COMPONENT":   39,
+		"AI_SHARED_MEMORY":                       40,
+		"RICH_RESPONSE_UNIFIED_SOURCES":          41,
+		"RICH_RESPONSE_UNIFIED_DOMAIN_CITATIONS": 42,
+		"RICH_RESPONSE_UR_INLINE_REELS_ENABLED":  43,
+		"RICH_RESPONSE_UR_MEDIA_GRID_ENABLED":    44,
+		"RICH_RESPONSE_UR_TIMESTAMP_PLACEHOLDER": 45,
+		"RICH_RESPONSE_IN_APP_SURVEY":            46,
+		"AI_RESPONSE_MODEL_BRANDING":             47,
+		"SESSION_TRANSPARENCY_SYSTEM_MESSAGE":    48,
+		"RICH_RESPONSE_UR_REASONING":             49,
+	}
+)
+
+func (x BotCapabilityMetadata_BotCapabilityType) Enum() *BotCapabilityMetadata_BotCapabilityType {
+	p := new(BotCapabilityMetadata_BotCapabilityType)
+	*p = x
+	return p
+}
+
+func (x BotCapabilityMetadata_BotCapabilityType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotCapabilityMetadata_BotCapabilityType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[19].Descriptor()
+}
+
+func (BotCapabilityMetadata_BotCapabilityType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[19]
+}
+
+func (x BotCapabilityMetadata_BotCapabilityType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotCapabilityMetadata_BotCapabilityType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotCapabilityMetadata_BotCapabilityType(num)
+	return nil
+}
+
+// Deprecated: Use BotCapabilityMetadata_BotCapabilityType.Descriptor instead.
+func (BotCapabilityMetadata_BotCapabilityType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{8, 0}
+}
+
+type BotModeSelectionMetadata_BotUserSelectionMode int32
+
+const (
+	BotModeSelectionMetadata_UNKNOWN_MODE   BotModeSelectionMetadata_BotUserSelectionMode = 0
+	BotModeSelectionMetadata_REASONING_MODE BotModeSelectionMetadata_BotUserSelectionMode = 1
+)
+
+// Enum value maps for BotModeSelectionMetadata_BotUserSelectionMode.
+var (
+	BotModeSelectionMetadata_BotUserSelectionMode_name = map[int32]string{
+		0: "UNKNOWN_MODE",
+		1: "REASONING_MODE",
+	}
+	BotModeSelectionMetadata_BotUserSelectionMode_value = map[string]int32{
+		"UNKNOWN_MODE":   0,
+		"REASONING_MODE": 1,
+	}
+)
+
+func (x BotModeSelectionMetadata_BotUserSelectionMode) Enum() *BotModeSelectionMetadata_BotUserSelectionMode {
+	p := new(BotModeSelectionMetadata_BotUserSelectionMode)
+	*p = x
+	return p
+}
+
+func (x BotModeSelectionMetadata_BotUserSelectionMode) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotModeSelectionMetadata_BotUserSelectionMode) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[20].Descriptor()
+}
+
+func (BotModeSelectionMetadata_BotUserSelectionMode) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[20]
+}
+
+func (x BotModeSelectionMetadata_BotUserSelectionMode) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotModeSelectionMetadata_BotUserSelectionMode) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotModeSelectionMetadata_BotUserSelectionMode(num)
+	return nil
+}
+
+// Deprecated: Use BotModeSelectionMetadata_BotUserSelectionMode.Descriptor instead.
+func (BotModeSelectionMetadata_BotUserSelectionMode) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{9, 0}
+}
+
+type BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType int32
+
+const (
+	BotQuotaMetadata_BotFeatureQuotaMetadata_UNKNOWN_FEATURE   BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType = 0
+	BotQuotaMetadata_BotFeatureQuotaMetadata_REASONING_FEATURE BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType = 1
+)
+
+// Enum value maps for BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType.
+var (
+	BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType_name = map[int32]string{
+		0: "UNKNOWN_FEATURE",
+		1: "REASONING_FEATURE",
+	}
+	BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType_value = map[string]int32{
+		"UNKNOWN_FEATURE":   0,
+		"REASONING_FEATURE": 1,
+	}
+)
+
+func (x BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType) Enum() *BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType {
+	p := new(BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType)
+	*p = x
+	return p
+}
+
+func (x BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[21].Descriptor()
+}
+
+func (BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[21]
+}
+
+func (x BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType(num)
+	return nil
+}
+
+// Deprecated: Use BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType.Descriptor instead.
+func (BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{10, 0, 0}
+}
+
+type BotImagineMetadata_ImagineType int32
+
+const (
+	BotImagineMetadata_UNKNOWN BotImagineMetadata_ImagineType = 0
+	BotImagineMetadata_IMAGINE BotImagineMetadata_ImagineType = 1
+	BotImagineMetadata_MEMU    BotImagineMetadata_ImagineType = 2
+	BotImagineMetadata_FLASH   BotImagineMetadata_ImagineType = 3
+	BotImagineMetadata_EDIT    BotImagineMetadata_ImagineType = 4
+)
+
+// Enum value maps for BotImagineMetadata_ImagineType.
+var (
+	BotImagineMetadata_ImagineType_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "IMAGINE",
+		2: "MEMU",
+		3: "FLASH",
+		4: "EDIT",
+	}
+	BotImagineMetadata_ImagineType_value = map[string]int32{
+		"UNKNOWN": 0,
+		"IMAGINE": 1,
+		"MEMU":    2,
+		"FLASH":   3,
+		"EDIT":    4,
+	}
+)
+
+func (x BotImagineMetadata_ImagineType) Enum() *BotImagineMetadata_ImagineType {
+	p := new(BotImagineMetadata_ImagineType)
+	*p = x
+	return p
+}
+
+func (x BotImagineMetadata_ImagineType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotImagineMetadata_ImagineType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[22].Descriptor()
+}
+
+func (BotImagineMetadata_ImagineType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[22]
+}
+
+func (x BotImagineMetadata_ImagineType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotImagineMetadata_ImagineType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotImagineMetadata_ImagineType(num)
+	return nil
+}
+
+// Deprecated: Use BotImagineMetadata_ImagineType.Descriptor instead.
+func (BotImagineMetadata_ImagineType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{11, 0}
+}
+
+type BotAgeCollectionMetadata_AgeCollectionType int32
+
+const (
+	BotAgeCollectionMetadata_O18_BINARY BotAgeCollectionMetadata_AgeCollectionType = 0
+	BotAgeCollectionMetadata_WAFFLE     BotAgeCollectionMetadata_AgeCollectionType = 1
+)
+
+// Enum value maps for BotAgeCollectionMetadata_AgeCollectionType.
+var (
+	BotAgeCollectionMetadata_AgeCollectionType_name = map[int32]string{
+		0: "O18_BINARY",
+		1: "WAFFLE",
+	}
+	BotAgeCollectionMetadata_AgeCollectionType_value = map[string]int32{
+		"O18_BINARY": 0,
+		"WAFFLE":     1,
+	}
+)
+
+func (x BotAgeCollectionMetadata_AgeCollectionType) Enum() *BotAgeCollectionMetadata_AgeCollectionType {
+	p := new(BotAgeCollectionMetadata_AgeCollectionType)
+	*p = x
+	return p
+}
+
+func (x BotAgeCollectionMetadata_AgeCollectionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotAgeCollectionMetadata_AgeCollectionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[23].Descriptor()
+}
+
+func (BotAgeCollectionMetadata_AgeCollectionType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[23]
+}
+
+func (x BotAgeCollectionMetadata_AgeCollectionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotAgeCollectionMetadata_AgeCollectionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotAgeCollectionMetadata_AgeCollectionType(num)
+	return nil
+}
+
+// Deprecated: Use BotAgeCollectionMetadata_AgeCollectionType.Descriptor instead.
+func (BotAgeCollectionMetadata_AgeCollectionType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{12, 0}
+}
+
+type BotSourcesMetadata_BotSourceItem_SourceProvider int32
+
+const (
+	BotSourcesMetadata_BotSourceItem_UNKNOWN BotSourcesMetadata_BotSourceItem_SourceProvider = 0
+	BotSourcesMetadata_BotSourceItem_BING    BotSourcesMetadata_BotSourceItem_SourceProvider = 1
+	BotSourcesMetadata_BotSourceItem_GOOGLE  BotSourcesMetadata_BotSourceItem_SourceProvider = 2
+	BotSourcesMetadata_BotSourceItem_SUPPORT BotSourcesMetadata_BotSourceItem_SourceProvider = 3
+	BotSourcesMetadata_BotSourceItem_OTHER   BotSourcesMetadata_BotSourceItem_SourceProvider = 4
+)
+
+// Enum value maps for BotSourcesMetadata_BotSourceItem_SourceProvider.
+var (
+	BotSourcesMetadata_BotSourceItem_SourceProvider_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "BING",
+		2: "GOOGLE",
+		3: "SUPPORT",
+		4: "OTHER",
+	}
+	BotSourcesMetadata_BotSourceItem_SourceProvider_value = map[string]int32{
+		"UNKNOWN": 0,
+		"BING":    1,
+		"GOOGLE":  2,
+		"SUPPORT": 3,
+		"OTHER":   4,
+	}
+)
+
+func (x BotSourcesMetadata_BotSourceItem_SourceProvider) Enum() *BotSourcesMetadata_BotSourceItem_SourceProvider {
+	p := new(BotSourcesMetadata_BotSourceItem_SourceProvider)
+	*p = x
+	return p
+}
+
+func (x BotSourcesMetadata_BotSourceItem_SourceProvider) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotSourcesMetadata_BotSourceItem_SourceProvider) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[24].Descriptor()
+}
+
+func (BotSourcesMetadata_BotSourceItem_SourceProvider) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[24]
+}
+
+func (x BotSourcesMetadata_BotSourceItem_SourceProvider) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotSourcesMetadata_BotSourceItem_SourceProvider) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotSourcesMetadata_BotSourceItem_SourceProvider(num)
+	return nil
+}
+
+// Deprecated: Use BotSourcesMetadata_BotSourceItem_SourceProvider.Descriptor instead.
+func (BotSourcesMetadata_BotSourceItem_SourceProvider) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{13, 0, 0}
+}
+
+type BotMessageOrigin_BotMessageOriginType int32
+
+const (
+	BotMessageOrigin_BOT_MESSAGE_ORIGIN_TYPE_AI_INITIATED BotMessageOrigin_BotMessageOriginType = 0
+)
+
+// Enum value maps for BotMessageOrigin_BotMessageOriginType.
+var (
+	BotMessageOrigin_BotMessageOriginType_name = map[int32]string{
+		0: "BOT_MESSAGE_ORIGIN_TYPE_AI_INITIATED",
+	}
+	BotMessageOrigin_BotMessageOriginType_value = map[string]int32{
+		"BOT_MESSAGE_ORIGIN_TYPE_AI_INITIATED": 0,
+	}
+)
+
+func (x BotMessageOrigin_BotMessageOriginType) Enum() *BotMessageOrigin_BotMessageOriginType {
+	p := new(BotMessageOrigin_BotMessageOriginType)
+	*p = x
+	return p
+}
+
+func (x BotMessageOrigin_BotMessageOriginType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotMessageOrigin_BotMessageOriginType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[25].Descriptor()
+}
+
+func (BotMessageOrigin_BotMessageOriginType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[25]
+}
+
+func (x BotMessageOrigin_BotMessageOriginType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotMessageOrigin_BotMessageOriginType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotMessageOrigin_BotMessageOriginType(num)
+	return nil
+}
+
+// Deprecated: Use BotMessageOrigin_BotMessageOriginType.Descriptor instead.
+func (BotMessageOrigin_BotMessageOriginType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{14, 0}
+}
+
+type AIThreadInfo_AIThreadClientInfo_AIThreadType int32
+
+const (
+	AIThreadInfo_AIThreadClientInfo_UNKNOWN   AIThreadInfo_AIThreadClientInfo_AIThreadType = 0
+	AIThreadInfo_AIThreadClientInfo_DEFAULT   AIThreadInfo_AIThreadClientInfo_AIThreadType = 1
+	AIThreadInfo_AIThreadClientInfo_INCOGNITO AIThreadInfo_AIThreadClientInfo_AIThreadType = 2
+)
+
+// Enum value maps for AIThreadInfo_AIThreadClientInfo_AIThreadType.
+var (
+	AIThreadInfo_AIThreadClientInfo_AIThreadType_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "DEFAULT",
+		2: "INCOGNITO",
+	}
+	AIThreadInfo_AIThreadClientInfo_AIThreadType_value = map[string]int32{
+		"UNKNOWN":   0,
+		"DEFAULT":   1,
+		"INCOGNITO": 2,
+	}
+)
+
+func (x AIThreadInfo_AIThreadClientInfo_AIThreadType) Enum() *AIThreadInfo_AIThreadClientInfo_AIThreadType {
+	p := new(AIThreadInfo_AIThreadClientInfo_AIThreadType)
+	*p = x
+	return p
+}
+
+func (x AIThreadInfo_AIThreadClientInfo_AIThreadType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIThreadInfo_AIThreadClientInfo_AIThreadType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[26].Descriptor()
+}
+
+func (AIThreadInfo_AIThreadClientInfo_AIThreadType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[26]
+}
+
+func (x AIThreadInfo_AIThreadClientInfo_AIThreadType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIThreadInfo_AIThreadClientInfo_AIThreadType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIThreadInfo_AIThreadClientInfo_AIThreadType(num)
+	return nil
+}
+
+// Deprecated: Use AIThreadInfo_AIThreadClientInfo_AIThreadType.Descriptor instead.
+func (AIThreadInfo_AIThreadClientInfo_AIThreadType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{15, 0, 0}
+}
+
+type BotFeedbackMessage_ReportKind int32
+
+const (
+	BotFeedbackMessage_NONE    BotFeedbackMessage_ReportKind = 0
+	BotFeedbackMessage_GENERIC BotFeedbackMessage_ReportKind = 1
+)
+
+// Enum value maps for BotFeedbackMessage_ReportKind.
+var (
+	BotFeedbackMessage_ReportKind_name = map[int32]string{
+		0: "NONE",
+		1: "GENERIC",
+	}
+	BotFeedbackMessage_ReportKind_value = map[string]int32{
+		"NONE":    0,
+		"GENERIC": 1,
+	}
+)
+
+func (x BotFeedbackMessage_ReportKind) Enum() *BotFeedbackMessage_ReportKind {
+	p := new(BotFeedbackMessage_ReportKind)
+	*p = x
+	return p
+}
+
+func (x BotFeedbackMessage_ReportKind) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotFeedbackMessage_ReportKind) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[27].Descriptor()
+}
+
+func (BotFeedbackMessage_ReportKind) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[27]
+}
+
+func (x BotFeedbackMessage_ReportKind) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotFeedbackMessage_ReportKind) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotFeedbackMessage_ReportKind(num)
+	return nil
+}
+
+// Deprecated: Use BotFeedbackMessage_ReportKind.Descriptor instead.
+func (BotFeedbackMessage_ReportKind) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0}
+}
+
+type BotFeedbackMessage_BotFeedbackKindMultiplePositive int32
+
+const (
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_POSITIVE_GENERIC BotFeedbackMessage_BotFeedbackKindMultiplePositive = 1
+)
+
+// Enum value maps for BotFeedbackMessage_BotFeedbackKindMultiplePositive.
+var (
+	BotFeedbackMessage_BotFeedbackKindMultiplePositive_name = map[int32]string{
+		1: "BOT_FEEDBACK_MULTIPLE_POSITIVE_GENERIC",
+	}
+	BotFeedbackMessage_BotFeedbackKindMultiplePositive_value = map[string]int32{
+		"BOT_FEEDBACK_MULTIPLE_POSITIVE_GENERIC": 1,
+	}
+)
+
+func (x BotFeedbackMessage_BotFeedbackKindMultiplePositive) Enum() *BotFeedbackMessage_BotFeedbackKindMultiplePositive {
+	p := new(BotFeedbackMessage_BotFeedbackKindMultiplePositive)
+	*p = x
+	return p
+}
+
+func (x BotFeedbackMessage_BotFeedbackKindMultiplePositive) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotFeedbackMessage_BotFeedbackKindMultiplePositive) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[28].Descriptor()
+}
+
+func (BotFeedbackMessage_BotFeedbackKindMultiplePositive) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[28]
+}
+
+func (x BotFeedbackMessage_BotFeedbackKindMultiplePositive) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotFeedbackMessage_BotFeedbackKindMultiplePositive) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotFeedbackMessage_BotFeedbackKindMultiplePositive(num)
+	return nil
+}
+
+// Deprecated: Use BotFeedbackMessage_BotFeedbackKindMultiplePositive.Descriptor instead.
+func (BotFeedbackMessage_BotFeedbackKindMultiplePositive) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 1}
+}
+
+type BotFeedbackMessage_BotFeedbackKindMultipleNegative int32
+
+const (
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_GENERIC                BotFeedbackMessage_BotFeedbackKindMultipleNegative = 1
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_HELPFUL                BotFeedbackMessage_BotFeedbackKindMultipleNegative = 2
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_INTERESTING            BotFeedbackMessage_BotFeedbackKindMultipleNegative = 4
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_ACCURATE               BotFeedbackMessage_BotFeedbackKindMultipleNegative = 8
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_SAFE                   BotFeedbackMessage_BotFeedbackKindMultipleNegative = 16
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_OTHER                  BotFeedbackMessage_BotFeedbackKindMultipleNegative = 32
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_REFUSED                BotFeedbackMessage_BotFeedbackKindMultipleNegative = 64
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_VISUALLY_APPEALING BotFeedbackMessage_BotFeedbackKindMultipleNegative = 128
+	BotFeedbackMessage_BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_RELEVANT_TO_TEXT   BotFeedbackMessage_BotFeedbackKindMultipleNegative = 256
+)
+
+// Enum value maps for BotFeedbackMessage_BotFeedbackKindMultipleNegative.
+var (
+	BotFeedbackMessage_BotFeedbackKindMultipleNegative_name = map[int32]string{
+		1:   "BOT_FEEDBACK_MULTIPLE_NEGATIVE_GENERIC",
+		2:   "BOT_FEEDBACK_MULTIPLE_NEGATIVE_HELPFUL",
+		4:   "BOT_FEEDBACK_MULTIPLE_NEGATIVE_INTERESTING",
+		8:   "BOT_FEEDBACK_MULTIPLE_NEGATIVE_ACCURATE",
+		16:  "BOT_FEEDBACK_MULTIPLE_NEGATIVE_SAFE",
+		32:  "BOT_FEEDBACK_MULTIPLE_NEGATIVE_OTHER",
+		64:  "BOT_FEEDBACK_MULTIPLE_NEGATIVE_REFUSED",
+		128: "BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_VISUALLY_APPEALING",
+		256: "BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_RELEVANT_TO_TEXT",
+	}
+	BotFeedbackMessage_BotFeedbackKindMultipleNegative_value = map[string]int32{
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_GENERIC":                1,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_HELPFUL":                2,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_INTERESTING":            4,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_ACCURATE":               8,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_SAFE":                   16,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_OTHER":                  32,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_REFUSED":                64,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_VISUALLY_APPEALING": 128,
+		"BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_RELEVANT_TO_TEXT":   256,
+	}
+)
+
+func (x BotFeedbackMessage_BotFeedbackKindMultipleNegative) Enum() *BotFeedbackMessage_BotFeedbackKindMultipleNegative {
+	p := new(BotFeedbackMessage_BotFeedbackKindMultipleNegative)
+	*p = x
+	return p
+}
+
+func (x BotFeedbackMessage_BotFeedbackKindMultipleNegative) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotFeedbackMessage_BotFeedbackKindMultipleNegative) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[29].Descriptor()
+}
+
+func (BotFeedbackMessage_BotFeedbackKindMultipleNegative) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[29]
+}
+
+func (x BotFeedbackMessage_BotFeedbackKindMultipleNegative) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotFeedbackMessage_BotFeedbackKindMultipleNegative) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotFeedbackMessage_BotFeedbackKindMultipleNegative(num)
+	return nil
+}
+
+// Deprecated: Use BotFeedbackMessage_BotFeedbackKindMultipleNegative.Descriptor instead.
+func (BotFeedbackMessage_BotFeedbackKindMultipleNegative) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 2}
+}
+
+type BotFeedbackMessage_BotFeedbackKind int32
+
+const (
+	BotFeedbackMessage_BOT_FEEDBACK_POSITIVE                             BotFeedbackMessage_BotFeedbackKind = 0
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_GENERIC                     BotFeedbackMessage_BotFeedbackKind = 1
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_HELPFUL                     BotFeedbackMessage_BotFeedbackKind = 2
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_INTERESTING                 BotFeedbackMessage_BotFeedbackKind = 3
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_ACCURATE                    BotFeedbackMessage_BotFeedbackKind = 4
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_SAFE                        BotFeedbackMessage_BotFeedbackKind = 5
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_OTHER                       BotFeedbackMessage_BotFeedbackKind = 6
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_REFUSED                     BotFeedbackMessage_BotFeedbackKind = 7
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_NOT_VISUALLY_APPEALING      BotFeedbackMessage_BotFeedbackKind = 8
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_NOT_RELEVANT_TO_TEXT        BotFeedbackMessage_BotFeedbackKind = 9
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_PERSONALIZED                BotFeedbackMessage_BotFeedbackKind = 10
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_CLARITY                     BotFeedbackMessage_BotFeedbackKind = 11
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_DOESNT_LOOK_LIKE_THE_PERSON BotFeedbackMessage_BotFeedbackKind = 12
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE_HALLUCINATION_INTERNAL_ONLY BotFeedbackMessage_BotFeedbackKind = 13
+	BotFeedbackMessage_BOT_FEEDBACK_NEGATIVE                             BotFeedbackMessage_BotFeedbackKind = 14
+)
+
+// Enum value maps for BotFeedbackMessage_BotFeedbackKind.
+var (
+	BotFeedbackMessage_BotFeedbackKind_name = map[int32]string{
+		0:  "BOT_FEEDBACK_POSITIVE",
+		1:  "BOT_FEEDBACK_NEGATIVE_GENERIC",
+		2:  "BOT_FEEDBACK_NEGATIVE_HELPFUL",
+		3:  "BOT_FEEDBACK_NEGATIVE_INTERESTING",
+		4:  "BOT_FEEDBACK_NEGATIVE_ACCURATE",
+		5:  "BOT_FEEDBACK_NEGATIVE_SAFE",
+		6:  "BOT_FEEDBACK_NEGATIVE_OTHER",
+		7:  "BOT_FEEDBACK_NEGATIVE_REFUSED",
+		8:  "BOT_FEEDBACK_NEGATIVE_NOT_VISUALLY_APPEALING",
+		9:  "BOT_FEEDBACK_NEGATIVE_NOT_RELEVANT_TO_TEXT",
+		10: "BOT_FEEDBACK_NEGATIVE_PERSONALIZED",
+		11: "BOT_FEEDBACK_NEGATIVE_CLARITY",
+		12: "BOT_FEEDBACK_NEGATIVE_DOESNT_LOOK_LIKE_THE_PERSON",
+		13: "BOT_FEEDBACK_NEGATIVE_HALLUCINATION_INTERNAL_ONLY",
+		14: "BOT_FEEDBACK_NEGATIVE",
+	}
+	BotFeedbackMessage_BotFeedbackKind_value = map[string]int32{
+		"BOT_FEEDBACK_POSITIVE":                             0,
+		"BOT_FEEDBACK_NEGATIVE_GENERIC":                     1,
+		"BOT_FEEDBACK_NEGATIVE_HELPFUL":                     2,
+		"BOT_FEEDBACK_NEGATIVE_INTERESTING":                 3,
+		"BOT_FEEDBACK_NEGATIVE_ACCURATE":                    4,
+		"BOT_FEEDBACK_NEGATIVE_SAFE":                        5,
+		"BOT_FEEDBACK_NEGATIVE_OTHER":                       6,
+		"BOT_FEEDBACK_NEGATIVE_REFUSED":                     7,
+		"BOT_FEEDBACK_NEGATIVE_NOT_VISUALLY_APPEALING":      8,
+		"BOT_FEEDBACK_NEGATIVE_NOT_RELEVANT_TO_TEXT":        9,
+		"BOT_FEEDBACK_NEGATIVE_PERSONALIZED":                10,
+		"BOT_FEEDBACK_NEGATIVE_CLARITY":                     11,
+		"BOT_FEEDBACK_NEGATIVE_DOESNT_LOOK_LIKE_THE_PERSON": 12,
+		"BOT_FEEDBACK_NEGATIVE_HALLUCINATION_INTERNAL_ONLY": 13,
+		"BOT_FEEDBACK_NEGATIVE":                             14,
+	}
+)
+
+func (x BotFeedbackMessage_BotFeedbackKind) Enum() *BotFeedbackMessage_BotFeedbackKind {
+	p := new(BotFeedbackMessage_BotFeedbackKind)
+	*p = x
+	return p
+}
+
+func (x BotFeedbackMessage_BotFeedbackKind) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotFeedbackMessage_BotFeedbackKind) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[30].Descriptor()
+}
+
+func (BotFeedbackMessage_BotFeedbackKind) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[30]
+}
+
+func (x BotFeedbackMessage_BotFeedbackKind) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotFeedbackMessage_BotFeedbackKind) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotFeedbackMessage_BotFeedbackKind(num)
+	return nil
+}
+
+// Deprecated: Use BotFeedbackMessage_BotFeedbackKind.Descriptor instead.
+func (BotFeedbackMessage_BotFeedbackKind) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 3}
+}
+
+type AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment int32
+
+const (
+	AIRichResponseInlineImageMetadata_AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED  AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment = 0
+	AIRichResponseInlineImageMetadata_AI_RICH_RESPONSE_IMAGE_LAYOUT_TRAILING_ALIGNED AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment = 1
+	AIRichResponseInlineImageMetadata_AI_RICH_RESPONSE_IMAGE_LAYOUT_CENTER_ALIGNED   AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment = 2
+)
+
+// Enum value maps for AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment.
+var (
+	AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment_name = map[int32]string{
+		0: "AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED",
+		1: "AI_RICH_RESPONSE_IMAGE_LAYOUT_TRAILING_ALIGNED",
+		2: "AI_RICH_RESPONSE_IMAGE_LAYOUT_CENTER_ALIGNED",
+	}
+	AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment_value = map[string]int32{
+		"AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED":  0,
+		"AI_RICH_RESPONSE_IMAGE_LAYOUT_TRAILING_ALIGNED": 1,
+		"AI_RICH_RESPONSE_IMAGE_LAYOUT_CENTER_ALIGNED":   2,
+	}
+)
+
+func (x AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment) Enum() *AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment {
+	p := new(AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment)
+	*p = x
+	return p
+}
+
+func (x AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[31].Descriptor()
+}
+
+func (AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[31]
+}
+
+func (x AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment(num)
+	return nil
+}
+
+// Deprecated: Use AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment.Descriptor instead.
+func (AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{17, 0}
+}
+
+type AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType int32
+
+const (
+	AIRichResponseCodeMetadata_AI_RICH_RESPONSE_CODE_HIGHLIGHT_DEFAULT AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType = 0
+	AIRichResponseCodeMetadata_AI_RICH_RESPONSE_CODE_HIGHLIGHT_KEYWORD AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType = 1
+	AIRichResponseCodeMetadata_AI_RICH_RESPONSE_CODE_HIGHLIGHT_METHOD  AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType = 2
+	AIRichResponseCodeMetadata_AI_RICH_RESPONSE_CODE_HIGHLIGHT_STRING  AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType = 3
+	AIRichResponseCodeMetadata_AI_RICH_RESPONSE_CODE_HIGHLIGHT_NUMBER  AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType = 4
+	AIRichResponseCodeMetadata_AI_RICH_RESPONSE_CODE_HIGHLIGHT_COMMENT AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType = 5
+)
+
+// Enum value maps for AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType.
+var (
+	AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType_name = map[int32]string{
+		0: "AI_RICH_RESPONSE_CODE_HIGHLIGHT_DEFAULT",
+		1: "AI_RICH_RESPONSE_CODE_HIGHLIGHT_KEYWORD",
+		2: "AI_RICH_RESPONSE_CODE_HIGHLIGHT_METHOD",
+		3: "AI_RICH_RESPONSE_CODE_HIGHLIGHT_STRING",
+		4: "AI_RICH_RESPONSE_CODE_HIGHLIGHT_NUMBER",
+		5: "AI_RICH_RESPONSE_CODE_HIGHLIGHT_COMMENT",
+	}
+	AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType_value = map[string]int32{
+		"AI_RICH_RESPONSE_CODE_HIGHLIGHT_DEFAULT": 0,
+		"AI_RICH_RESPONSE_CODE_HIGHLIGHT_KEYWORD": 1,
+		"AI_RICH_RESPONSE_CODE_HIGHLIGHT_METHOD":  2,
+		"AI_RICH_RESPONSE_CODE_HIGHLIGHT_STRING":  3,
+		"AI_RICH_RESPONSE_CODE_HIGHLIGHT_NUMBER":  4,
+		"AI_RICH_RESPONSE_CODE_HIGHLIGHT_COMMENT": 5,
+	}
+)
+
+func (x AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType) Enum() *AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType {
+	p := new(AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType)
+	*p = x
+	return p
+}
+
+func (x AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[32].Descriptor()
+}
+
+func (AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[32]
+}
+
+func (x AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType(num)
+	return nil
+}
+
+// Deprecated: Use AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType.Descriptor instead.
+func (AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{18, 0}
+}
+
+type AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType int32
+
+const (
+	AIRichResponseDynamicMetadata_AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_UNKNOWN AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType = 0
+	AIRichResponseDynamicMetadata_AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_IMAGE   AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType = 1
+	AIRichResponseDynamicMetadata_AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF     AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType = 2
+)
+
+// Enum value maps for AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType.
+var (
+	AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType_name = map[int32]string{
+		0: "AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_UNKNOWN",
+		1: "AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_IMAGE",
+		2: "AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF",
+	}
+	AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType_value = map[string]int32{
+		"AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_UNKNOWN": 0,
+		"AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_IMAGE":   1,
+		"AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF":     2,
+	}
+)
+
+func (x AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType) Enum() *AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType {
+	p := new(AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType)
+	*p = x
+	return p
+}
+
+func (x AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[33].Descriptor()
+}
+
+func (AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[33]
+}
+
+func (x AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType(num)
+	return nil
+}
+
+// Deprecated: Use AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType.Descriptor instead.
+func (AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{19, 0}
+}
+
+type AIRichResponseContentItemsMetadata_ContentType int32
+
+const (
+	AIRichResponseContentItemsMetadata_DEFAULT  AIRichResponseContentItemsMetadata_ContentType = 0
+	AIRichResponseContentItemsMetadata_CAROUSEL AIRichResponseContentItemsMetadata_ContentType = 1
+)
+
+// Enum value maps for AIRichResponseContentItemsMetadata_ContentType.
+var (
+	AIRichResponseContentItemsMetadata_ContentType_name = map[int32]string{
+		0: "DEFAULT",
+		1: "CAROUSEL",
+	}
+	AIRichResponseContentItemsMetadata_ContentType_value = map[string]int32{
+		"DEFAULT":  0,
+		"CAROUSEL": 1,
+	}
+)
+
+func (x AIRichResponseContentItemsMetadata_ContentType) Enum() *AIRichResponseContentItemsMetadata_ContentType {
+	p := new(AIRichResponseContentItemsMetadata_ContentType)
+	*p = x
+	return p
+}
+
+func (x AIRichResponseContentItemsMetadata_ContentType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIRichResponseContentItemsMetadata_ContentType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[34].Descriptor()
+}
+
+func (AIRichResponseContentItemsMetadata_ContentType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[34]
+}
+
+func (x AIRichResponseContentItemsMetadata_ContentType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIRichResponseContentItemsMetadata_ContentType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIRichResponseContentItemsMetadata_ContentType(num)
+	return nil
+}
+
+// Deprecated: Use AIRichResponseContentItemsMetadata_ContentType.Descriptor instead.
+func (AIRichResponseContentItemsMetadata_ContentType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{20, 0}
+}
+
+type BotDocumentMessageMetadata_DocumentPluginType int32
+
+const (
+	BotDocumentMessageMetadata_TEXT_EXTRACTION BotDocumentMessageMetadata_DocumentPluginType = 0
+	BotDocumentMessageMetadata_OCR_AND_IMAGES  BotDocumentMessageMetadata_DocumentPluginType = 1
+)
+
+// Enum value maps for BotDocumentMessageMetadata_DocumentPluginType.
+var (
+	BotDocumentMessageMetadata_DocumentPluginType_name = map[int32]string{
+		0: "TEXT_EXTRACTION",
+		1: "OCR_AND_IMAGES",
+	}
+	BotDocumentMessageMetadata_DocumentPluginType_value = map[string]int32{
+		"TEXT_EXTRACTION": 0,
+		"OCR_AND_IMAGES":  1,
+	}
+)
+
+func (x BotDocumentMessageMetadata_DocumentPluginType) Enum() *BotDocumentMessageMetadata_DocumentPluginType {
+	p := new(BotDocumentMessageMetadata_DocumentPluginType)
+	*p = x
+	return p
+}
+
+func (x BotDocumentMessageMetadata_DocumentPluginType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (BotDocumentMessageMetadata_DocumentPluginType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[35].Descriptor()
+}
+
+func (BotDocumentMessageMetadata_DocumentPluginType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[35]
+}
+
+func (x BotDocumentMessageMetadata_DocumentPluginType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *BotDocumentMessageMetadata_DocumentPluginType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = BotDocumentMessageMetadata_DocumentPluginType(num)
+	return nil
+}
+
+// Deprecated: Use BotDocumentMessageMetadata_DocumentPluginType.Descriptor instead.
+func (BotDocumentMessageMetadata_DocumentPluginType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{21, 0}
+}
+
+type AIHomeState_AIHomeOption_AIHomeActionType int32
+
+const (
+	AIHomeState_AIHomeOption_PROMPT        AIHomeState_AIHomeOption_AIHomeActionType = 0
+	AIHomeState_AIHomeOption_CREATE_IMAGE  AIHomeState_AIHomeOption_AIHomeActionType = 1
+	AIHomeState_AIHomeOption_ANIMATE_PHOTO AIHomeState_AIHomeOption_AIHomeActionType = 2
+	AIHomeState_AIHomeOption_ANALYZE_FILE  AIHomeState_AIHomeOption_AIHomeActionType = 3
+)
+
+// Enum value maps for AIHomeState_AIHomeOption_AIHomeActionType.
+var (
+	AIHomeState_AIHomeOption_AIHomeActionType_name = map[int32]string{
+		0: "PROMPT",
+		1: "CREATE_IMAGE",
+		2: "ANIMATE_PHOTO",
+		3: "ANALYZE_FILE",
+	}
+	AIHomeState_AIHomeOption_AIHomeActionType_value = map[string]int32{
+		"PROMPT":        0,
+		"CREATE_IMAGE":  1,
+		"ANIMATE_PHOTO": 2,
+		"ANALYZE_FILE":  3,
+	}
+)
+
+func (x AIHomeState_AIHomeOption_AIHomeActionType) Enum() *AIHomeState_AIHomeOption_AIHomeActionType {
+	p := new(AIHomeState_AIHomeOption_AIHomeActionType)
+	*p = x
+	return p
+}
+
+func (x AIHomeState_AIHomeOption_AIHomeActionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AIHomeState_AIHomeOption_AIHomeActionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAICommon_WAAICommon_proto_enumTypes[36].Descriptor()
+}
+
+func (AIHomeState_AIHomeOption_AIHomeActionType) Type() protoreflect.EnumType {
+	return &file_waAICommon_WAAICommon_proto_enumTypes[36]
+}
+
+func (x AIHomeState_AIHomeOption_AIHomeActionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *AIHomeState_AIHomeOption_AIHomeActionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = AIHomeState_AIHomeOption_AIHomeActionType(num)
+	return nil
+}
+
+// Deprecated: Use AIHomeState_AIHomeOption_AIHomeActionType.Descriptor instead.
+func (AIHomeState_AIHomeOption_AIHomeActionType) EnumDescriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{22, 0, 0}
+}
+
+type BotPluginMetadata struct {
+	state                  protoimpl.MessageState            `protogen:"open.v1"`
+	Provider               *BotPluginMetadata_SearchProvider `protobuf:"varint,1,opt,name=provider,enum=WAAICommon.BotPluginMetadata_SearchProvider" json:"provider,omitempty"`
+	PluginType             *BotPluginMetadata_PluginType     `protobuf:"varint,2,opt,name=pluginType,enum=WAAICommon.BotPluginMetadata_PluginType" json:"pluginType,omitempty"`
+	ThumbnailCDNURL        *string                           `protobuf:"bytes,3,opt,name=thumbnailCDNURL" json:"thumbnailCDNURL,omitempty"`
+	ProfilePhotoCDNURL     *string                           `protobuf:"bytes,4,opt,name=profilePhotoCDNURL" json:"profilePhotoCDNURL,omitempty"`
+	SearchProviderURL      *string                           `protobuf:"bytes,5,opt,name=searchProviderURL" json:"searchProviderURL,omitempty"`
+	ReferenceIndex         *uint32                           `protobuf:"varint,6,opt,name=referenceIndex" json:"referenceIndex,omitempty"`
+	ExpectedLinksCount     *uint32                           `protobuf:"varint,7,opt,name=expectedLinksCount" json:"expectedLinksCount,omitempty"`
+	SearchQuery            *string                           `protobuf:"bytes,9,opt,name=searchQuery" json:"searchQuery,omitempty"`
+	ParentPluginMessageKey *waCommon.MessageKey              `protobuf:"bytes,10,opt,name=parentPluginMessageKey" json:"parentPluginMessageKey,omitempty"`
+	DeprecatedField        *BotPluginMetadata_PluginType     `protobuf:"varint,11,opt,name=deprecatedField,enum=WAAICommon.BotPluginMetadata_PluginType" json:"deprecatedField,omitempty"`
+	ParentPluginType       *BotPluginMetadata_PluginType     `protobuf:"varint,12,opt,name=parentPluginType,enum=WAAICommon.BotPluginMetadata_PluginType" json:"parentPluginType,omitempty"`
+	FaviconCDNURL          *string                           `protobuf:"bytes,13,opt,name=faviconCDNURL" json:"faviconCDNURL,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *BotPluginMetadata) Reset() {
+	*x = BotPluginMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotPluginMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotPluginMetadata) ProtoMessage() {}
+
+func (x *BotPluginMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotPluginMetadata.ProtoReflect.Descriptor instead.
+func (*BotPluginMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *BotPluginMetadata) GetProvider() BotPluginMetadata_SearchProvider {
+	if x != nil && x.Provider != nil {
+		return *x.Provider
+	}
+	return BotPluginMetadata_UNKNOWN
+}
+
+func (x *BotPluginMetadata) GetPluginType() BotPluginMetadata_PluginType {
+	if x != nil && x.PluginType != nil {
+		return *x.PluginType
+	}
+	return BotPluginMetadata_UNKNOWN_PLUGIN
+}
+
+func (x *BotPluginMetadata) GetThumbnailCDNURL() string {
+	if x != nil && x.ThumbnailCDNURL != nil {
+		return *x.ThumbnailCDNURL
+	}
+	return ""
+}
+
+func (x *BotPluginMetadata) GetProfilePhotoCDNURL() string {
+	if x != nil && x.ProfilePhotoCDNURL != nil {
+		return *x.ProfilePhotoCDNURL
+	}
+	return ""
+}
+
+func (x *BotPluginMetadata) GetSearchProviderURL() string {
+	if x != nil && x.SearchProviderURL != nil {
+		return *x.SearchProviderURL
+	}
+	return ""
+}
+
+func (x *BotPluginMetadata) GetReferenceIndex() uint32 {
+	if x != nil && x.ReferenceIndex != nil {
+		return *x.ReferenceIndex
+	}
+	return 0
+}
+
+func (x *BotPluginMetadata) GetExpectedLinksCount() uint32 {
+	if x != nil && x.ExpectedLinksCount != nil {
+		return *x.ExpectedLinksCount
+	}
+	return 0
+}
+
+func (x *BotPluginMetadata) GetSearchQuery() string {
+	if x != nil && x.SearchQuery != nil {
+		return *x.SearchQuery
+	}
+	return ""
+}
+
+func (x *BotPluginMetadata) GetParentPluginMessageKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.ParentPluginMessageKey
+	}
+	return nil
+}
+
+func (x *BotPluginMetadata) GetDeprecatedField() BotPluginMetadata_PluginType {
+	if x != nil && x.DeprecatedField != nil {
+		return *x.DeprecatedField
+	}
+	return BotPluginMetadata_UNKNOWN_PLUGIN
+}
+
+func (x *BotPluginMetadata) GetParentPluginType() BotPluginMetadata_PluginType {
+	if x != nil && x.ParentPluginType != nil {
+		return *x.ParentPluginType
+	}
+	return BotPluginMetadata_UNKNOWN_PLUGIN
+}
+
+func (x *BotPluginMetadata) GetFaviconCDNURL() string {
+	if x != nil && x.FaviconCDNURL != nil {
+		return *x.FaviconCDNURL
+	}
+	return ""
+}
+
+type BotLinkedAccount struct {
+	state         protoimpl.MessageState                 `protogen:"open.v1"`
+	Type          *BotLinkedAccount_BotLinkedAccountType `protobuf:"varint,1,opt,name=type,enum=WAAICommon.BotLinkedAccount_BotLinkedAccountType" json:"type,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotLinkedAccount) Reset() {
+	*x = BotLinkedAccount{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotLinkedAccount) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotLinkedAccount) ProtoMessage() {}
+
+func (x *BotLinkedAccount) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotLinkedAccount.ProtoReflect.Descriptor instead.
+func (*BotLinkedAccount) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *BotLinkedAccount) GetType() BotLinkedAccount_BotLinkedAccountType {
+	if x != nil && x.Type != nil {
+		return *x.Type
+	}
+	return BotLinkedAccount_BOT_LINKED_ACCOUNT_TYPE_1P
+}
+
+type BotSignatureVerificationUseCaseProof struct {
+	state            protoimpl.MessageState                                    `protogen:"open.v1"`
+	Version          *int32                                                    `protobuf:"varint,1,opt,name=version" json:"version,omitempty"`
+	UseCase          *BotSignatureVerificationUseCaseProof_BotSignatureUseCase `protobuf:"varint,2,opt,name=useCase,enum=WAAICommon.BotSignatureVerificationUseCaseProof_BotSignatureUseCase" json:"useCase,omitempty"`
+	Signature        []byte                                                    `protobuf:"bytes,3,opt,name=signature" json:"signature,omitempty"`
+	CertificateChain [][]byte                                                  `protobuf:"bytes,4,rep,name=certificateChain" json:"certificateChain,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *BotSignatureVerificationUseCaseProof) Reset() {
+	*x = BotSignatureVerificationUseCaseProof{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotSignatureVerificationUseCaseProof) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotSignatureVerificationUseCaseProof) ProtoMessage() {}
+
+func (x *BotSignatureVerificationUseCaseProof) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotSignatureVerificationUseCaseProof.ProtoReflect.Descriptor instead.
+func (*BotSignatureVerificationUseCaseProof) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *BotSignatureVerificationUseCaseProof) GetVersion() int32 {
+	if x != nil && x.Version != nil {
+		return *x.Version
+	}
+	return 0
+}
+
+func (x *BotSignatureVerificationUseCaseProof) GetUseCase() BotSignatureVerificationUseCaseProof_BotSignatureUseCase {
+	if x != nil && x.UseCase != nil {
+		return *x.UseCase
+	}
+	return BotSignatureVerificationUseCaseProof_UNSPECIFIED
+}
+
+func (x *BotSignatureVerificationUseCaseProof) GetSignature() []byte {
+	if x != nil {
+		return x.Signature
+	}
+	return nil
+}
+
+func (x *BotSignatureVerificationUseCaseProof) GetCertificateChain() [][]byte {
+	if x != nil {
+		return x.CertificateChain
+	}
+	return nil
+}
+
+type BotPromotionMessageMetadata struct {
+	state         protoimpl.MessageState                        `protogen:"open.v1"`
+	PromotionType *BotPromotionMessageMetadata_BotPromotionType `protobuf:"varint,1,opt,name=promotionType,enum=WAAICommon.BotPromotionMessageMetadata_BotPromotionType" json:"promotionType,omitempty"`
+	ButtonTitle   *string                                       `protobuf:"bytes,2,opt,name=buttonTitle" json:"buttonTitle,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotPromotionMessageMetadata) Reset() {
+	*x = BotPromotionMessageMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotPromotionMessageMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotPromotionMessageMetadata) ProtoMessage() {}
+
+func (x *BotPromotionMessageMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotPromotionMessageMetadata.ProtoReflect.Descriptor instead.
+func (*BotPromotionMessageMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *BotPromotionMessageMetadata) GetPromotionType() BotPromotionMessageMetadata_BotPromotionType {
+	if x != nil && x.PromotionType != nil {
+		return *x.PromotionType
+	}
+	return BotPromotionMessageMetadata_UNKNOWN_TYPE
+}
+
+func (x *BotPromotionMessageMetadata) GetButtonTitle() string {
+	if x != nil && x.ButtonTitle != nil {
+		return *x.ButtonTitle
+	}
+	return ""
+}
+
+type BotMediaMetadata struct {
+	state             protoimpl.MessageState            `protogen:"open.v1"`
+	FileSHA256        *string                           `protobuf:"bytes,1,opt,name=fileSHA256" json:"fileSHA256,omitempty"`
+	MediaKey          *string                           `protobuf:"bytes,2,opt,name=mediaKey" json:"mediaKey,omitempty"`
+	FileEncSHA256     *string                           `protobuf:"bytes,3,opt,name=fileEncSHA256" json:"fileEncSHA256,omitempty"`
+	DirectPath        *string                           `protobuf:"bytes,4,opt,name=directPath" json:"directPath,omitempty"`
+	MediaKeyTimestamp *int64                            `protobuf:"varint,5,opt,name=mediaKeyTimestamp" json:"mediaKeyTimestamp,omitempty"`
+	Mimetype          *string                           `protobuf:"bytes,6,opt,name=mimetype" json:"mimetype,omitempty"`
+	OrientationType   *BotMediaMetadata_OrientationType `protobuf:"varint,7,opt,name=orientationType,enum=WAAICommon.BotMediaMetadata_OrientationType" json:"orientationType,omitempty"`
+	unknownFields     protoimpl.UnknownFields
+	sizeCache         protoimpl.SizeCache
+}
+
+func (x *BotMediaMetadata) Reset() {
+	*x = BotMediaMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMediaMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMediaMetadata) ProtoMessage() {}
+
+func (x *BotMediaMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMediaMetadata.ProtoReflect.Descriptor instead.
+func (*BotMediaMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *BotMediaMetadata) GetFileSHA256() string {
+	if x != nil && x.FileSHA256 != nil {
+		return *x.FileSHA256
+	}
+	return ""
+}
+
+func (x *BotMediaMetadata) GetMediaKey() string {
+	if x != nil && x.MediaKey != nil {
+		return *x.MediaKey
+	}
+	return ""
+}
+
+func (x *BotMediaMetadata) GetFileEncSHA256() string {
+	if x != nil && x.FileEncSHA256 != nil {
+		return *x.FileEncSHA256
+	}
+	return ""
+}
+
+func (x *BotMediaMetadata) GetDirectPath() string {
+	if x != nil && x.DirectPath != nil {
+		return *x.DirectPath
+	}
+	return ""
+}
+
+func (x *BotMediaMetadata) GetMediaKeyTimestamp() int64 {
+	if x != nil && x.MediaKeyTimestamp != nil {
+		return *x.MediaKeyTimestamp
+	}
+	return 0
+}
+
+func (x *BotMediaMetadata) GetMimetype() string {
+	if x != nil && x.Mimetype != nil {
+		return *x.Mimetype
+	}
+	return ""
+}
+
+func (x *BotMediaMetadata) GetOrientationType() BotMediaMetadata_OrientationType {
+	if x != nil && x.OrientationType != nil {
+		return *x.OrientationType
+	}
+	return BotMediaMetadata_CENTER
+}
+
+type BotReminderMetadata struct {
+	state                protoimpl.MessageState                 `protogen:"open.v1"`
+	RequestMessageKey    *waCommon.MessageKey                   `protobuf:"bytes,1,opt,name=requestMessageKey" json:"requestMessageKey,omitempty"`
+	Action               *BotReminderMetadata_ReminderAction    `protobuf:"varint,2,opt,name=action,enum=WAAICommon.BotReminderMetadata_ReminderAction" json:"action,omitempty"`
+	Name                 *string                                `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"`
+	NextTriggerTimestamp *uint64                                `protobuf:"varint,4,opt,name=nextTriggerTimestamp" json:"nextTriggerTimestamp,omitempty"`
+	Frequency            *BotReminderMetadata_ReminderFrequency `protobuf:"varint,5,opt,name=frequency,enum=WAAICommon.BotReminderMetadata_ReminderFrequency" json:"frequency,omitempty"`
+	unknownFields        protoimpl.UnknownFields
+	sizeCache            protoimpl.SizeCache
+}
+
+func (x *BotReminderMetadata) Reset() {
+	*x = BotReminderMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotReminderMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotReminderMetadata) ProtoMessage() {}
+
+func (x *BotReminderMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotReminderMetadata.ProtoReflect.Descriptor instead.
+func (*BotReminderMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *BotReminderMetadata) GetRequestMessageKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.RequestMessageKey
+	}
+	return nil
+}
+
+func (x *BotReminderMetadata) GetAction() BotReminderMetadata_ReminderAction {
+	if x != nil && x.Action != nil {
+		return *x.Action
+	}
+	return BotReminderMetadata_NOTIFY
+}
+
+func (x *BotReminderMetadata) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *BotReminderMetadata) GetNextTriggerTimestamp() uint64 {
+	if x != nil && x.NextTriggerTimestamp != nil {
+		return *x.NextTriggerTimestamp
+	}
+	return 0
+}
+
+func (x *BotReminderMetadata) GetFrequency() BotReminderMetadata_ReminderFrequency {
+	if x != nil && x.Frequency != nil {
+		return *x.Frequency
+	}
+	return BotReminderMetadata_ONCE
+}
+
+type BotModelMetadata struct {
+	state              protoimpl.MessageState               `protogen:"open.v1"`
+	ModelType          *BotModelMetadata_ModelType          `protobuf:"varint,1,opt,name=modelType,enum=WAAICommon.BotModelMetadata_ModelType" json:"modelType,omitempty"`
+	PremiumModelStatus *BotModelMetadata_PremiumModelStatus `protobuf:"varint,2,opt,name=premiumModelStatus,enum=WAAICommon.BotModelMetadata_PremiumModelStatus" json:"premiumModelStatus,omitempty"`
+	ModelNameOverride  *string                              `protobuf:"bytes,3,opt,name=modelNameOverride" json:"modelNameOverride,omitempty"`
+	unknownFields      protoimpl.UnknownFields
+	sizeCache          protoimpl.SizeCache
+}
+
+func (x *BotModelMetadata) Reset() {
+	*x = BotModelMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotModelMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotModelMetadata) ProtoMessage() {}
+
+func (x *BotModelMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotModelMetadata.ProtoReflect.Descriptor instead.
+func (*BotModelMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *BotModelMetadata) GetModelType() BotModelMetadata_ModelType {
+	if x != nil && x.ModelType != nil {
+		return *x.ModelType
+	}
+	return BotModelMetadata_UNKNOWN_TYPE
+}
+
+func (x *BotModelMetadata) GetPremiumModelStatus() BotModelMetadata_PremiumModelStatus {
+	if x != nil && x.PremiumModelStatus != nil {
+		return *x.PremiumModelStatus
+	}
+	return BotModelMetadata_UNKNOWN_STATUS
+}
+
+func (x *BotModelMetadata) GetModelNameOverride() string {
+	if x != nil && x.ModelNameOverride != nil {
+		return *x.ModelNameOverride
+	}
+	return ""
+}
+
+type BotProgressIndicatorMetadata struct {
+	state               protoimpl.MessageState                                  `protogen:"open.v1"`
+	ProgressDescription *string                                                 `protobuf:"bytes,1,opt,name=progressDescription" json:"progressDescription,omitempty"`
+	StepsMetadata       []*BotProgressIndicatorMetadata_BotPlanningStepMetadata `protobuf:"bytes,2,rep,name=stepsMetadata" json:"stepsMetadata,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *BotProgressIndicatorMetadata) Reset() {
+	*x = BotProgressIndicatorMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotProgressIndicatorMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotProgressIndicatorMetadata) ProtoMessage() {}
+
+func (x *BotProgressIndicatorMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata.ProtoReflect.Descriptor instead.
+func (*BotProgressIndicatorMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *BotProgressIndicatorMetadata) GetProgressDescription() string {
+	if x != nil && x.ProgressDescription != nil {
+		return *x.ProgressDescription
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata) GetStepsMetadata() []*BotProgressIndicatorMetadata_BotPlanningStepMetadata {
+	if x != nil {
+		return x.StepsMetadata
+	}
+	return nil
+}
+
+type BotCapabilityMetadata struct {
+	state         protoimpl.MessageState                    `protogen:"open.v1"`
+	Capabilities  []BotCapabilityMetadata_BotCapabilityType `protobuf:"varint,1,rep,name=capabilities,enum=WAAICommon.BotCapabilityMetadata_BotCapabilityType" json:"capabilities,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotCapabilityMetadata) Reset() {
+	*x = BotCapabilityMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotCapabilityMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotCapabilityMetadata) ProtoMessage() {}
+
+func (x *BotCapabilityMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotCapabilityMetadata.ProtoReflect.Descriptor instead.
+func (*BotCapabilityMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *BotCapabilityMetadata) GetCapabilities() []BotCapabilityMetadata_BotCapabilityType {
+	if x != nil {
+		return x.Capabilities
+	}
+	return nil
+}
+
+type BotModeSelectionMetadata struct {
+	state         protoimpl.MessageState                          `protogen:"open.v1"`
+	Mode          []BotModeSelectionMetadata_BotUserSelectionMode `protobuf:"varint,1,rep,name=mode,enum=WAAICommon.BotModeSelectionMetadata_BotUserSelectionMode" json:"mode,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotModeSelectionMetadata) Reset() {
+	*x = BotModeSelectionMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotModeSelectionMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotModeSelectionMetadata) ProtoMessage() {}
+
+func (x *BotModeSelectionMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotModeSelectionMetadata.ProtoReflect.Descriptor instead.
+func (*BotModeSelectionMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *BotModeSelectionMetadata) GetMode() []BotModeSelectionMetadata_BotUserSelectionMode {
+	if x != nil {
+		return x.Mode
+	}
+	return nil
+}
+
+type BotQuotaMetadata struct {
+	state                   protoimpl.MessageState                      `protogen:"open.v1"`
+	BotFeatureQuotaMetadata []*BotQuotaMetadata_BotFeatureQuotaMetadata `protobuf:"bytes,1,rep,name=botFeatureQuotaMetadata" json:"botFeatureQuotaMetadata,omitempty"`
+	unknownFields           protoimpl.UnknownFields
+	sizeCache               protoimpl.SizeCache
+}
+
+func (x *BotQuotaMetadata) Reset() {
+	*x = BotQuotaMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotQuotaMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotQuotaMetadata) ProtoMessage() {}
+
+func (x *BotQuotaMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotQuotaMetadata.ProtoReflect.Descriptor instead.
+func (*BotQuotaMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *BotQuotaMetadata) GetBotFeatureQuotaMetadata() []*BotQuotaMetadata_BotFeatureQuotaMetadata {
+	if x != nil {
+		return x.BotFeatureQuotaMetadata
+	}
+	return nil
+}
+
+type BotImagineMetadata struct {
+	state         protoimpl.MessageState          `protogen:"open.v1"`
+	ImagineType   *BotImagineMetadata_ImagineType `protobuf:"varint,1,opt,name=imagineType,enum=WAAICommon.BotImagineMetadata_ImagineType" json:"imagineType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotImagineMetadata) Reset() {
+	*x = BotImagineMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotImagineMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotImagineMetadata) ProtoMessage() {}
+
+func (x *BotImagineMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotImagineMetadata.ProtoReflect.Descriptor instead.
+func (*BotImagineMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *BotImagineMetadata) GetImagineType() BotImagineMetadata_ImagineType {
+	if x != nil && x.ImagineType != nil {
+		return *x.ImagineType
+	}
+	return BotImagineMetadata_UNKNOWN
+}
+
+type BotAgeCollectionMetadata struct {
+	state                              protoimpl.MessageState                      `protogen:"open.v1"`
+	AgeCollectionEligible              *bool                                       `protobuf:"varint,1,opt,name=ageCollectionEligible" json:"ageCollectionEligible,omitempty"`
+	ShouldTriggerAgeCollectionOnClient *bool                                       `protobuf:"varint,2,opt,name=shouldTriggerAgeCollectionOnClient" json:"shouldTriggerAgeCollectionOnClient,omitempty"`
+	AgeCollectionType                  *BotAgeCollectionMetadata_AgeCollectionType `protobuf:"varint,3,opt,name=ageCollectionType,enum=WAAICommon.BotAgeCollectionMetadata_AgeCollectionType" json:"ageCollectionType,omitempty"`
+	unknownFields                      protoimpl.UnknownFields
+	sizeCache                          protoimpl.SizeCache
+}
+
+func (x *BotAgeCollectionMetadata) Reset() {
+	*x = BotAgeCollectionMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[12]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotAgeCollectionMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotAgeCollectionMetadata) ProtoMessage() {}
+
+func (x *BotAgeCollectionMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[12]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotAgeCollectionMetadata.ProtoReflect.Descriptor instead.
+func (*BotAgeCollectionMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *BotAgeCollectionMetadata) GetAgeCollectionEligible() bool {
+	if x != nil && x.AgeCollectionEligible != nil {
+		return *x.AgeCollectionEligible
+	}
+	return false
+}
+
+func (x *BotAgeCollectionMetadata) GetShouldTriggerAgeCollectionOnClient() bool {
+	if x != nil && x.ShouldTriggerAgeCollectionOnClient != nil {
+		return *x.ShouldTriggerAgeCollectionOnClient
+	}
+	return false
+}
+
+func (x *BotAgeCollectionMetadata) GetAgeCollectionType() BotAgeCollectionMetadata_AgeCollectionType {
+	if x != nil && x.AgeCollectionType != nil {
+		return *x.AgeCollectionType
+	}
+	return BotAgeCollectionMetadata_O18_BINARY
+}
+
+type BotSourcesMetadata struct {
+	state         protoimpl.MessageState              `protogen:"open.v1"`
+	Sources       []*BotSourcesMetadata_BotSourceItem `protobuf:"bytes,1,rep,name=sources" json:"sources,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotSourcesMetadata) Reset() {
+	*x = BotSourcesMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[13]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotSourcesMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotSourcesMetadata) ProtoMessage() {}
+
+func (x *BotSourcesMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[13]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotSourcesMetadata.ProtoReflect.Descriptor instead.
+func (*BotSourcesMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *BotSourcesMetadata) GetSources() []*BotSourcesMetadata_BotSourceItem {
+	if x != nil {
+		return x.Sources
+	}
+	return nil
+}
+
+type BotMessageOrigin struct {
+	state         protoimpl.MessageState                 `protogen:"open.v1"`
+	Type          *BotMessageOrigin_BotMessageOriginType `protobuf:"varint,1,opt,name=type,enum=WAAICommon.BotMessageOrigin_BotMessageOriginType" json:"type,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotMessageOrigin) Reset() {
+	*x = BotMessageOrigin{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[14]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMessageOrigin) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMessageOrigin) ProtoMessage() {}
+
+func (x *BotMessageOrigin) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[14]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMessageOrigin.ProtoReflect.Descriptor instead.
+func (*BotMessageOrigin) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *BotMessageOrigin) GetType() BotMessageOrigin_BotMessageOriginType {
+	if x != nil && x.Type != nil {
+		return *x.Type
+	}
+	return BotMessageOrigin_BOT_MESSAGE_ORIGIN_TYPE_AI_INITIATED
+}
+
+type AIThreadInfo struct {
+	state         protoimpl.MessageState           `protogen:"open.v1"`
+	ServerInfo    *AIThreadInfo_AIThreadServerInfo `protobuf:"bytes,1,opt,name=serverInfo" json:"serverInfo,omitempty"`
+	ClientInfo    *AIThreadInfo_AIThreadClientInfo `protobuf:"bytes,2,opt,name=clientInfo" json:"clientInfo,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIThreadInfo) Reset() {
+	*x = AIThreadInfo{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[15]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIThreadInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIThreadInfo) ProtoMessage() {}
+
+func (x *AIThreadInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[15]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIThreadInfo.ProtoReflect.Descriptor instead.
+func (*AIThreadInfo) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *AIThreadInfo) GetServerInfo() *AIThreadInfo_AIThreadServerInfo {
+	if x != nil {
+		return x.ServerInfo
+	}
+	return nil
+}
+
+func (x *AIThreadInfo) GetClientInfo() *AIThreadInfo_AIThreadClientInfo {
+	if x != nil {
+		return x.ClientInfo
+	}
+	return nil
+}
+
+type BotFeedbackMessage struct {
+	state                    protoimpl.MessageState                       `protogen:"open.v1"`
+	MessageKey               *waCommon.MessageKey                         `protobuf:"bytes,1,opt,name=messageKey" json:"messageKey,omitempty"`
+	Kind                     *BotFeedbackMessage_BotFeedbackKind          `protobuf:"varint,2,opt,name=kind,enum=WAAICommon.BotFeedbackMessage_BotFeedbackKind" json:"kind,omitempty"`
+	Text                     *string                                      `protobuf:"bytes,3,opt,name=text" json:"text,omitempty"`
+	KindNegative             *uint64                                      `protobuf:"varint,4,opt,name=kindNegative" json:"kindNegative,omitempty"`
+	KindPositive             *uint64                                      `protobuf:"varint,5,opt,name=kindPositive" json:"kindPositive,omitempty"`
+	KindReport               *BotFeedbackMessage_ReportKind               `protobuf:"varint,6,opt,name=kindReport,enum=WAAICommon.BotFeedbackMessage_ReportKind" json:"kindReport,omitempty"`
+	SideBySideSurveyMetadata *BotFeedbackMessage_SideBySideSurveyMetadata `protobuf:"bytes,7,opt,name=sideBySideSurveyMetadata" json:"sideBySideSurveyMetadata,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage) Reset() {
+	*x = BotFeedbackMessage{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[16]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage) ProtoMessage() {}
+
+func (x *BotFeedbackMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[16]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *BotFeedbackMessage) GetMessageKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.MessageKey
+	}
+	return nil
+}
+
+func (x *BotFeedbackMessage) GetKind() BotFeedbackMessage_BotFeedbackKind {
+	if x != nil && x.Kind != nil {
+		return *x.Kind
+	}
+	return BotFeedbackMessage_BOT_FEEDBACK_POSITIVE
+}
+
+func (x *BotFeedbackMessage) GetText() string {
+	if x != nil && x.Text != nil {
+		return *x.Text
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage) GetKindNegative() uint64 {
+	if x != nil && x.KindNegative != nil {
+		return *x.KindNegative
+	}
+	return 0
+}
+
+func (x *BotFeedbackMessage) GetKindPositive() uint64 {
+	if x != nil && x.KindPositive != nil {
+		return *x.KindPositive
+	}
+	return 0
+}
+
+func (x *BotFeedbackMessage) GetKindReport() BotFeedbackMessage_ReportKind {
+	if x != nil && x.KindReport != nil {
+		return *x.KindReport
+	}
+	return BotFeedbackMessage_NONE
+}
+
+func (x *BotFeedbackMessage) GetSideBySideSurveyMetadata() *BotFeedbackMessage_SideBySideSurveyMetadata {
+	if x != nil {
+		return x.SideBySideSurveyMetadata
+	}
+	return nil
+}
+
+type AIRichResponseInlineImageMetadata struct {
+	state         protoimpl.MessageState                                          `protogen:"open.v1"`
+	ImageURL      *AIRichResponseImageURL                                         `protobuf:"bytes,1,opt,name=imageURL" json:"imageURL,omitempty"`
+	ImageText     *string                                                         `protobuf:"bytes,2,opt,name=imageText" json:"imageText,omitempty"`
+	Alignment     *AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment `protobuf:"varint,3,opt,name=alignment,enum=WAAICommon.AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment" json:"alignment,omitempty"`
+	TapLinkURL    *string                                                         `protobuf:"bytes,4,opt,name=tapLinkURL" json:"tapLinkURL,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseInlineImageMetadata) Reset() {
+	*x = AIRichResponseInlineImageMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[17]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseInlineImageMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseInlineImageMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseInlineImageMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[17]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseInlineImageMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseInlineImageMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *AIRichResponseInlineImageMetadata) GetImageURL() *AIRichResponseImageURL {
+	if x != nil {
+		return x.ImageURL
+	}
+	return nil
+}
+
+func (x *AIRichResponseInlineImageMetadata) GetImageText() string {
+	if x != nil && x.ImageText != nil {
+		return *x.ImageText
+	}
+	return ""
+}
+
+func (x *AIRichResponseInlineImageMetadata) GetAlignment() AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment {
+	if x != nil && x.Alignment != nil {
+		return *x.Alignment
+	}
+	return AIRichResponseInlineImageMetadata_AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED
+}
+
+func (x *AIRichResponseInlineImageMetadata) GetTapLinkURL() string {
+	if x != nil && x.TapLinkURL != nil {
+		return *x.TapLinkURL
+	}
+	return ""
+}
+
+type AIRichResponseCodeMetadata struct {
+	state         protoimpl.MessageState                                `protogen:"open.v1"`
+	CodeLanguage  *string                                               `protobuf:"bytes,1,opt,name=codeLanguage" json:"codeLanguage,omitempty"`
+	CodeBlocks    []*AIRichResponseCodeMetadata_AIRichResponseCodeBlock `protobuf:"bytes,2,rep,name=codeBlocks" json:"codeBlocks,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseCodeMetadata) Reset() {
+	*x = AIRichResponseCodeMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[18]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseCodeMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseCodeMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseCodeMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[18]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseCodeMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseCodeMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *AIRichResponseCodeMetadata) GetCodeLanguage() string {
+	if x != nil && x.CodeLanguage != nil {
+		return *x.CodeLanguage
+	}
+	return ""
+}
+
+func (x *AIRichResponseCodeMetadata) GetCodeBlocks() []*AIRichResponseCodeMetadata_AIRichResponseCodeBlock {
+	if x != nil {
+		return x.CodeBlocks
+	}
+	return nil
+}
+
+type AIRichResponseDynamicMetadata struct {
+	state         protoimpl.MessageState                                           `protogen:"open.v1"`
+	Type          *AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType `protobuf:"varint,1,opt,name=type,enum=WAAICommon.AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType" json:"type,omitempty"`
+	Version       *uint64                                                          `protobuf:"varint,2,opt,name=version" json:"version,omitempty"`
+	URL           *string                                                          `protobuf:"bytes,3,opt,name=URL" json:"URL,omitempty"`
+	LoopCount     *uint32                                                          `protobuf:"varint,4,opt,name=loopCount" json:"loopCount,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseDynamicMetadata) Reset() {
+	*x = AIRichResponseDynamicMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[19]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseDynamicMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseDynamicMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseDynamicMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[19]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseDynamicMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseDynamicMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *AIRichResponseDynamicMetadata) GetType() AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType {
+	if x != nil && x.Type != nil {
+		return *x.Type
+	}
+	return AIRichResponseDynamicMetadata_AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_UNKNOWN
+}
+
+func (x *AIRichResponseDynamicMetadata) GetVersion() uint64 {
+	if x != nil && x.Version != nil {
+		return *x.Version
+	}
+	return 0
+}
+
+func (x *AIRichResponseDynamicMetadata) GetURL() string {
+	if x != nil && x.URL != nil {
+		return *x.URL
+	}
+	return ""
+}
+
+func (x *AIRichResponseDynamicMetadata) GetLoopCount() uint32 {
+	if x != nil && x.LoopCount != nil {
+		return *x.LoopCount
+	}
+	return 0
+}
+
+type AIRichResponseContentItemsMetadata struct {
+	state         protoimpl.MessageState                                                  `protogen:"open.v1"`
+	ItemsMetadata []*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata `protobuf:"bytes,1,rep,name=itemsMetadata" json:"itemsMetadata,omitempty"`
+	ContentType   *AIRichResponseContentItemsMetadata_ContentType                         `protobuf:"varint,2,opt,name=contentType,enum=WAAICommon.AIRichResponseContentItemsMetadata_ContentType" json:"contentType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseContentItemsMetadata) Reset() {
+	*x = AIRichResponseContentItemsMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[20]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseContentItemsMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseContentItemsMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseContentItemsMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[20]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseContentItemsMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseContentItemsMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *AIRichResponseContentItemsMetadata) GetItemsMetadata() []*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata {
+	if x != nil {
+		return x.ItemsMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseContentItemsMetadata) GetContentType() AIRichResponseContentItemsMetadata_ContentType {
+	if x != nil && x.ContentType != nil {
+		return *x.ContentType
+	}
+	return AIRichResponseContentItemsMetadata_DEFAULT
+}
+
+type BotDocumentMessageMetadata struct {
+	state         protoimpl.MessageState                         `protogen:"open.v1"`
+	PluginType    *BotDocumentMessageMetadata_DocumentPluginType `protobuf:"varint,1,opt,name=pluginType,enum=WAAICommon.BotDocumentMessageMetadata_DocumentPluginType" json:"pluginType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotDocumentMessageMetadata) Reset() {
+	*x = BotDocumentMessageMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[21]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotDocumentMessageMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotDocumentMessageMetadata) ProtoMessage() {}
+
+func (x *BotDocumentMessageMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[21]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotDocumentMessageMetadata.ProtoReflect.Descriptor instead.
+func (*BotDocumentMessageMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *BotDocumentMessageMetadata) GetPluginType() BotDocumentMessageMetadata_DocumentPluginType {
+	if x != nil && x.PluginType != nil {
+		return *x.PluginType
+	}
+	return BotDocumentMessageMetadata_TEXT_EXTRACTION
+}
+
+type AIHomeState struct {
+	state               protoimpl.MessageState      `protogen:"open.v1"`
+	LastFetchTime       *int64                      `protobuf:"varint,1,opt,name=lastFetchTime" json:"lastFetchTime,omitempty"`
+	CapabilityOptions   []*AIHomeState_AIHomeOption `protobuf:"bytes,2,rep,name=capabilityOptions" json:"capabilityOptions,omitempty"`
+	ConversationOptions []*AIHomeState_AIHomeOption `protobuf:"bytes,3,rep,name=conversationOptions" json:"conversationOptions,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *AIHomeState) Reset() {
+	*x = AIHomeState{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[22]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIHomeState) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIHomeState) ProtoMessage() {}
+
+func (x *AIHomeState) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[22]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIHomeState.ProtoReflect.Descriptor instead.
+func (*AIHomeState) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *AIHomeState) GetLastFetchTime() int64 {
+	if x != nil && x.LastFetchTime != nil {
+		return *x.LastFetchTime
+	}
+	return 0
+}
+
+func (x *AIHomeState) GetCapabilityOptions() []*AIHomeState_AIHomeOption {
+	if x != nil {
+		return x.CapabilityOptions
+	}
+	return nil
+}
+
+func (x *AIHomeState) GetConversationOptions() []*AIHomeState_AIHomeOption {
+	if x != nil {
+		return x.ConversationOptions
+	}
+	return nil
+}
+
+type BotAvatarMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Sentiment     *uint32                `protobuf:"varint,1,opt,name=sentiment" json:"sentiment,omitempty"`
+	BehaviorGraph *string                `protobuf:"bytes,2,opt,name=behaviorGraph" json:"behaviorGraph,omitempty"`
+	Action        *uint32                `protobuf:"varint,3,opt,name=action" json:"action,omitempty"`
+	Intensity     *uint32                `protobuf:"varint,4,opt,name=intensity" json:"intensity,omitempty"`
+	WordCount     *uint32                `protobuf:"varint,5,opt,name=wordCount" json:"wordCount,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotAvatarMetadata) Reset() {
+	*x = BotAvatarMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[23]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotAvatarMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotAvatarMetadata) ProtoMessage() {}
+
+func (x *BotAvatarMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[23]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotAvatarMetadata.ProtoReflect.Descriptor instead.
+func (*BotAvatarMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *BotAvatarMetadata) GetSentiment() uint32 {
+	if x != nil && x.Sentiment != nil {
+		return *x.Sentiment
+	}
+	return 0
+}
+
+func (x *BotAvatarMetadata) GetBehaviorGraph() string {
+	if x != nil && x.BehaviorGraph != nil {
+		return *x.BehaviorGraph
+	}
+	return ""
+}
+
+func (x *BotAvatarMetadata) GetAction() uint32 {
+	if x != nil && x.Action != nil {
+		return *x.Action
+	}
+	return 0
+}
+
+func (x *BotAvatarMetadata) GetIntensity() uint32 {
+	if x != nil && x.Intensity != nil {
+		return *x.Intensity
+	}
+	return 0
+}
+
+func (x *BotAvatarMetadata) GetWordCount() uint32 {
+	if x != nil && x.WordCount != nil {
+		return *x.WordCount
+	}
+	return 0
+}
+
+type BotSuggestedPromptMetadata struct {
+	state               protoimpl.MessageState `protogen:"open.v1"`
+	SuggestedPrompts    []string               `protobuf:"bytes,1,rep,name=suggestedPrompts" json:"suggestedPrompts,omitempty"`
+	SelectedPromptIndex *uint32                `protobuf:"varint,2,opt,name=selectedPromptIndex" json:"selectedPromptIndex,omitempty"`
+	PromptSuggestions   *BotPromptSuggestions  `protobuf:"bytes,3,opt,name=promptSuggestions" json:"promptSuggestions,omitempty"`
+	SelectedPromptID    *string                `protobuf:"bytes,4,opt,name=selectedPromptID" json:"selectedPromptID,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *BotSuggestedPromptMetadata) Reset() {
+	*x = BotSuggestedPromptMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[24]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotSuggestedPromptMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotSuggestedPromptMetadata) ProtoMessage() {}
+
+func (x *BotSuggestedPromptMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[24]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotSuggestedPromptMetadata.ProtoReflect.Descriptor instead.
+func (*BotSuggestedPromptMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *BotSuggestedPromptMetadata) GetSuggestedPrompts() []string {
+	if x != nil {
+		return x.SuggestedPrompts
+	}
+	return nil
+}
+
+func (x *BotSuggestedPromptMetadata) GetSelectedPromptIndex() uint32 {
+	if x != nil && x.SelectedPromptIndex != nil {
+		return *x.SelectedPromptIndex
+	}
+	return 0
+}
+
+func (x *BotSuggestedPromptMetadata) GetPromptSuggestions() *BotPromptSuggestions {
+	if x != nil {
+		return x.PromptSuggestions
+	}
+	return nil
+}
+
+func (x *BotSuggestedPromptMetadata) GetSelectedPromptID() string {
+	if x != nil && x.SelectedPromptID != nil {
+		return *x.SelectedPromptID
+	}
+	return ""
+}
+
+type BotPromptSuggestions struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Suggestions   []*BotPromptSuggestion `protobuf:"bytes,1,rep,name=suggestions" json:"suggestions,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotPromptSuggestions) Reset() {
+	*x = BotPromptSuggestions{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[25]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotPromptSuggestions) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotPromptSuggestions) ProtoMessage() {}
+
+func (x *BotPromptSuggestions) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[25]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotPromptSuggestions.ProtoReflect.Descriptor instead.
+func (*BotPromptSuggestions) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{25}
+}
+
+func (x *BotPromptSuggestions) GetSuggestions() []*BotPromptSuggestion {
+	if x != nil {
+		return x.Suggestions
+	}
+	return nil
+}
+
+type BotPromptSuggestion struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Prompt        *string                `protobuf:"bytes,1,opt,name=prompt" json:"prompt,omitempty"`
+	PromptID      *string                `protobuf:"bytes,2,opt,name=promptID" json:"promptID,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotPromptSuggestion) Reset() {
+	*x = BotPromptSuggestion{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[26]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotPromptSuggestion) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotPromptSuggestion) ProtoMessage() {}
+
+func (x *BotPromptSuggestion) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[26]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotPromptSuggestion.ProtoReflect.Descriptor instead.
+func (*BotPromptSuggestion) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *BotPromptSuggestion) GetPrompt() string {
+	if x != nil && x.Prompt != nil {
+		return *x.Prompt
+	}
+	return ""
+}
+
+func (x *BotPromptSuggestion) GetPromptID() string {
+	if x != nil && x.PromptID != nil {
+		return *x.PromptID
+	}
+	return ""
+}
+
+type BotLinkedAccountsMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Accounts      []*BotLinkedAccount    `protobuf:"bytes,1,rep,name=accounts" json:"accounts,omitempty"`
+	AcAuthTokens  []byte                 `protobuf:"bytes,2,opt,name=acAuthTokens" json:"acAuthTokens,omitempty"`
+	AcErrorCode   *int32                 `protobuf:"varint,3,opt,name=acErrorCode" json:"acErrorCode,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotLinkedAccountsMetadata) Reset() {
+	*x = BotLinkedAccountsMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[27]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotLinkedAccountsMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotLinkedAccountsMetadata) ProtoMessage() {}
+
+func (x *BotLinkedAccountsMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[27]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotLinkedAccountsMetadata.ProtoReflect.Descriptor instead.
+func (*BotLinkedAccountsMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{27}
+}
+
+func (x *BotLinkedAccountsMetadata) GetAccounts() []*BotLinkedAccount {
+	if x != nil {
+		return x.Accounts
+	}
+	return nil
+}
+
+func (x *BotLinkedAccountsMetadata) GetAcAuthTokens() []byte {
+	if x != nil {
+		return x.AcAuthTokens
+	}
+	return nil
+}
+
+func (x *BotLinkedAccountsMetadata) GetAcErrorCode() int32 {
+	if x != nil && x.AcErrorCode != nil {
+		return *x.AcErrorCode
+	}
+	return 0
+}
+
+type BotMemoryMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	AddedFacts    []*BotMemoryFact       `protobuf:"bytes,1,rep,name=addedFacts" json:"addedFacts,omitempty"`
+	RemovedFacts  []*BotMemoryFact       `protobuf:"bytes,2,rep,name=removedFacts" json:"removedFacts,omitempty"`
+	Disclaimer    *string                `protobuf:"bytes,3,opt,name=disclaimer" json:"disclaimer,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotMemoryMetadata) Reset() {
+	*x = BotMemoryMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[28]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMemoryMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMemoryMetadata) ProtoMessage() {}
+
+func (x *BotMemoryMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[28]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMemoryMetadata.ProtoReflect.Descriptor instead.
+func (*BotMemoryMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *BotMemoryMetadata) GetAddedFacts() []*BotMemoryFact {
+	if x != nil {
+		return x.AddedFacts
+	}
+	return nil
+}
+
+func (x *BotMemoryMetadata) GetRemovedFacts() []*BotMemoryFact {
+	if x != nil {
+		return x.RemovedFacts
+	}
+	return nil
+}
+
+func (x *BotMemoryMetadata) GetDisclaimer() string {
+	if x != nil && x.Disclaimer != nil {
+		return *x.Disclaimer
+	}
+	return ""
+}
+
+type BotMemoryFact struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Fact          *string                `protobuf:"bytes,1,opt,name=fact" json:"fact,omitempty"`
+	FactID        *string                `protobuf:"bytes,2,opt,name=factID" json:"factID,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotMemoryFact) Reset() {
+	*x = BotMemoryFact{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[29]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMemoryFact) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMemoryFact) ProtoMessage() {}
+
+func (x *BotMemoryFact) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[29]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMemoryFact.ProtoReflect.Descriptor instead.
+func (*BotMemoryFact) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{29}
+}
+
+func (x *BotMemoryFact) GetFact() string {
+	if x != nil && x.Fact != nil {
+		return *x.Fact
+	}
+	return ""
+}
+
+func (x *BotMemoryFact) GetFactID() string {
+	if x != nil && x.FactID != nil {
+		return *x.FactID
+	}
+	return ""
+}
+
+type BotSignatureVerificationMetadata struct {
+	state         protoimpl.MessageState                  `protogen:"open.v1"`
+	Proofs        []*BotSignatureVerificationUseCaseProof `protobuf:"bytes,1,rep,name=proofs" json:"proofs,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotSignatureVerificationMetadata) Reset() {
+	*x = BotSignatureVerificationMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[30]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotSignatureVerificationMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotSignatureVerificationMetadata) ProtoMessage() {}
+
+func (x *BotSignatureVerificationMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[30]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotSignatureVerificationMetadata.ProtoReflect.Descriptor instead.
+func (*BotSignatureVerificationMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{30}
+}
+
+func (x *BotSignatureVerificationMetadata) GetProofs() []*BotSignatureVerificationUseCaseProof {
+	if x != nil {
+		return x.Proofs
+	}
+	return nil
+}
+
+type BotRenderingMetadata struct {
+	state         protoimpl.MessageState          `protogen:"open.v1"`
+	Keywords      []*BotRenderingMetadata_Keyword `protobuf:"bytes,1,rep,name=keywords" json:"keywords,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotRenderingMetadata) Reset() {
+	*x = BotRenderingMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[31]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotRenderingMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotRenderingMetadata) ProtoMessage() {}
+
+func (x *BotRenderingMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[31]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotRenderingMetadata.ProtoReflect.Descriptor instead.
+func (*BotRenderingMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{31}
+}
+
+func (x *BotRenderingMetadata) GetKeywords() []*BotRenderingMetadata_Keyword {
+	if x != nil {
+		return x.Keywords
+	}
+	return nil
+}
+
+type BotMetricsMetadata struct {
+	state                 protoimpl.MessageState      `protogen:"open.v1"`
+	DestinationID         *string                     `protobuf:"bytes,1,opt,name=destinationID" json:"destinationID,omitempty"`
+	DestinationEntryPoint *BotMetricsEntryPoint       `protobuf:"varint,2,opt,name=destinationEntryPoint,enum=WAAICommon.BotMetricsEntryPoint" json:"destinationEntryPoint,omitempty"`
+	ThreadOrigin          *BotMetricsThreadEntryPoint `protobuf:"varint,3,opt,name=threadOrigin,enum=WAAICommon.BotMetricsThreadEntryPoint" json:"threadOrigin,omitempty"`
+	unknownFields         protoimpl.UnknownFields
+	sizeCache             protoimpl.SizeCache
+}
+
+func (x *BotMetricsMetadata) Reset() {
+	*x = BotMetricsMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[32]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMetricsMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMetricsMetadata) ProtoMessage() {}
+
+func (x *BotMetricsMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[32]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMetricsMetadata.ProtoReflect.Descriptor instead.
+func (*BotMetricsMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{32}
+}
+
+func (x *BotMetricsMetadata) GetDestinationID() string {
+	if x != nil && x.DestinationID != nil {
+		return *x.DestinationID
+	}
+	return ""
+}
+
+func (x *BotMetricsMetadata) GetDestinationEntryPoint() BotMetricsEntryPoint {
+	if x != nil && x.DestinationEntryPoint != nil {
+		return *x.DestinationEntryPoint
+	}
+	return BotMetricsEntryPoint_UNDEFINED_ENTRY_POINT
+}
+
+func (x *BotMetricsMetadata) GetThreadOrigin() BotMetricsThreadEntryPoint {
+	if x != nil && x.ThreadOrigin != nil {
+		return *x.ThreadOrigin
+	}
+	return BotMetricsThreadEntryPoint_AI_TAB_THREAD
+}
+
+type BotSessionMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	SessionID     *string                `protobuf:"bytes,1,opt,name=sessionID" json:"sessionID,omitempty"`
+	SessionSource *BotSessionSource      `protobuf:"varint,2,opt,name=sessionSource,enum=WAAICommon.BotSessionSource" json:"sessionSource,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotSessionMetadata) Reset() {
+	*x = BotSessionMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[33]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotSessionMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotSessionMetadata) ProtoMessage() {}
+
+func (x *BotSessionMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[33]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotSessionMetadata.ProtoReflect.Descriptor instead.
+func (*BotSessionMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{33}
+}
+
+func (x *BotSessionMetadata) GetSessionID() string {
+	if x != nil && x.SessionID != nil {
+		return *x.SessionID
+	}
+	return ""
+}
+
+func (x *BotSessionMetadata) GetSessionSource() BotSessionSource {
+	if x != nil && x.SessionSource != nil {
+		return *x.SessionSource
+	}
+	return BotSessionSource_NONE
+}
+
+type BotMemuMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	FaceImages    []*BotMediaMetadata    `protobuf:"bytes,1,rep,name=faceImages" json:"faceImages,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotMemuMetadata) Reset() {
+	*x = BotMemuMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[34]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMemuMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMemuMetadata) ProtoMessage() {}
+
+func (x *BotMemuMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[34]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMemuMetadata.ProtoReflect.Descriptor instead.
+func (*BotMemuMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{34}
+}
+
+func (x *BotMemuMetadata) GetFaceImages() []*BotMediaMetadata {
+	if x != nil {
+		return x.FaceImages
+	}
+	return nil
+}
+
+type InThreadSurveyMetadata struct {
+	state                    protoimpl.MessageState                                       `protogen:"open.v1"`
+	TessaSessionID           *string                                                      `protobuf:"bytes,1,opt,name=tessaSessionID" json:"tessaSessionID,omitempty"`
+	SimonSessionID           *string                                                      `protobuf:"bytes,2,opt,name=simonSessionID" json:"simonSessionID,omitempty"`
+	SimonSurveyID            *string                                                      `protobuf:"bytes,3,opt,name=simonSurveyID" json:"simonSurveyID,omitempty"`
+	TessaRootID              *string                                                      `protobuf:"bytes,4,opt,name=tessaRootID" json:"tessaRootID,omitempty"`
+	RequestID                *string                                                      `protobuf:"bytes,5,opt,name=requestID" json:"requestID,omitempty"`
+	TessaEvent               *string                                                      `protobuf:"bytes,6,opt,name=tessaEvent" json:"tessaEvent,omitempty"`
+	InvitationHeaderText     *string                                                      `protobuf:"bytes,7,opt,name=invitationHeaderText" json:"invitationHeaderText,omitempty"`
+	InvitationBodyText       *string                                                      `protobuf:"bytes,8,opt,name=invitationBodyText" json:"invitationBodyText,omitempty"`
+	InvitationCtaText        *string                                                      `protobuf:"bytes,9,opt,name=invitationCtaText" json:"invitationCtaText,omitempty"`
+	InvitationCtaURL         *string                                                      `protobuf:"bytes,10,opt,name=invitationCtaURL" json:"invitationCtaURL,omitempty"`
+	SurveyTitle              *string                                                      `protobuf:"bytes,11,opt,name=surveyTitle" json:"surveyTitle,omitempty"`
+	Questions                []*InThreadSurveyMetadata_InThreadSurveyQuestion             `protobuf:"bytes,12,rep,name=questions" json:"questions,omitempty"`
+	SurveyContinueButtonText *string                                                      `protobuf:"bytes,13,opt,name=surveyContinueButtonText" json:"surveyContinueButtonText,omitempty"`
+	SurveySubmitButtonText   *string                                                      `protobuf:"bytes,14,opt,name=surveySubmitButtonText" json:"surveySubmitButtonText,omitempty"`
+	PrivacyStatementFull     *string                                                      `protobuf:"bytes,15,opt,name=privacyStatementFull" json:"privacyStatementFull,omitempty"`
+	PrivacyStatementParts    []*InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart `protobuf:"bytes,16,rep,name=privacyStatementParts" json:"privacyStatementParts,omitempty"`
+	FeedbackToastText        *string                                                      `protobuf:"bytes,17,opt,name=feedbackToastText" json:"feedbackToastText,omitempty"`
+	StartQuestionIndex       *int32                                                       `protobuf:"varint,18,opt,name=startQuestionIndex" json:"startQuestionIndex,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *InThreadSurveyMetadata) Reset() {
+	*x = InThreadSurveyMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[35]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *InThreadSurveyMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InThreadSurveyMetadata) ProtoMessage() {}
+
+func (x *InThreadSurveyMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[35]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InThreadSurveyMetadata.ProtoReflect.Descriptor instead.
+func (*InThreadSurveyMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{35}
+}
+
+func (x *InThreadSurveyMetadata) GetTessaSessionID() string {
+	if x != nil && x.TessaSessionID != nil {
+		return *x.TessaSessionID
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetSimonSessionID() string {
+	if x != nil && x.SimonSessionID != nil {
+		return *x.SimonSessionID
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetSimonSurveyID() string {
+	if x != nil && x.SimonSurveyID != nil {
+		return *x.SimonSurveyID
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetTessaRootID() string {
+	if x != nil && x.TessaRootID != nil {
+		return *x.TessaRootID
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetRequestID() string {
+	if x != nil && x.RequestID != nil {
+		return *x.RequestID
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetTessaEvent() string {
+	if x != nil && x.TessaEvent != nil {
+		return *x.TessaEvent
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetInvitationHeaderText() string {
+	if x != nil && x.InvitationHeaderText != nil {
+		return *x.InvitationHeaderText
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetInvitationBodyText() string {
+	if x != nil && x.InvitationBodyText != nil {
+		return *x.InvitationBodyText
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetInvitationCtaText() string {
+	if x != nil && x.InvitationCtaText != nil {
+		return *x.InvitationCtaText
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetInvitationCtaURL() string {
+	if x != nil && x.InvitationCtaURL != nil {
+		return *x.InvitationCtaURL
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetSurveyTitle() string {
+	if x != nil && x.SurveyTitle != nil {
+		return *x.SurveyTitle
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetQuestions() []*InThreadSurveyMetadata_InThreadSurveyQuestion {
+	if x != nil {
+		return x.Questions
+	}
+	return nil
+}
+
+func (x *InThreadSurveyMetadata) GetSurveyContinueButtonText() string {
+	if x != nil && x.SurveyContinueButtonText != nil {
+		return *x.SurveyContinueButtonText
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetSurveySubmitButtonText() string {
+	if x != nil && x.SurveySubmitButtonText != nil {
+		return *x.SurveySubmitButtonText
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetPrivacyStatementFull() string {
+	if x != nil && x.PrivacyStatementFull != nil {
+		return *x.PrivacyStatementFull
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetPrivacyStatementParts() []*InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart {
+	if x != nil {
+		return x.PrivacyStatementParts
+	}
+	return nil
+}
+
+func (x *InThreadSurveyMetadata) GetFeedbackToastText() string {
+	if x != nil && x.FeedbackToastText != nil {
+		return *x.FeedbackToastText
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata) GetStartQuestionIndex() int32 {
+	if x != nil && x.StartQuestionIndex != nil {
+		return *x.StartQuestionIndex
+	}
+	return 0
+}
+
+type BotMessageOriginMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Origins       []*BotMessageOrigin    `protobuf:"bytes,1,rep,name=origins" json:"origins,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotMessageOriginMetadata) Reset() {
+	*x = BotMessageOriginMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[36]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMessageOriginMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMessageOriginMetadata) ProtoMessage() {}
+
+func (x *BotMessageOriginMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[36]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMessageOriginMetadata.ProtoReflect.Descriptor instead.
+func (*BotMessageOriginMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{36}
+}
+
+func (x *BotMessageOriginMetadata) GetOrigins() []*BotMessageOrigin {
+	if x != nil {
+		return x.Origins
+	}
+	return nil
+}
+
+type BotUnifiedResponseMutation struct {
+	state                    protoimpl.MessageState                             `protogen:"open.v1"`
+	SbsMetadata              *BotUnifiedResponseMutation_SideBySideMetadata     `protobuf:"bytes,1,opt,name=sbsMetadata" json:"sbsMetadata,omitempty"`
+	MediaDetailsMetadataList []*BotUnifiedResponseMutation_MediaDetailsMetadata `protobuf:"bytes,2,rep,name=mediaDetailsMetadataList" json:"mediaDetailsMetadataList,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *BotUnifiedResponseMutation) Reset() {
+	*x = BotUnifiedResponseMutation{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[37]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotUnifiedResponseMutation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotUnifiedResponseMutation) ProtoMessage() {}
+
+func (x *BotUnifiedResponseMutation) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[37]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotUnifiedResponseMutation.ProtoReflect.Descriptor instead.
+func (*BotUnifiedResponseMutation) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{37}
+}
+
+func (x *BotUnifiedResponseMutation) GetSbsMetadata() *BotUnifiedResponseMutation_SideBySideMetadata {
+	if x != nil {
+		return x.SbsMetadata
+	}
+	return nil
+}
+
+func (x *BotUnifiedResponseMutation) GetMediaDetailsMetadataList() []*BotUnifiedResponseMutation_MediaDetailsMetadata {
+	if x != nil {
+		return x.MediaDetailsMetadataList
+	}
+	return nil
+}
+
+type BotMetadata struct {
+	state                       protoimpl.MessageState            `protogen:"open.v1"`
+	AvatarMetadata              *BotAvatarMetadata                `protobuf:"bytes,1,opt,name=avatarMetadata" json:"avatarMetadata,omitempty"`
+	PersonaID                   *string                           `protobuf:"bytes,2,opt,name=personaID" json:"personaID,omitempty"`
+	PluginMetadata              *BotPluginMetadata                `protobuf:"bytes,3,opt,name=pluginMetadata" json:"pluginMetadata,omitempty"`
+	SuggestedPromptMetadata     *BotSuggestedPromptMetadata       `protobuf:"bytes,4,opt,name=suggestedPromptMetadata" json:"suggestedPromptMetadata,omitempty"`
+	InvokerJID                  *string                           `protobuf:"bytes,5,opt,name=invokerJID" json:"invokerJID,omitempty"`
+	SessionMetadata             *BotSessionMetadata               `protobuf:"bytes,6,opt,name=sessionMetadata" json:"sessionMetadata,omitempty"`
+	MemuMetadata                *BotMemuMetadata                  `protobuf:"bytes,7,opt,name=memuMetadata" json:"memuMetadata,omitempty"`
+	Timezone                    *string                           `protobuf:"bytes,8,opt,name=timezone" json:"timezone,omitempty"`
+	ReminderMetadata            *BotReminderMetadata              `protobuf:"bytes,9,opt,name=reminderMetadata" json:"reminderMetadata,omitempty"`
+	ModelMetadata               *BotModelMetadata                 `protobuf:"bytes,10,opt,name=modelMetadata" json:"modelMetadata,omitempty"`
+	MessageDisclaimerText       *string                           `protobuf:"bytes,11,opt,name=messageDisclaimerText" json:"messageDisclaimerText,omitempty"`
+	ProgressIndicatorMetadata   *BotProgressIndicatorMetadata     `protobuf:"bytes,12,opt,name=progressIndicatorMetadata" json:"progressIndicatorMetadata,omitempty"`
+	CapabilityMetadata          *BotCapabilityMetadata            `protobuf:"bytes,13,opt,name=capabilityMetadata" json:"capabilityMetadata,omitempty"`
+	ImagineMetadata             *BotImagineMetadata               `protobuf:"bytes,14,opt,name=imagineMetadata" json:"imagineMetadata,omitempty"`
+	MemoryMetadata              *BotMemoryMetadata                `protobuf:"bytes,15,opt,name=memoryMetadata" json:"memoryMetadata,omitempty"`
+	RenderingMetadata           *BotRenderingMetadata             `protobuf:"bytes,16,opt,name=renderingMetadata" json:"renderingMetadata,omitempty"`
+	BotMetricsMetadata          *BotMetricsMetadata               `protobuf:"bytes,17,opt,name=botMetricsMetadata" json:"botMetricsMetadata,omitempty"`
+	BotLinkedAccountsMetadata   *BotLinkedAccountsMetadata        `protobuf:"bytes,18,opt,name=botLinkedAccountsMetadata" json:"botLinkedAccountsMetadata,omitempty"`
+	RichResponseSourcesMetadata *BotSourcesMetadata               `protobuf:"bytes,19,opt,name=richResponseSourcesMetadata" json:"richResponseSourcesMetadata,omitempty"`
+	AiConversationContext       []byte                            `protobuf:"bytes,20,opt,name=aiConversationContext" json:"aiConversationContext,omitempty"`
+	BotPromotionMessageMetadata *BotPromotionMessageMetadata      `protobuf:"bytes,21,opt,name=botPromotionMessageMetadata" json:"botPromotionMessageMetadata,omitempty"`
+	BotModeSelectionMetadata    *BotModeSelectionMetadata         `protobuf:"bytes,22,opt,name=botModeSelectionMetadata" json:"botModeSelectionMetadata,omitempty"`
+	BotQuotaMetadata            *BotQuotaMetadata                 `protobuf:"bytes,23,opt,name=botQuotaMetadata" json:"botQuotaMetadata,omitempty"`
+	BotAgeCollectionMetadata    *BotAgeCollectionMetadata         `protobuf:"bytes,24,opt,name=botAgeCollectionMetadata" json:"botAgeCollectionMetadata,omitempty"`
+	ConversationStarterPromptID *string                           `protobuf:"bytes,25,opt,name=conversationStarterPromptID" json:"conversationStarterPromptID,omitempty"`
+	BotResponseID               *string                           `protobuf:"bytes,26,opt,name=botResponseID" json:"botResponseID,omitempty"`
+	VerificationMetadata        *BotSignatureVerificationMetadata `protobuf:"bytes,27,opt,name=verificationMetadata" json:"verificationMetadata,omitempty"`
+	UnifiedResponseMutation     *BotUnifiedResponseMutation       `protobuf:"bytes,28,opt,name=unifiedResponseMutation" json:"unifiedResponseMutation,omitempty"`
+	BotMessageOriginMetadata    *BotMessageOriginMetadata         `protobuf:"bytes,29,opt,name=botMessageOriginMetadata" json:"botMessageOriginMetadata,omitempty"`
+	InThreadSurveyMetadata      *InThreadSurveyMetadata           `protobuf:"bytes,30,opt,name=inThreadSurveyMetadata" json:"inThreadSurveyMetadata,omitempty"`
+	BotThreadInfo               *AIThreadInfo                     `protobuf:"bytes,31,opt,name=botThreadInfo" json:"botThreadInfo,omitempty"`
+	RegenerateMetadata          *AIRegenerateMetadata             `protobuf:"bytes,32,opt,name=regenerateMetadata" json:"regenerateMetadata,omitempty"`
+	SessionTransparencyMetadata *SessionTransparencyMetadata      `protobuf:"bytes,33,opt,name=sessionTransparencyMetadata" json:"sessionTransparencyMetadata,omitempty"`
+	BotDocumentMessageMetadata  *BotDocumentMessageMetadata       `protobuf:"bytes,34,opt,name=botDocumentMessageMetadata" json:"botDocumentMessageMetadata,omitempty"`
+	InternalMetadata            []byte                            `protobuf:"bytes,999,opt,name=internalMetadata" json:"internalMetadata,omitempty"`
+	unknownFields               protoimpl.UnknownFields
+	sizeCache                   protoimpl.SizeCache
+}
+
+func (x *BotMetadata) Reset() {
+	*x = BotMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[38]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMetadata) ProtoMessage() {}
+
+func (x *BotMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[38]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMetadata.ProtoReflect.Descriptor instead.
+func (*BotMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{38}
+}
+
+func (x *BotMetadata) GetAvatarMetadata() *BotAvatarMetadata {
+	if x != nil {
+		return x.AvatarMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetPersonaID() string {
+	if x != nil && x.PersonaID != nil {
+		return *x.PersonaID
+	}
+	return ""
+}
+
+func (x *BotMetadata) GetPluginMetadata() *BotPluginMetadata {
+	if x != nil {
+		return x.PluginMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetSuggestedPromptMetadata() *BotSuggestedPromptMetadata {
+	if x != nil {
+		return x.SuggestedPromptMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetInvokerJID() string {
+	if x != nil && x.InvokerJID != nil {
+		return *x.InvokerJID
+	}
+	return ""
+}
+
+func (x *BotMetadata) GetSessionMetadata() *BotSessionMetadata {
+	if x != nil {
+		return x.SessionMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetMemuMetadata() *BotMemuMetadata {
+	if x != nil {
+		return x.MemuMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetTimezone() string {
+	if x != nil && x.Timezone != nil {
+		return *x.Timezone
+	}
+	return ""
+}
+
+func (x *BotMetadata) GetReminderMetadata() *BotReminderMetadata {
+	if x != nil {
+		return x.ReminderMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetModelMetadata() *BotModelMetadata {
+	if x != nil {
+		return x.ModelMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetMessageDisclaimerText() string {
+	if x != nil && x.MessageDisclaimerText != nil {
+		return *x.MessageDisclaimerText
+	}
+	return ""
+}
+
+func (x *BotMetadata) GetProgressIndicatorMetadata() *BotProgressIndicatorMetadata {
+	if x != nil {
+		return x.ProgressIndicatorMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetCapabilityMetadata() *BotCapabilityMetadata {
+	if x != nil {
+		return x.CapabilityMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetImagineMetadata() *BotImagineMetadata {
+	if x != nil {
+		return x.ImagineMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetMemoryMetadata() *BotMemoryMetadata {
+	if x != nil {
+		return x.MemoryMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetRenderingMetadata() *BotRenderingMetadata {
+	if x != nil {
+		return x.RenderingMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotMetricsMetadata() *BotMetricsMetadata {
+	if x != nil {
+		return x.BotMetricsMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotLinkedAccountsMetadata() *BotLinkedAccountsMetadata {
+	if x != nil {
+		return x.BotLinkedAccountsMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetRichResponseSourcesMetadata() *BotSourcesMetadata {
+	if x != nil {
+		return x.RichResponseSourcesMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetAiConversationContext() []byte {
+	if x != nil {
+		return x.AiConversationContext
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotPromotionMessageMetadata() *BotPromotionMessageMetadata {
+	if x != nil {
+		return x.BotPromotionMessageMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotModeSelectionMetadata() *BotModeSelectionMetadata {
+	if x != nil {
+		return x.BotModeSelectionMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotQuotaMetadata() *BotQuotaMetadata {
+	if x != nil {
+		return x.BotQuotaMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotAgeCollectionMetadata() *BotAgeCollectionMetadata {
+	if x != nil {
+		return x.BotAgeCollectionMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetConversationStarterPromptID() string {
+	if x != nil && x.ConversationStarterPromptID != nil {
+		return *x.ConversationStarterPromptID
+	}
+	return ""
+}
+
+func (x *BotMetadata) GetBotResponseID() string {
+	if x != nil && x.BotResponseID != nil {
+		return *x.BotResponseID
+	}
+	return ""
+}
+
+func (x *BotMetadata) GetVerificationMetadata() *BotSignatureVerificationMetadata {
+	if x != nil {
+		return x.VerificationMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetUnifiedResponseMutation() *BotUnifiedResponseMutation {
+	if x != nil {
+		return x.UnifiedResponseMutation
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotMessageOriginMetadata() *BotMessageOriginMetadata {
+	if x != nil {
+		return x.BotMessageOriginMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetInThreadSurveyMetadata() *InThreadSurveyMetadata {
+	if x != nil {
+		return x.InThreadSurveyMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotThreadInfo() *AIThreadInfo {
+	if x != nil {
+		return x.BotThreadInfo
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetRegenerateMetadata() *AIRegenerateMetadata {
+	if x != nil {
+		return x.RegenerateMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetSessionTransparencyMetadata() *SessionTransparencyMetadata {
+	if x != nil {
+		return x.SessionTransparencyMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetBotDocumentMessageMetadata() *BotDocumentMessageMetadata {
+	if x != nil {
+		return x.BotDocumentMessageMetadata
+	}
+	return nil
+}
+
+func (x *BotMetadata) GetInternalMetadata() []byte {
+	if x != nil {
+		return x.InternalMetadata
+	}
+	return nil
+}
+
+type ForwardedAIBotMessageInfo struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	BotName       *string                `protobuf:"bytes,1,opt,name=botName" json:"botName,omitempty"`
+	BotJID        *string                `protobuf:"bytes,2,opt,name=botJID" json:"botJID,omitempty"`
+	CreatorName   *string                `protobuf:"bytes,3,opt,name=creatorName" json:"creatorName,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ForwardedAIBotMessageInfo) Reset() {
+	*x = ForwardedAIBotMessageInfo{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[39]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ForwardedAIBotMessageInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ForwardedAIBotMessageInfo) ProtoMessage() {}
+
+func (x *ForwardedAIBotMessageInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[39]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ForwardedAIBotMessageInfo.ProtoReflect.Descriptor instead.
+func (*ForwardedAIBotMessageInfo) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{39}
+}
+
+func (x *ForwardedAIBotMessageInfo) GetBotName() string {
+	if x != nil && x.BotName != nil {
+		return *x.BotName
+	}
+	return ""
+}
+
+func (x *ForwardedAIBotMessageInfo) GetBotJID() string {
+	if x != nil && x.BotJID != nil {
+		return *x.BotJID
+	}
+	return ""
+}
+
+func (x *ForwardedAIBotMessageInfo) GetCreatorName() string {
+	if x != nil && x.CreatorName != nil {
+		return *x.CreatorName
+	}
+	return ""
+}
+
+type BotMessageSharingInfo struct {
+	state               protoimpl.MessageState `protogen:"open.v1"`
+	BotEntryPointOrigin *BotMetricsEntryPoint  `protobuf:"varint,1,opt,name=botEntryPointOrigin,enum=WAAICommon.BotMetricsEntryPoint" json:"botEntryPointOrigin,omitempty"`
+	ForwardScore        *uint32                `protobuf:"varint,2,opt,name=forwardScore" json:"forwardScore,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *BotMessageSharingInfo) Reset() {
+	*x = BotMessageSharingInfo{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[40]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotMessageSharingInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotMessageSharingInfo) ProtoMessage() {}
+
+func (x *BotMessageSharingInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[40]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotMessageSharingInfo.ProtoReflect.Descriptor instead.
+func (*BotMessageSharingInfo) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{40}
+}
+
+func (x *BotMessageSharingInfo) GetBotEntryPointOrigin() BotMetricsEntryPoint {
+	if x != nil && x.BotEntryPointOrigin != nil {
+		return *x.BotEntryPointOrigin
+	}
+	return BotMetricsEntryPoint_UNDEFINED_ENTRY_POINT
+}
+
+func (x *BotMessageSharingInfo) GetForwardScore() uint32 {
+	if x != nil && x.ForwardScore != nil {
+		return *x.ForwardScore
+	}
+	return 0
+}
+
+type AIRichResponseImageURL struct {
+	state           protoimpl.MessageState `protogen:"open.v1"`
+	ImagePreviewURL *string                `protobuf:"bytes,1,opt,name=imagePreviewURL" json:"imagePreviewURL,omitempty"`
+	ImageHighResURL *string                `protobuf:"bytes,2,opt,name=imageHighResURL" json:"imageHighResURL,omitempty"`
+	SourceURL       *string                `protobuf:"bytes,3,opt,name=sourceURL" json:"sourceURL,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *AIRichResponseImageURL) Reset() {
+	*x = AIRichResponseImageURL{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[41]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseImageURL) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseImageURL) ProtoMessage() {}
+
+func (x *AIRichResponseImageURL) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[41]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseImageURL.ProtoReflect.Descriptor instead.
+func (*AIRichResponseImageURL) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{41}
+}
+
+func (x *AIRichResponseImageURL) GetImagePreviewURL() string {
+	if x != nil && x.ImagePreviewURL != nil {
+		return *x.ImagePreviewURL
+	}
+	return ""
+}
+
+func (x *AIRichResponseImageURL) GetImageHighResURL() string {
+	if x != nil && x.ImageHighResURL != nil {
+		return *x.ImageHighResURL
+	}
+	return ""
+}
+
+func (x *AIRichResponseImageURL) GetSourceURL() string {
+	if x != nil && x.SourceURL != nil {
+		return *x.SourceURL
+	}
+	return ""
+}
+
+type AIRichResponseGridImageMetadata struct {
+	state         protoimpl.MessageState    `protogen:"open.v1"`
+	GridImageURL  *AIRichResponseImageURL   `protobuf:"bytes,1,opt,name=gridImageURL" json:"gridImageURL,omitempty"`
+	ImageURLs     []*AIRichResponseImageURL `protobuf:"bytes,2,rep,name=imageURLs" json:"imageURLs,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseGridImageMetadata) Reset() {
+	*x = AIRichResponseGridImageMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[42]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseGridImageMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseGridImageMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseGridImageMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[42]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseGridImageMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseGridImageMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{42}
+}
+
+func (x *AIRichResponseGridImageMetadata) GetGridImageURL() *AIRichResponseImageURL {
+	if x != nil {
+		return x.GridImageURL
+	}
+	return nil
+}
+
+func (x *AIRichResponseGridImageMetadata) GetImageURLs() []*AIRichResponseImageURL {
+	if x != nil {
+		return x.ImageURLs
+	}
+	return nil
+}
+
+type AIRichResponseTableMetadata struct {
+	state         protoimpl.MessageState                                `protogen:"open.v1"`
+	Rows          []*AIRichResponseTableMetadata_AIRichResponseTableRow `protobuf:"bytes,1,rep,name=rows" json:"rows,omitempty"`
+	Title         *string                                               `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseTableMetadata) Reset() {
+	*x = AIRichResponseTableMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[43]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseTableMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseTableMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseTableMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[43]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseTableMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseTableMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{43}
+}
+
+func (x *AIRichResponseTableMetadata) GetRows() []*AIRichResponseTableMetadata_AIRichResponseTableRow {
+	if x != nil {
+		return x.Rows
+	}
+	return nil
+}
+
+func (x *AIRichResponseTableMetadata) GetTitle() string {
+	if x != nil && x.Title != nil {
+		return *x.Title
+	}
+	return ""
+}
+
+type AIRichResponseUnifiedResponse struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Data          []byte                 `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseUnifiedResponse) Reset() {
+	*x = AIRichResponseUnifiedResponse{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[44]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseUnifiedResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseUnifiedResponse) ProtoMessage() {}
+
+func (x *AIRichResponseUnifiedResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[44]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseUnifiedResponse.ProtoReflect.Descriptor instead.
+func (*AIRichResponseUnifiedResponse) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{44}
+}
+
+func (x *AIRichResponseUnifiedResponse) GetData() []byte {
+	if x != nil {
+		return x.Data
+	}
+	return nil
+}
+
+type AIRichResponseLatexMetadata struct {
+	state         protoimpl.MessageState                                       `protogen:"open.v1"`
+	Text          *string                                                      `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"`
+	Expressions   []*AIRichResponseLatexMetadata_AIRichResponseLatexExpression `protobuf:"bytes,2,rep,name=expressions" json:"expressions,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseLatexMetadata) Reset() {
+	*x = AIRichResponseLatexMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[45]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseLatexMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseLatexMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseLatexMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[45]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseLatexMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseLatexMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{45}
+}
+
+func (x *AIRichResponseLatexMetadata) GetText() string {
+	if x != nil && x.Text != nil {
+		return *x.Text
+	}
+	return ""
+}
+
+func (x *AIRichResponseLatexMetadata) GetExpressions() []*AIRichResponseLatexMetadata_AIRichResponseLatexExpression {
+	if x != nil {
+		return x.Expressions
+	}
+	return nil
+}
+
+type AIRichResponseMapMetadata struct {
+	state           protoimpl.MessageState                                   `protogen:"open.v1"`
+	CenterLatitude  *float64                                                 `protobuf:"fixed64,1,opt,name=centerLatitude" json:"centerLatitude,omitempty"`
+	CenterLongitude *float64                                                 `protobuf:"fixed64,2,opt,name=centerLongitude" json:"centerLongitude,omitempty"`
+	LatitudeDelta   *float64                                                 `protobuf:"fixed64,3,opt,name=latitudeDelta" json:"latitudeDelta,omitempty"`
+	LongitudeDelta  *float64                                                 `protobuf:"fixed64,4,opt,name=longitudeDelta" json:"longitudeDelta,omitempty"`
+	Annotations     []*AIRichResponseMapMetadata_AIRichResponseMapAnnotation `protobuf:"bytes,5,rep,name=annotations" json:"annotations,omitempty"`
+	ShowInfoList    *bool                                                    `protobuf:"varint,6,opt,name=showInfoList" json:"showInfoList,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *AIRichResponseMapMetadata) Reset() {
+	*x = AIRichResponseMapMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[46]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseMapMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseMapMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseMapMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[46]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseMapMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseMapMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{46}
+}
+
+func (x *AIRichResponseMapMetadata) GetCenterLatitude() float64 {
+	if x != nil && x.CenterLatitude != nil {
+		return *x.CenterLatitude
+	}
+	return 0
+}
+
+func (x *AIRichResponseMapMetadata) GetCenterLongitude() float64 {
+	if x != nil && x.CenterLongitude != nil {
+		return *x.CenterLongitude
+	}
+	return 0
+}
+
+func (x *AIRichResponseMapMetadata) GetLatitudeDelta() float64 {
+	if x != nil && x.LatitudeDelta != nil {
+		return *x.LatitudeDelta
+	}
+	return 0
+}
+
+func (x *AIRichResponseMapMetadata) GetLongitudeDelta() float64 {
+	if x != nil && x.LongitudeDelta != nil {
+		return *x.LongitudeDelta
+	}
+	return 0
+}
+
+func (x *AIRichResponseMapMetadata) GetAnnotations() []*AIRichResponseMapMetadata_AIRichResponseMapAnnotation {
+	if x != nil {
+		return x.Annotations
+	}
+	return nil
+}
+
+func (x *AIRichResponseMapMetadata) GetShowInfoList() bool {
+	if x != nil && x.ShowInfoList != nil {
+		return *x.ShowInfoList
+	}
+	return false
+}
+
+type AIRichResponseSubMessage struct {
+	state                protoimpl.MessageState              `protogen:"open.v1"`
+	MessageType          *AIRichResponseSubMessageType       `protobuf:"varint,1,opt,name=messageType,enum=WAAICommon.AIRichResponseSubMessageType" json:"messageType,omitempty"`
+	GridImageMetadata    *AIRichResponseGridImageMetadata    `protobuf:"bytes,2,opt,name=gridImageMetadata" json:"gridImageMetadata,omitempty"`
+	MessageText          *string                             `protobuf:"bytes,3,opt,name=messageText" json:"messageText,omitempty"`
+	ImageMetadata        *AIRichResponseInlineImageMetadata  `protobuf:"bytes,4,opt,name=imageMetadata" json:"imageMetadata,omitempty"`
+	CodeMetadata         *AIRichResponseCodeMetadata         `protobuf:"bytes,5,opt,name=codeMetadata" json:"codeMetadata,omitempty"`
+	TableMetadata        *AIRichResponseTableMetadata        `protobuf:"bytes,6,opt,name=tableMetadata" json:"tableMetadata,omitempty"`
+	DynamicMetadata      *AIRichResponseDynamicMetadata      `protobuf:"bytes,7,opt,name=dynamicMetadata" json:"dynamicMetadata,omitempty"`
+	LatexMetadata        *AIRichResponseLatexMetadata        `protobuf:"bytes,8,opt,name=latexMetadata" json:"latexMetadata,omitempty"`
+	MapMetadata          *AIRichResponseMapMetadata          `protobuf:"bytes,9,opt,name=mapMetadata" json:"mapMetadata,omitempty"`
+	ContentItemsMetadata *AIRichResponseContentItemsMetadata `protobuf:"bytes,10,opt,name=contentItemsMetadata" json:"contentItemsMetadata,omitempty"`
+	unknownFields        protoimpl.UnknownFields
+	sizeCache            protoimpl.SizeCache
+}
+
+func (x *AIRichResponseSubMessage) Reset() {
+	*x = AIRichResponseSubMessage{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[47]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseSubMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseSubMessage) ProtoMessage() {}
+
+func (x *AIRichResponseSubMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[47]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseSubMessage.ProtoReflect.Descriptor instead.
+func (*AIRichResponseSubMessage) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{47}
+}
+
+func (x *AIRichResponseSubMessage) GetMessageType() AIRichResponseSubMessageType {
+	if x != nil && x.MessageType != nil {
+		return *x.MessageType
+	}
+	return AIRichResponseSubMessageType_AI_RICH_RESPONSE_UNKNOWN
+}
+
+func (x *AIRichResponseSubMessage) GetGridImageMetadata() *AIRichResponseGridImageMetadata {
+	if x != nil {
+		return x.GridImageMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseSubMessage) GetMessageText() string {
+	if x != nil && x.MessageText != nil {
+		return *x.MessageText
+	}
+	return ""
+}
+
+func (x *AIRichResponseSubMessage) GetImageMetadata() *AIRichResponseInlineImageMetadata {
+	if x != nil {
+		return x.ImageMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseSubMessage) GetCodeMetadata() *AIRichResponseCodeMetadata {
+	if x != nil {
+		return x.CodeMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseSubMessage) GetTableMetadata() *AIRichResponseTableMetadata {
+	if x != nil {
+		return x.TableMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseSubMessage) GetDynamicMetadata() *AIRichResponseDynamicMetadata {
+	if x != nil {
+		return x.DynamicMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseSubMessage) GetLatexMetadata() *AIRichResponseLatexMetadata {
+	if x != nil {
+		return x.LatexMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseSubMessage) GetMapMetadata() *AIRichResponseMapMetadata {
+	if x != nil {
+		return x.MapMetadata
+	}
+	return nil
+}
+
+func (x *AIRichResponseSubMessage) GetContentItemsMetadata() *AIRichResponseContentItemsMetadata {
+	if x != nil {
+		return x.ContentItemsMetadata
+	}
+	return nil
+}
+
+type AIRegenerateMetadata struct {
+	state               protoimpl.MessageState `protogen:"open.v1"`
+	MessageKey          *waCommon.MessageKey   `protobuf:"bytes,1,opt,name=messageKey" json:"messageKey,omitempty"`
+	ResponseTimestampMS *int64                 `protobuf:"varint,2,opt,name=responseTimestampMS" json:"responseTimestampMS,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *AIRegenerateMetadata) Reset() {
+	*x = AIRegenerateMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[48]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRegenerateMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRegenerateMetadata) ProtoMessage() {}
+
+func (x *AIRegenerateMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[48]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRegenerateMetadata.ProtoReflect.Descriptor instead.
+func (*AIRegenerateMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{48}
+}
+
+func (x *AIRegenerateMetadata) GetMessageKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.MessageKey
+	}
+	return nil
+}
+
+func (x *AIRegenerateMetadata) GetResponseTimestampMS() int64 {
+	if x != nil && x.ResponseTimestampMS != nil {
+		return *x.ResponseTimestampMS
+	}
+	return 0
+}
+
+type SessionTransparencyMetadata struct {
+	state                   protoimpl.MessageState   `protogen:"open.v1"`
+	DisclaimerText          *string                  `protobuf:"bytes,1,opt,name=disclaimerText" json:"disclaimerText,omitempty"`
+	HcaID                   *string                  `protobuf:"bytes,2,opt,name=hcaID" json:"hcaID,omitempty"`
+	SessionTransparencyType *SessionTransparencyType `protobuf:"varint,3,opt,name=sessionTransparencyType,enum=WAAICommon.SessionTransparencyType" json:"sessionTransparencyType,omitempty"`
+	unknownFields           protoimpl.UnknownFields
+	sizeCache               protoimpl.SizeCache
+}
+
+func (x *SessionTransparencyMetadata) Reset() {
+	*x = SessionTransparencyMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[49]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SessionTransparencyMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SessionTransparencyMetadata) ProtoMessage() {}
+
+func (x *SessionTransparencyMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[49]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SessionTransparencyMetadata.ProtoReflect.Descriptor instead.
+func (*SessionTransparencyMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{49}
+}
+
+func (x *SessionTransparencyMetadata) GetDisclaimerText() string {
+	if x != nil && x.DisclaimerText != nil {
+		return *x.DisclaimerText
+	}
+	return ""
+}
+
+func (x *SessionTransparencyMetadata) GetHcaID() string {
+	if x != nil && x.HcaID != nil {
+		return *x.HcaID
+	}
+	return ""
+}
+
+func (x *SessionTransparencyMetadata) GetSessionTransparencyType() SessionTransparencyType {
+	if x != nil && x.SessionTransparencyType != nil {
+		return *x.SessionTransparencyType
+	}
+	return SessionTransparencyType_UNKNOWN_TYPE
+}
+
+type BotProgressIndicatorMetadata_BotPlanningStepMetadata struct {
+	state            protoimpl.MessageState                                                                   `protogen:"open.v1"`
+	StatusTitle      *string                                                                                  `protobuf:"bytes,1,opt,name=statusTitle" json:"statusTitle,omitempty"`
+	StatusBody       *string                                                                                  `protobuf:"bytes,2,opt,name=statusBody" json:"statusBody,omitempty"`
+	SourcesMetadata  []*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata `protobuf:"bytes,3,rep,name=sourcesMetadata" json:"sourcesMetadata,omitempty"`
+	Status           *BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus                 `protobuf:"varint,4,opt,name=status,enum=WAAICommon.BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus" json:"status,omitempty"`
+	IsReasoning      *bool                                                                                    `protobuf:"varint,5,opt,name=isReasoning" json:"isReasoning,omitempty"`
+	IsEnhancedSearch *bool                                                                                    `protobuf:"varint,6,opt,name=isEnhancedSearch" json:"isEnhancedSearch,omitempty"`
+	Sections         []*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata   `protobuf:"bytes,7,rep,name=sections" json:"sections,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) Reset() {
+	*x = BotProgressIndicatorMetadata_BotPlanningStepMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[50]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata) ProtoMessage() {}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[50]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata_BotPlanningStepMetadata.ProtoReflect.Descriptor instead.
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7, 0}
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) GetStatusTitle() string {
+	if x != nil && x.StatusTitle != nil {
+		return *x.StatusTitle
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) GetStatusBody() string {
+	if x != nil && x.StatusBody != nil {
+		return *x.StatusBody
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) GetSourcesMetadata() []*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata {
+	if x != nil {
+		return x.SourcesMetadata
+	}
+	return nil
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) GetStatus() BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus {
+	if x != nil && x.Status != nil {
+		return *x.Status
+	}
+	return BotProgressIndicatorMetadata_BotPlanningStepMetadata_UNKNOWN
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) GetIsReasoning() bool {
+	if x != nil && x.IsReasoning != nil {
+		return *x.IsReasoning
+	}
+	return false
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) GetIsEnhancedSearch() bool {
+	if x != nil && x.IsEnhancedSearch != nil {
+		return *x.IsEnhancedSearch
+	}
+	return false
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata) GetSections() []*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata {
+	if x != nil {
+		return x.Sections
+	}
+	return nil
+}
+
+type BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata struct {
+	state         protoimpl.MessageState                                                                                                 `protogen:"open.v1"`
+	SourceTitle   *string                                                                                                                `protobuf:"bytes,1,opt,name=sourceTitle" json:"sourceTitle,omitempty"`
+	Provider      *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider `protobuf:"varint,2,opt,name=provider,enum=WAAICommon.BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider" json:"provider,omitempty"`
+	SourceURL     *string                                                                                                                `protobuf:"bytes,3,opt,name=sourceURL" json:"sourceURL,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) Reset() {
+	*x = BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[51]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) ProtoMessage() {
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[51]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata.ProtoReflect.Descriptor instead.
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7, 0, 0}
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) GetSourceTitle() string {
+	if x != nil && x.SourceTitle != nil {
+		return *x.SourceTitle
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) GetProvider() BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider {
+	if x != nil && x.Provider != nil {
+		return *x.Provider
+	}
+	return BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_UNKNOWN
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata) GetSourceURL() string {
+	if x != nil && x.SourceURL != nil {
+		return *x.SourceURL
+	}
+	return ""
+}
+
+type BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata struct {
+	state           protoimpl.MessageState                                                                  `protogen:"open.v1"`
+	SectionTitle    *string                                                                                 `protobuf:"bytes,1,opt,name=sectionTitle" json:"sectionTitle,omitempty"`
+	SectionBody     *string                                                                                 `protobuf:"bytes,2,opt,name=sectionBody" json:"sectionBody,omitempty"`
+	SourcesMetadata []*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata `protobuf:"bytes,3,rep,name=sourcesMetadata" json:"sourcesMetadata,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) Reset() {
+	*x = BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[52]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) ProtoMessage() {
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[52]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata.ProtoReflect.Descriptor instead.
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7, 0, 1}
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) GetSectionTitle() string {
+	if x != nil && x.SectionTitle != nil {
+		return *x.SectionTitle
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) GetSectionBody() string {
+	if x != nil && x.SectionBody != nil {
+		return *x.SectionBody
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata) GetSourcesMetadata() []*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata {
+	if x != nil {
+		return x.SourcesMetadata
+	}
+	return nil
+}
+
+type BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata struct {
+	state         protoimpl.MessageState                                                        `protogen:"open.v1"`
+	Title         *string                                                                       `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"`
+	Provider      *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider `protobuf:"varint,2,opt,name=provider,enum=WAAICommon.BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider" json:"provider,omitempty"`
+	SourceURL     *string                                                                       `protobuf:"bytes,3,opt,name=sourceURL" json:"sourceURL,omitempty"`
+	FavIconURL    *string                                                                       `protobuf:"bytes,4,opt,name=favIconURL" json:"favIconURL,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) Reset() {
+	*x = BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[53]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) ProtoMessage() {
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[53]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata.ProtoReflect.Descriptor instead.
+func (*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{7, 0, 2}
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) GetTitle() string {
+	if x != nil && x.Title != nil {
+		return *x.Title
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) GetProvider() BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider {
+	if x != nil && x.Provider != nil {
+		return *x.Provider
+	}
+	return BotProgressIndicatorMetadata_BotPlanningStepMetadata_UNKNOWN_PROVIDER
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) GetSourceURL() string {
+	if x != nil && x.SourceURL != nil {
+		return *x.SourceURL
+	}
+	return ""
+}
+
+func (x *BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata) GetFavIconURL() string {
+	if x != nil && x.FavIconURL != nil {
+		return *x.FavIconURL
+	}
+	return ""
+}
+
+type BotQuotaMetadata_BotFeatureQuotaMetadata struct {
+	state               protoimpl.MessageState                                   `protogen:"open.v1"`
+	FeatureType         *BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType `protobuf:"varint,1,opt,name=featureType,enum=WAAICommon.BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType" json:"featureType,omitempty"`
+	RemainingQuota      *uint32                                                  `protobuf:"varint,2,opt,name=remainingQuota" json:"remainingQuota,omitempty"`
+	ExpirationTimestamp *uint64                                                  `protobuf:"varint,3,opt,name=expirationTimestamp" json:"expirationTimestamp,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *BotQuotaMetadata_BotFeatureQuotaMetadata) Reset() {
+	*x = BotQuotaMetadata_BotFeatureQuotaMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[54]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotQuotaMetadata_BotFeatureQuotaMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotQuotaMetadata_BotFeatureQuotaMetadata) ProtoMessage() {}
+
+func (x *BotQuotaMetadata_BotFeatureQuotaMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[54]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotQuotaMetadata_BotFeatureQuotaMetadata.ProtoReflect.Descriptor instead.
+func (*BotQuotaMetadata_BotFeatureQuotaMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{10, 0}
+}
+
+func (x *BotQuotaMetadata_BotFeatureQuotaMetadata) GetFeatureType() BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType {
+	if x != nil && x.FeatureType != nil {
+		return *x.FeatureType
+	}
+	return BotQuotaMetadata_BotFeatureQuotaMetadata_UNKNOWN_FEATURE
+}
+
+func (x *BotQuotaMetadata_BotFeatureQuotaMetadata) GetRemainingQuota() uint32 {
+	if x != nil && x.RemainingQuota != nil {
+		return *x.RemainingQuota
+	}
+	return 0
+}
+
+func (x *BotQuotaMetadata_BotFeatureQuotaMetadata) GetExpirationTimestamp() uint64 {
+	if x != nil && x.ExpirationTimestamp != nil {
+		return *x.ExpirationTimestamp
+	}
+	return 0
+}
+
+type BotSourcesMetadata_BotSourceItem struct {
+	state             protoimpl.MessageState                           `protogen:"open.v1"`
+	Provider          *BotSourcesMetadata_BotSourceItem_SourceProvider `protobuf:"varint,1,opt,name=provider,enum=WAAICommon.BotSourcesMetadata_BotSourceItem_SourceProvider" json:"provider,omitempty"`
+	ThumbnailCDNURL   *string                                          `protobuf:"bytes,2,opt,name=thumbnailCDNURL" json:"thumbnailCDNURL,omitempty"`
+	SourceProviderURL *string                                          `protobuf:"bytes,3,opt,name=sourceProviderURL" json:"sourceProviderURL,omitempty"`
+	SourceQuery       *string                                          `protobuf:"bytes,4,opt,name=sourceQuery" json:"sourceQuery,omitempty"`
+	FaviconCDNURL     *string                                          `protobuf:"bytes,5,opt,name=faviconCDNURL" json:"faviconCDNURL,omitempty"`
+	CitationNumber    *uint32                                          `protobuf:"varint,6,opt,name=citationNumber" json:"citationNumber,omitempty"`
+	SourceTitle       *string                                          `protobuf:"bytes,7,opt,name=sourceTitle" json:"sourceTitle,omitempty"`
+	unknownFields     protoimpl.UnknownFields
+	sizeCache         protoimpl.SizeCache
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) Reset() {
+	*x = BotSourcesMetadata_BotSourceItem{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[55]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotSourcesMetadata_BotSourceItem) ProtoMessage() {}
+
+func (x *BotSourcesMetadata_BotSourceItem) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[55]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotSourcesMetadata_BotSourceItem.ProtoReflect.Descriptor instead.
+func (*BotSourcesMetadata_BotSourceItem) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{13, 0}
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) GetProvider() BotSourcesMetadata_BotSourceItem_SourceProvider {
+	if x != nil && x.Provider != nil {
+		return *x.Provider
+	}
+	return BotSourcesMetadata_BotSourceItem_UNKNOWN
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) GetThumbnailCDNURL() string {
+	if x != nil && x.ThumbnailCDNURL != nil {
+		return *x.ThumbnailCDNURL
+	}
+	return ""
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) GetSourceProviderURL() string {
+	if x != nil && x.SourceProviderURL != nil {
+		return *x.SourceProviderURL
+	}
+	return ""
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) GetSourceQuery() string {
+	if x != nil && x.SourceQuery != nil {
+		return *x.SourceQuery
+	}
+	return ""
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) GetFaviconCDNURL() string {
+	if x != nil && x.FaviconCDNURL != nil {
+		return *x.FaviconCDNURL
+	}
+	return ""
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) GetCitationNumber() uint32 {
+	if x != nil && x.CitationNumber != nil {
+		return *x.CitationNumber
+	}
+	return 0
+}
+
+func (x *BotSourcesMetadata_BotSourceItem) GetSourceTitle() string {
+	if x != nil && x.SourceTitle != nil {
+		return *x.SourceTitle
+	}
+	return ""
+}
+
+type AIThreadInfo_AIThreadClientInfo struct {
+	state         protoimpl.MessageState                        `protogen:"open.v1"`
+	Type          *AIThreadInfo_AIThreadClientInfo_AIThreadType `protobuf:"varint,1,opt,name=type,enum=WAAICommon.AIThreadInfo_AIThreadClientInfo_AIThreadType" json:"type,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIThreadInfo_AIThreadClientInfo) Reset() {
+	*x = AIThreadInfo_AIThreadClientInfo{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[56]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIThreadInfo_AIThreadClientInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIThreadInfo_AIThreadClientInfo) ProtoMessage() {}
+
+func (x *AIThreadInfo_AIThreadClientInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[56]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIThreadInfo_AIThreadClientInfo.ProtoReflect.Descriptor instead.
+func (*AIThreadInfo_AIThreadClientInfo) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{15, 0}
+}
+
+func (x *AIThreadInfo_AIThreadClientInfo) GetType() AIThreadInfo_AIThreadClientInfo_AIThreadType {
+	if x != nil && x.Type != nil {
+		return *x.Type
+	}
+	return AIThreadInfo_AIThreadClientInfo_UNKNOWN
+}
+
+type AIThreadInfo_AIThreadServerInfo struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Title         *string                `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIThreadInfo_AIThreadServerInfo) Reset() {
+	*x = AIThreadInfo_AIThreadServerInfo{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[57]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIThreadInfo_AIThreadServerInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIThreadInfo_AIThreadServerInfo) ProtoMessage() {}
+
+func (x *AIThreadInfo_AIThreadServerInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[57]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIThreadInfo_AIThreadServerInfo.ProtoReflect.Descriptor instead.
+func (*AIThreadInfo_AIThreadServerInfo) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{15, 1}
+}
+
+func (x *AIThreadInfo_AIThreadServerInfo) GetTitle() string {
+	if x != nil && x.Title != nil {
+		return *x.Title
+	}
+	return ""
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata struct {
+	state                     protoimpl.MessageState                                                           `protogen:"open.v1"`
+	SelectedRequestID         *string                                                                          `protobuf:"bytes,1,opt,name=selectedRequestID" json:"selectedRequestID,omitempty"`
+	SurveyID                  *uint32                                                                          `protobuf:"varint,2,opt,name=surveyID" json:"surveyID,omitempty"`
+	SimonSessionFbid          *string                                                                          `protobuf:"bytes,3,opt,name=simonSessionFbid" json:"simonSessionFbid,omitempty"`
+	ResponseOtid              *string                                                                          `protobuf:"bytes,4,opt,name=responseOtid" json:"responseOtid,omitempty"`
+	ResponseTimestampMSString *string                                                                          `protobuf:"bytes,5,opt,name=responseTimestampMSString" json:"responseTimestampMSString,omitempty"`
+	IsSelectedResponsePrimary *bool                                                                            `protobuf:"varint,6,opt,name=isSelectedResponsePrimary" json:"isSelectedResponsePrimary,omitempty"`
+	MessageIDToEdit           *string                                                                          `protobuf:"bytes,7,opt,name=messageIDToEdit" json:"messageIDToEdit,omitempty"`
+	AnalyticsData             *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData       `protobuf:"bytes,8,opt,name=analyticsData" json:"analyticsData,omitempty"`
+	MetaAiAnalyticsData       *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData `protobuf:"bytes,9,opt,name=metaAiAnalyticsData" json:"metaAiAnalyticsData,omitempty"`
+	unknownFields             protoimpl.UnknownFields
+	sizeCache                 protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[58]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata) ProtoMessage() {}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[58]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0}
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetSelectedRequestID() string {
+	if x != nil && x.SelectedRequestID != nil {
+		return *x.SelectedRequestID
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetSurveyID() uint32 {
+	if x != nil && x.SurveyID != nil {
+		return *x.SurveyID
+	}
+	return 0
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetSimonSessionFbid() string {
+	if x != nil && x.SimonSessionFbid != nil {
+		return *x.SimonSessionFbid
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetResponseOtid() string {
+	if x != nil && x.ResponseOtid != nil {
+		return *x.ResponseOtid
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetResponseTimestampMSString() string {
+	if x != nil && x.ResponseTimestampMSString != nil {
+		return *x.ResponseTimestampMSString
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetIsSelectedResponsePrimary() bool {
+	if x != nil && x.IsSelectedResponsePrimary != nil {
+		return *x.IsSelectedResponsePrimary
+	}
+	return false
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetMessageIDToEdit() string {
+	if x != nil && x.MessageIDToEdit != nil {
+		return *x.MessageIDToEdit
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetAnalyticsData() *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData {
+	if x != nil {
+		return x.AnalyticsData
+	}
+	return nil
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata) GetMetaAiAnalyticsData() *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData {
+	if x != nil {
+		return x.MetaAiAnalyticsData
+	}
+	return nil
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData struct {
+	state               protoimpl.MessageState                                                                                                   `protogen:"open.v1"`
+	SurveyID            *uint32                                                                                                                  `protobuf:"varint,1,opt,name=surveyID" json:"surveyID,omitempty"`
+	PrimaryResponseID   *string                                                                                                                  `protobuf:"bytes,2,opt,name=primaryResponseID" json:"primaryResponseID,omitempty"`
+	TestArmName         *string                                                                                                                  `protobuf:"bytes,3,opt,name=testArmName" json:"testArmName,omitempty"`
+	TimestampMSString   *string                                                                                                                  `protobuf:"bytes,4,opt,name=timestampMSString" json:"timestampMSString,omitempty"`
+	CtaImpressionEvent  *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData  `protobuf:"bytes,5,opt,name=ctaImpressionEvent" json:"ctaImpressionEvent,omitempty"`
+	CtaClickEvent       *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData       `protobuf:"bytes,6,opt,name=ctaClickEvent" json:"ctaClickEvent,omitempty"`
+	CardImpressionEvent *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData `protobuf:"bytes,7,opt,name=cardImpressionEvent" json:"cardImpressionEvent,omitempty"`
+	ResponseEvent       *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData       `protobuf:"bytes,8,opt,name=responseEvent" json:"responseEvent,omitempty"`
+	AbandonEvent        *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData        `protobuf:"bytes,9,opt,name=abandonEvent" json:"abandonEvent,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[59]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) ProtoMessage() {
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[59]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0, 0}
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetSurveyID() uint32 {
+	if x != nil && x.SurveyID != nil {
+		return *x.SurveyID
+	}
+	return 0
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetPrimaryResponseID() string {
+	if x != nil && x.PrimaryResponseID != nil {
+		return *x.PrimaryResponseID
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetTestArmName() string {
+	if x != nil && x.TestArmName != nil {
+		return *x.TestArmName
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetTimestampMSString() string {
+	if x != nil && x.TimestampMSString != nil {
+		return *x.TimestampMSString
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetCtaImpressionEvent() *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData {
+	if x != nil {
+		return x.CtaImpressionEvent
+	}
+	return nil
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetCtaClickEvent() *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData {
+	if x != nil {
+		return x.CtaClickEvent
+	}
+	return nil
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetCardImpressionEvent() *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData {
+	if x != nil {
+		return x.CardImpressionEvent
+	}
+	return nil
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetResponseEvent() *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData {
+	if x != nil {
+		return x.ResponseEvent
+	}
+	return nil
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData) GetAbandonEvent() *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData {
+	if x != nil {
+		return x.AbandonEvent
+	}
+	return nil
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData struct {
+	state            protoimpl.MessageState `protogen:"open.v1"`
+	TessaEvent       *string                `protobuf:"bytes,1,opt,name=tessaEvent" json:"tessaEvent,omitempty"`
+	TessaSessionFbid *string                `protobuf:"bytes,2,opt,name=tessaSessionFbid" json:"tessaSessionFbid,omitempty"`
+	SimonSessionFbid *string                `protobuf:"bytes,3,opt,name=simonSessionFbid" json:"simonSessionFbid,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[60]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) ProtoMessage() {}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[60]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0, 1}
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) GetTessaEvent() string {
+	if x != nil && x.TessaEvent != nil {
+		return *x.TessaEvent
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) GetTessaSessionFbid() string {
+	if x != nil && x.TessaSessionFbid != nil {
+		return *x.TessaSessionFbid
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData) GetSimonSessionFbid() string {
+	if x != nil && x.SimonSessionFbid != nil {
+		return *x.SimonSessionFbid
+	}
+	return ""
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData struct {
+	state                    protoimpl.MessageState `protogen:"open.v1"`
+	AbandonDwellTimeMSString *string                `protobuf:"bytes,1,opt,name=abandonDwellTimeMSString" json:"abandonDwellTimeMSString,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[61]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData) ProtoMessage() {
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[61]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0, 0, 0}
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData) GetAbandonDwellTimeMSString() string {
+	if x != nil && x.AbandonDwellTimeMSString != nil {
+		return *x.AbandonDwellTimeMSString
+	}
+	return ""
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData struct {
+	state                     protoimpl.MessageState `protogen:"open.v1"`
+	ResponseDwellTimeMSString *string                `protobuf:"bytes,1,opt,name=responseDwellTimeMSString" json:"responseDwellTimeMSString,omitempty"`
+	SelectedResponseID        *string                `protobuf:"bytes,2,opt,name=selectedResponseID" json:"selectedResponseID,omitempty"`
+	unknownFields             protoimpl.UnknownFields
+	sizeCache                 protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[62]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData) ProtoMessage() {
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[62]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0, 0, 1}
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData) GetResponseDwellTimeMSString() string {
+	if x != nil && x.ResponseDwellTimeMSString != nil {
+		return *x.ResponseDwellTimeMSString
+	}
+	return ""
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData) GetSelectedResponseID() string {
+	if x != nil && x.SelectedResponseID != nil {
+		return *x.SelectedResponseID
+	}
+	return ""
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[63]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData) ProtoMessage() {
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[63]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0, 0, 2}
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData struct {
+	state                  protoimpl.MessageState `protogen:"open.v1"`
+	IsSurveyExpired        *bool                  `protobuf:"varint,1,opt,name=isSurveyExpired" json:"isSurveyExpired,omitempty"`
+	ClickDwellTimeMSString *string                `protobuf:"bytes,2,opt,name=clickDwellTimeMSString" json:"clickDwellTimeMSString,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[64]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData) ProtoMessage() {
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[64]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0, 0, 3}
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData) GetIsSurveyExpired() bool {
+	if x != nil && x.IsSurveyExpired != nil {
+		return *x.IsSurveyExpired
+	}
+	return false
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData) GetClickDwellTimeMSString() string {
+	if x != nil && x.ClickDwellTimeMSString != nil {
+		return *x.ClickDwellTimeMSString
+	}
+	return ""
+}
+
+type BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData struct {
+	state           protoimpl.MessageState `protogen:"open.v1"`
+	IsSurveyExpired *bool                  `protobuf:"varint,1,opt,name=isSurveyExpired" json:"isSurveyExpired,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData) Reset() {
+	*x = BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[65]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData) ProtoMessage() {
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[65]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData.ProtoReflect.Descriptor instead.
+func (*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{16, 0, 0, 4}
+}
+
+func (x *BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData) GetIsSurveyExpired() bool {
+	if x != nil && x.IsSurveyExpired != nil {
+		return *x.IsSurveyExpired
+	}
+	return false
+}
+
+type AIRichResponseCodeMetadata_AIRichResponseCodeBlock struct {
+	state         protoimpl.MessageState                                      `protogen:"open.v1"`
+	HighlightType *AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType `protobuf:"varint,1,opt,name=highlightType,enum=WAAICommon.AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType" json:"highlightType,omitempty"`
+	CodeContent   *string                                                     `protobuf:"bytes,2,opt,name=codeContent" json:"codeContent,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseCodeMetadata_AIRichResponseCodeBlock) Reset() {
+	*x = AIRichResponseCodeMetadata_AIRichResponseCodeBlock{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[66]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseCodeMetadata_AIRichResponseCodeBlock) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseCodeMetadata_AIRichResponseCodeBlock) ProtoMessage() {}
+
+func (x *AIRichResponseCodeMetadata_AIRichResponseCodeBlock) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[66]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseCodeMetadata_AIRichResponseCodeBlock.ProtoReflect.Descriptor instead.
+func (*AIRichResponseCodeMetadata_AIRichResponseCodeBlock) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{18, 0}
+}
+
+func (x *AIRichResponseCodeMetadata_AIRichResponseCodeBlock) GetHighlightType() AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType {
+	if x != nil && x.HighlightType != nil {
+		return *x.HighlightType
+	}
+	return AIRichResponseCodeMetadata_AI_RICH_RESPONSE_CODE_HIGHLIGHT_DEFAULT
+}
+
+func (x *AIRichResponseCodeMetadata_AIRichResponseCodeBlock) GetCodeContent() string {
+	if x != nil && x.CodeContent != nil {
+		return *x.CodeContent
+	}
+	return ""
+}
+
+type AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to AIRichResponseContentItem:
+	//
+	//	*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_ReelItem
+	AIRichResponseContentItem isAIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_AIRichResponseContentItem `protobuf_oneof:"aIRichResponseContentItem"`
+	unknownFields             protoimpl.UnknownFields
+	sizeCache                 protoimpl.SizeCache
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata) Reset() {
+	*x = AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[67]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata) ProtoMessage() {}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[67]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata.ProtoReflect.Descriptor instead.
+func (*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{20, 0}
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata) GetAIRichResponseContentItem() isAIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_AIRichResponseContentItem {
+	if x != nil {
+		return x.AIRichResponseContentItem
+	}
+	return nil
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata) GetReelItem() *AIRichResponseContentItemsMetadata_AIRichResponseReelItem {
+	if x != nil {
+		if x, ok := x.AIRichResponseContentItem.(*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_ReelItem); ok {
+			return x.ReelItem
+		}
+	}
+	return nil
+}
+
+type isAIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_AIRichResponseContentItem interface {
+	isAIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_AIRichResponseContentItem()
+}
+
+type AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_ReelItem struct {
+	ReelItem *AIRichResponseContentItemsMetadata_AIRichResponseReelItem `protobuf:"bytes,1,opt,name=reelItem,oneof"`
+}
+
+func (*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_ReelItem) isAIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_AIRichResponseContentItem() {
+}
+
+type AIRichResponseContentItemsMetadata_AIRichResponseReelItem struct {
+	state          protoimpl.MessageState `protogen:"open.v1"`
+	Title          *string                `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"`
+	ProfileIconURL *string                `protobuf:"bytes,2,opt,name=profileIconURL" json:"profileIconURL,omitempty"`
+	ThumbnailURL   *string                `protobuf:"bytes,3,opt,name=thumbnailURL" json:"thumbnailURL,omitempty"`
+	VideoURL       *string                `protobuf:"bytes,4,opt,name=videoURL" json:"videoURL,omitempty"`
+	unknownFields  protoimpl.UnknownFields
+	sizeCache      protoimpl.SizeCache
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseReelItem) Reset() {
+	*x = AIRichResponseContentItemsMetadata_AIRichResponseReelItem{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[68]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseReelItem) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseContentItemsMetadata_AIRichResponseReelItem) ProtoMessage() {}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseReelItem) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[68]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseContentItemsMetadata_AIRichResponseReelItem.ProtoReflect.Descriptor instead.
+func (*AIRichResponseContentItemsMetadata_AIRichResponseReelItem) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{20, 1}
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseReelItem) GetTitle() string {
+	if x != nil && x.Title != nil {
+		return *x.Title
+	}
+	return ""
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseReelItem) GetProfileIconURL() string {
+	if x != nil && x.ProfileIconURL != nil {
+		return *x.ProfileIconURL
+	}
+	return ""
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseReelItem) GetThumbnailURL() string {
+	if x != nil && x.ThumbnailURL != nil {
+		return *x.ThumbnailURL
+	}
+	return ""
+}
+
+func (x *AIRichResponseContentItemsMetadata_AIRichResponseReelItem) GetVideoURL() string {
+	if x != nil && x.VideoURL != nil {
+		return *x.VideoURL
+	}
+	return ""
+}
+
+type AIHomeState_AIHomeOption struct {
+	state                protoimpl.MessageState                     `protogen:"open.v1"`
+	Type                 *AIHomeState_AIHomeOption_AIHomeActionType `protobuf:"varint,1,opt,name=type,enum=WAAICommon.AIHomeState_AIHomeOption_AIHomeActionType" json:"type,omitempty"`
+	Title                *string                                    `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"`
+	PromptText           *string                                    `protobuf:"bytes,3,opt,name=promptText" json:"promptText,omitempty"`
+	SessionID            *string                                    `protobuf:"bytes,4,opt,name=sessionID" json:"sessionID,omitempty"`
+	ImageWdsIdentifier   *string                                    `protobuf:"bytes,5,opt,name=imageWdsIdentifier" json:"imageWdsIdentifier,omitempty"`
+	ImageTintColor       *string                                    `protobuf:"bytes,6,opt,name=imageTintColor" json:"imageTintColor,omitempty"`
+	ImageBackgroundColor *string                                    `protobuf:"bytes,7,opt,name=imageBackgroundColor" json:"imageBackgroundColor,omitempty"`
+	unknownFields        protoimpl.UnknownFields
+	sizeCache            protoimpl.SizeCache
+}
+
+func (x *AIHomeState_AIHomeOption) Reset() {
+	*x = AIHomeState_AIHomeOption{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[69]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIHomeState_AIHomeOption) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIHomeState_AIHomeOption) ProtoMessage() {}
+
+func (x *AIHomeState_AIHomeOption) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[69]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIHomeState_AIHomeOption.ProtoReflect.Descriptor instead.
+func (*AIHomeState_AIHomeOption) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{22, 0}
+}
+
+func (x *AIHomeState_AIHomeOption) GetType() AIHomeState_AIHomeOption_AIHomeActionType {
+	if x != nil && x.Type != nil {
+		return *x.Type
+	}
+	return AIHomeState_AIHomeOption_PROMPT
+}
+
+func (x *AIHomeState_AIHomeOption) GetTitle() string {
+	if x != nil && x.Title != nil {
+		return *x.Title
+	}
+	return ""
+}
+
+func (x *AIHomeState_AIHomeOption) GetPromptText() string {
+	if x != nil && x.PromptText != nil {
+		return *x.PromptText
+	}
+	return ""
+}
+
+func (x *AIHomeState_AIHomeOption) GetSessionID() string {
+	if x != nil && x.SessionID != nil {
+		return *x.SessionID
+	}
+	return ""
+}
+
+func (x *AIHomeState_AIHomeOption) GetImageWdsIdentifier() string {
+	if x != nil && x.ImageWdsIdentifier != nil {
+		return *x.ImageWdsIdentifier
+	}
+	return ""
+}
+
+func (x *AIHomeState_AIHomeOption) GetImageTintColor() string {
+	if x != nil && x.ImageTintColor != nil {
+		return *x.ImageTintColor
+	}
+	return ""
+}
+
+func (x *AIHomeState_AIHomeOption) GetImageBackgroundColor() string {
+	if x != nil && x.ImageBackgroundColor != nil {
+		return *x.ImageBackgroundColor
+	}
+	return ""
+}
+
+type BotRenderingMetadata_Keyword struct {
+	state             protoimpl.MessageState `protogen:"open.v1"`
+	Value             *string                `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"`
+	AssociatedPrompts []string               `protobuf:"bytes,2,rep,name=associatedPrompts" json:"associatedPrompts,omitempty"`
+	unknownFields     protoimpl.UnknownFields
+	sizeCache         protoimpl.SizeCache
+}
+
+func (x *BotRenderingMetadata_Keyword) Reset() {
+	*x = BotRenderingMetadata_Keyword{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[70]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotRenderingMetadata_Keyword) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotRenderingMetadata_Keyword) ProtoMessage() {}
+
+func (x *BotRenderingMetadata_Keyword) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[70]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotRenderingMetadata_Keyword.ProtoReflect.Descriptor instead.
+func (*BotRenderingMetadata_Keyword) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{31, 0}
+}
+
+func (x *BotRenderingMetadata_Keyword) GetValue() string {
+	if x != nil && x.Value != nil {
+		return *x.Value
+	}
+	return ""
+}
+
+func (x *BotRenderingMetadata_Keyword) GetAssociatedPrompts() []string {
+	if x != nil {
+		return x.AssociatedPrompts
+	}
+	return nil
+}
+
+type InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Text          *string                `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"`
+	URL           *string                `protobuf:"bytes,2,opt,name=URL" json:"URL,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart) Reset() {
+	*x = InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[71]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart) ProtoMessage() {}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[71]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart.ProtoReflect.Descriptor instead.
+func (*InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{35, 0}
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart) GetText() string {
+	if x != nil && x.Text != nil {
+		return *x.Text
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart) GetURL() string {
+	if x != nil && x.URL != nil {
+		return *x.URL
+	}
+	return ""
+}
+
+type InThreadSurveyMetadata_InThreadSurveyOption struct {
+	state          protoimpl.MessageState `protogen:"open.v1"`
+	StringValue    *string                `protobuf:"bytes,1,opt,name=stringValue" json:"stringValue,omitempty"`
+	NumericValue   *uint32                `protobuf:"varint,2,opt,name=numericValue" json:"numericValue,omitempty"`
+	TextTranslated *string                `protobuf:"bytes,3,opt,name=textTranslated" json:"textTranslated,omitempty"`
+	unknownFields  protoimpl.UnknownFields
+	sizeCache      protoimpl.SizeCache
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyOption) Reset() {
+	*x = InThreadSurveyMetadata_InThreadSurveyOption{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[72]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyOption) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InThreadSurveyMetadata_InThreadSurveyOption) ProtoMessage() {}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyOption) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[72]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InThreadSurveyMetadata_InThreadSurveyOption.ProtoReflect.Descriptor instead.
+func (*InThreadSurveyMetadata_InThreadSurveyOption) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{35, 1}
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyOption) GetStringValue() string {
+	if x != nil && x.StringValue != nil {
+		return *x.StringValue
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyOption) GetNumericValue() uint32 {
+	if x != nil && x.NumericValue != nil {
+		return *x.NumericValue
+	}
+	return 0
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyOption) GetTextTranslated() string {
+	if x != nil && x.TextTranslated != nil {
+		return *x.TextTranslated
+	}
+	return ""
+}
+
+type InThreadSurveyMetadata_InThreadSurveyQuestion struct {
+	state           protoimpl.MessageState                         `protogen:"open.v1"`
+	QuestionText    *string                                        `protobuf:"bytes,1,opt,name=questionText" json:"questionText,omitempty"`
+	QuestionID      *string                                        `protobuf:"bytes,2,opt,name=questionID" json:"questionID,omitempty"`
+	QuestionOptions []*InThreadSurveyMetadata_InThreadSurveyOption `protobuf:"bytes,3,rep,name=questionOptions" json:"questionOptions,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyQuestion) Reset() {
+	*x = InThreadSurveyMetadata_InThreadSurveyQuestion{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[73]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyQuestion) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InThreadSurveyMetadata_InThreadSurveyQuestion) ProtoMessage() {}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyQuestion) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[73]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InThreadSurveyMetadata_InThreadSurveyQuestion.ProtoReflect.Descriptor instead.
+func (*InThreadSurveyMetadata_InThreadSurveyQuestion) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{35, 2}
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyQuestion) GetQuestionText() string {
+	if x != nil && x.QuestionText != nil {
+		return *x.QuestionText
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyQuestion) GetQuestionID() string {
+	if x != nil && x.QuestionID != nil {
+		return *x.QuestionID
+	}
+	return ""
+}
+
+func (x *InThreadSurveyMetadata_InThreadSurveyQuestion) GetQuestionOptions() []*InThreadSurveyMetadata_InThreadSurveyOption {
+	if x != nil {
+		return x.QuestionOptions
+	}
+	return nil
+}
+
+type BotUnifiedResponseMutation_MediaDetailsMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	ID            *string                `protobuf:"bytes,1,opt,name=ID" json:"ID,omitempty"`
+	HighResMedia  *BotMediaMetadata      `protobuf:"bytes,2,opt,name=highResMedia" json:"highResMedia,omitempty"`
+	PreviewMedia  *BotMediaMetadata      `protobuf:"bytes,3,opt,name=previewMedia" json:"previewMedia,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BotUnifiedResponseMutation_MediaDetailsMetadata) Reset() {
+	*x = BotUnifiedResponseMutation_MediaDetailsMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[74]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotUnifiedResponseMutation_MediaDetailsMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotUnifiedResponseMutation_MediaDetailsMetadata) ProtoMessage() {}
+
+func (x *BotUnifiedResponseMutation_MediaDetailsMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[74]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotUnifiedResponseMutation_MediaDetailsMetadata.ProtoReflect.Descriptor instead.
+func (*BotUnifiedResponseMutation_MediaDetailsMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{37, 0}
+}
+
+func (x *BotUnifiedResponseMutation_MediaDetailsMetadata) GetID() string {
+	if x != nil && x.ID != nil {
+		return *x.ID
+	}
+	return ""
+}
+
+func (x *BotUnifiedResponseMutation_MediaDetailsMetadata) GetHighResMedia() *BotMediaMetadata {
+	if x != nil {
+		return x.HighResMedia
+	}
+	return nil
+}
+
+func (x *BotUnifiedResponseMutation_MediaDetailsMetadata) GetPreviewMedia() *BotMediaMetadata {
+	if x != nil {
+		return x.PreviewMedia
+	}
+	return nil
+}
+
+type BotUnifiedResponseMutation_SideBySideMetadata struct {
+	state                protoimpl.MessageState `protogen:"open.v1"`
+	PrimaryResponseID    *string                `protobuf:"bytes,1,opt,name=primaryResponseID" json:"primaryResponseID,omitempty"`
+	SurveyCtaHasRendered *bool                  `protobuf:"varint,2,opt,name=surveyCtaHasRendered" json:"surveyCtaHasRendered,omitempty"`
+	unknownFields        protoimpl.UnknownFields
+	sizeCache            protoimpl.SizeCache
+}
+
+func (x *BotUnifiedResponseMutation_SideBySideMetadata) Reset() {
+	*x = BotUnifiedResponseMutation_SideBySideMetadata{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[75]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BotUnifiedResponseMutation_SideBySideMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BotUnifiedResponseMutation_SideBySideMetadata) ProtoMessage() {}
+
+func (x *BotUnifiedResponseMutation_SideBySideMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[75]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BotUnifiedResponseMutation_SideBySideMetadata.ProtoReflect.Descriptor instead.
+func (*BotUnifiedResponseMutation_SideBySideMetadata) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{37, 1}
+}
+
+func (x *BotUnifiedResponseMutation_SideBySideMetadata) GetPrimaryResponseID() string {
+	if x != nil && x.PrimaryResponseID != nil {
+		return *x.PrimaryResponseID
+	}
+	return ""
+}
+
+func (x *BotUnifiedResponseMutation_SideBySideMetadata) GetSurveyCtaHasRendered() bool {
+	if x != nil && x.SurveyCtaHasRendered != nil {
+		return *x.SurveyCtaHasRendered
+	}
+	return false
+}
+
+type AIRichResponseTableMetadata_AIRichResponseTableRow struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Items         []string               `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"`
+	IsHeading     *bool                  `protobuf:"varint,2,opt,name=isHeading" json:"isHeading,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *AIRichResponseTableMetadata_AIRichResponseTableRow) Reset() {
+	*x = AIRichResponseTableMetadata_AIRichResponseTableRow{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[76]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseTableMetadata_AIRichResponseTableRow) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseTableMetadata_AIRichResponseTableRow) ProtoMessage() {}
+
+func (x *AIRichResponseTableMetadata_AIRichResponseTableRow) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[76]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseTableMetadata_AIRichResponseTableRow.ProtoReflect.Descriptor instead.
+func (*AIRichResponseTableMetadata_AIRichResponseTableRow) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{43, 0}
+}
+
+func (x *AIRichResponseTableMetadata_AIRichResponseTableRow) GetItems() []string {
+	if x != nil {
+		return x.Items
+	}
+	return nil
+}
+
+func (x *AIRichResponseTableMetadata_AIRichResponseTableRow) GetIsHeading() bool {
+	if x != nil && x.IsHeading != nil {
+		return *x.IsHeading
+	}
+	return false
+}
+
+type AIRichResponseLatexMetadata_AIRichResponseLatexExpression struct {
+	state                protoimpl.MessageState `protogen:"open.v1"`
+	LatexExpression      *string                `protobuf:"bytes,1,opt,name=latexExpression" json:"latexExpression,omitempty"`
+	URL                  *string                `protobuf:"bytes,2,opt,name=URL" json:"URL,omitempty"`
+	Width                *float64               `protobuf:"fixed64,3,opt,name=width" json:"width,omitempty"`
+	Height               *float64               `protobuf:"fixed64,4,opt,name=height" json:"height,omitempty"`
+	FontHeight           *float64               `protobuf:"fixed64,5,opt,name=fontHeight" json:"fontHeight,omitempty"`
+	ImageTopPadding      *float64               `protobuf:"fixed64,6,opt,name=imageTopPadding" json:"imageTopPadding,omitempty"`
+	ImageLeadingPadding  *float64               `protobuf:"fixed64,7,opt,name=imageLeadingPadding" json:"imageLeadingPadding,omitempty"`
+	ImageBottomPadding   *float64               `protobuf:"fixed64,8,opt,name=imageBottomPadding" json:"imageBottomPadding,omitempty"`
+	ImageTrailingPadding *float64               `protobuf:"fixed64,9,opt,name=imageTrailingPadding" json:"imageTrailingPadding,omitempty"`
+	unknownFields        protoimpl.UnknownFields
+	sizeCache            protoimpl.SizeCache
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) Reset() {
+	*x = AIRichResponseLatexMetadata_AIRichResponseLatexExpression{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[77]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseLatexMetadata_AIRichResponseLatexExpression) ProtoMessage() {}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[77]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseLatexMetadata_AIRichResponseLatexExpression.ProtoReflect.Descriptor instead.
+func (*AIRichResponseLatexMetadata_AIRichResponseLatexExpression) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{45, 0}
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetLatexExpression() string {
+	if x != nil && x.LatexExpression != nil {
+		return *x.LatexExpression
+	}
+	return ""
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetURL() string {
+	if x != nil && x.URL != nil {
+		return *x.URL
+	}
+	return ""
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetWidth() float64 {
+	if x != nil && x.Width != nil {
+		return *x.Width
+	}
+	return 0
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetHeight() float64 {
+	if x != nil && x.Height != nil {
+		return *x.Height
+	}
+	return 0
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetFontHeight() float64 {
+	if x != nil && x.FontHeight != nil {
+		return *x.FontHeight
+	}
+	return 0
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetImageTopPadding() float64 {
+	if x != nil && x.ImageTopPadding != nil {
+		return *x.ImageTopPadding
+	}
+	return 0
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetImageLeadingPadding() float64 {
+	if x != nil && x.ImageLeadingPadding != nil {
+		return *x.ImageLeadingPadding
+	}
+	return 0
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetImageBottomPadding() float64 {
+	if x != nil && x.ImageBottomPadding != nil {
+		return *x.ImageBottomPadding
+	}
+	return 0
+}
+
+func (x *AIRichResponseLatexMetadata_AIRichResponseLatexExpression) GetImageTrailingPadding() float64 {
+	if x != nil && x.ImageTrailingPadding != nil {
+		return *x.ImageTrailingPadding
+	}
+	return 0
+}
+
+type AIRichResponseMapMetadata_AIRichResponseMapAnnotation struct {
+	state            protoimpl.MessageState `protogen:"open.v1"`
+	AnnotationNumber *uint32                `protobuf:"varint,1,opt,name=annotationNumber" json:"annotationNumber,omitempty"`
+	Latitude         *float64               `protobuf:"fixed64,2,opt,name=latitude" json:"latitude,omitempty"`
+	Longitude        *float64               `protobuf:"fixed64,3,opt,name=longitude" json:"longitude,omitempty"`
+	Title            *string                `protobuf:"bytes,4,opt,name=title" json:"title,omitempty"`
+	Body             *string                `protobuf:"bytes,5,opt,name=body" json:"body,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) Reset() {
+	*x = AIRichResponseMapMetadata_AIRichResponseMapAnnotation{}
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[78]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AIRichResponseMapMetadata_AIRichResponseMapAnnotation) ProtoMessage() {}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) ProtoReflect() protoreflect.Message {
+	mi := &file_waAICommon_WAAICommon_proto_msgTypes[78]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AIRichResponseMapMetadata_AIRichResponseMapAnnotation.ProtoReflect.Descriptor instead.
+func (*AIRichResponseMapMetadata_AIRichResponseMapAnnotation) Descriptor() ([]byte, []int) {
+	return file_waAICommon_WAAICommon_proto_rawDescGZIP(), []int{46, 0}
+}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) GetAnnotationNumber() uint32 {
+	if x != nil && x.AnnotationNumber != nil {
+		return *x.AnnotationNumber
+	}
+	return 0
+}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) GetLatitude() float64 {
+	if x != nil && x.Latitude != nil {
+		return *x.Latitude
+	}
+	return 0
+}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) GetLongitude() float64 {
+	if x != nil && x.Longitude != nil {
+		return *x.Longitude
+	}
+	return 0
+}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) GetTitle() string {
+	if x != nil && x.Title != nil {
+		return *x.Title
+	}
+	return ""
+}
+
+func (x *AIRichResponseMapMetadata_AIRichResponseMapAnnotation) GetBody() string {
+	if x != nil && x.Body != nil {
+		return *x.Body
+	}
+	return ""
+}
+
+var File_waAICommon_WAAICommon_proto protoreflect.FileDescriptor
+
+const file_waAICommon_WAAICommon_proto_rawDesc = "" +
+	"\n" +
+	"\x1bwaAICommon/WAAICommon.proto\x12\n" +
+	"WAAICommon\x1a\x17waCommon/WACommon.proto\"\xc2\x06\n" +
+	"\x11BotPluginMetadata\x12H\n" +
+	"\bprovider\x18\x01 \x01(\x0e2,.WAAICommon.BotPluginMetadata.SearchProviderR\bprovider\x12H\n" +
+	"\n" +
+	"pluginType\x18\x02 \x01(\x0e2(.WAAICommon.BotPluginMetadata.PluginTypeR\n" +
+	"pluginType\x12(\n" +
+	"\x0fthumbnailCDNURL\x18\x03 \x01(\tR\x0fthumbnailCDNURL\x12.\n" +
+	"\x12profilePhotoCDNURL\x18\x04 \x01(\tR\x12profilePhotoCDNURL\x12,\n" +
+	"\x11searchProviderURL\x18\x05 \x01(\tR\x11searchProviderURL\x12&\n" +
+	"\x0ereferenceIndex\x18\x06 \x01(\rR\x0ereferenceIndex\x12.\n" +
+	"\x12expectedLinksCount\x18\a \x01(\rR\x12expectedLinksCount\x12 \n" +
+	"\vsearchQuery\x18\t \x01(\tR\vsearchQuery\x12L\n" +
+	"\x16parentPluginMessageKey\x18\n" +
+	" \x01(\v2\x14.WACommon.MessageKeyR\x16parentPluginMessageKey\x12R\n" +
+	"\x0fdeprecatedField\x18\v \x01(\x0e2(.WAAICommon.BotPluginMetadata.PluginTypeR\x0fdeprecatedField\x12T\n" +
+	"\x10parentPluginType\x18\f \x01(\x0e2(.WAAICommon.BotPluginMetadata.PluginTypeR\x10parentPluginType\x12$\n" +
+	"\rfaviconCDNURL\x18\r \x01(\tR\rfaviconCDNURL\"7\n" +
+	"\n" +
+	"PluginType\x12\x12\n" +
+	"\x0eUNKNOWN_PLUGIN\x10\x00\x12\t\n" +
+	"\x05REELS\x10\x01\x12\n" +
+	"\n" +
+	"\x06SEARCH\x10\x02\"@\n" +
+	"\x0eSearchProvider\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\b\n" +
+	"\x04BING\x10\x01\x12\n" +
+	"\n" +
+	"\x06GOOGLE\x10\x02\x12\v\n" +
+	"\aSUPPORT\x10\x03\"\x91\x01\n" +
+	"\x10BotLinkedAccount\x12E\n" +
+	"\x04type\x18\x01 \x01(\x0e21.WAAICommon.BotLinkedAccount.BotLinkedAccountTypeR\x04type\"6\n" +
+	"\x14BotLinkedAccountType\x12\x1e\n" +
+	"\x1aBOT_LINKED_ACCOUNT_TYPE_1P\x10\x00\"\xa2\x02\n" +
+	"$BotSignatureVerificationUseCaseProof\x12\x18\n" +
+	"\aversion\x18\x01 \x01(\x05R\aversion\x12^\n" +
+	"\auseCase\x18\x02 \x01(\x0e2D.WAAICommon.BotSignatureVerificationUseCaseProof.BotSignatureUseCaseR\auseCase\x12\x1c\n" +
+	"\tsignature\x18\x03 \x01(\fR\tsignature\x12*\n" +
+	"\x10certificateChain\x18\x04 \x03(\fR\x10certificateChain\"6\n" +
+	"\x13BotSignatureUseCase\x12\x0f\n" +
+	"\vUNSPECIFIED\x10\x00\x12\x0e\n" +
+	"\n" +
+	"WA_BOT_MSG\x10\x01\"\xe3\x01\n" +
+	"\x1bBotPromotionMessageMetadata\x12^\n" +
+	"\rpromotionType\x18\x01 \x01(\x0e28.WAAICommon.BotPromotionMessageMetadata.BotPromotionTypeR\rpromotionType\x12 \n" +
+	"\vbuttonTitle\x18\x02 \x01(\tR\vbuttonTitle\"B\n" +
+	"\x10BotPromotionType\x12\x10\n" +
+	"\fUNKNOWN_TYPE\x10\x00\x12\a\n" +
+	"\x03C50\x10\x01\x12\x13\n" +
+	"\x0fSURVEY_PLATFORM\x10\x02\"\xea\x02\n" +
+	"\x10BotMediaMetadata\x12\x1e\n" +
+	"\n" +
+	"fileSHA256\x18\x01 \x01(\tR\n" +
+	"fileSHA256\x12\x1a\n" +
+	"\bmediaKey\x18\x02 \x01(\tR\bmediaKey\x12$\n" +
+	"\rfileEncSHA256\x18\x03 \x01(\tR\rfileEncSHA256\x12\x1e\n" +
+	"\n" +
+	"directPath\x18\x04 \x01(\tR\n" +
+	"directPath\x12,\n" +
+	"\x11mediaKeyTimestamp\x18\x05 \x01(\x03R\x11mediaKeyTimestamp\x12\x1a\n" +
+	"\bmimetype\x18\x06 \x01(\tR\bmimetype\x12V\n" +
+	"\x0forientationType\x18\a \x01(\x0e2,.WAAICommon.BotMediaMetadata.OrientationTypeR\x0forientationType\"2\n" +
+	"\x0fOrientationType\x12\n" +
+	"\n" +
+	"\x06CENTER\x10\x01\x12\b\n" +
+	"\x04LEFT\x10\x02\x12\t\n" +
+	"\x05RIGHT\x10\x03\"\xcd\x03\n" +
+	"\x13BotReminderMetadata\x12B\n" +
+	"\x11requestMessageKey\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\x11requestMessageKey\x12F\n" +
+	"\x06action\x18\x02 \x01(\x0e2..WAAICommon.BotReminderMetadata.ReminderActionR\x06action\x12\x12\n" +
+	"\x04name\x18\x03 \x01(\tR\x04name\x122\n" +
+	"\x14nextTriggerTimestamp\x18\x04 \x01(\x04R\x14nextTriggerTimestamp\x12O\n" +
+	"\tfrequency\x18\x05 \x01(\x0e21.WAAICommon.BotReminderMetadata.ReminderFrequencyR\tfrequency\"O\n" +
+	"\x11ReminderFrequency\x12\b\n" +
+	"\x04ONCE\x10\x01\x12\t\n" +
+	"\x05DAILY\x10\x02\x12\n" +
+	"\n" +
+	"\x06WEEKLY\x10\x03\x12\f\n" +
+	"\bBIWEEKLY\x10\x04\x12\v\n" +
+	"\aMONTHLY\x10\x05\"@\n" +
+	"\x0eReminderAction\x12\n" +
+	"\n" +
+	"\x06NOTIFY\x10\x01\x12\n" +
+	"\n" +
+	"\x06CREATE\x10\x02\x12\n" +
+	"\n" +
+	"\x06DELETE\x10\x03\x12\n" +
+	"\n" +
+	"\x06UPDATE\x10\x04\"\xff\x02\n" +
+	"\x10BotModelMetadata\x12D\n" +
+	"\tmodelType\x18\x01 \x01(\x0e2&.WAAICommon.BotModelMetadata.ModelTypeR\tmodelType\x12_\n" +
+	"\x12premiumModelStatus\x18\x02 \x01(\x0e2/.WAAICommon.BotModelMetadata.PremiumModelStatusR\x12premiumModelStatus\x12,\n" +
+	"\x11modelNameOverride\x18\x03 \x01(\tR\x11modelNameOverride\"O\n" +
+	"\x12PremiumModelStatus\x12\x12\n" +
+	"\x0eUNKNOWN_STATUS\x10\x00\x12\r\n" +
+	"\tAVAILABLE\x10\x01\x12\x16\n" +
+	"\x12QUOTA_EXCEED_LIMIT\x10\x02\"E\n" +
+	"\tModelType\x12\x10\n" +
+	"\fUNKNOWN_TYPE\x10\x00\x12\x0e\n" +
+	"\n" +
+	"LLAMA_PROD\x10\x01\x12\x16\n" +
+	"\x12LLAMA_PROD_PREMIUM\x10\x02\"\xb6\r\n" +
+	"\x1cBotProgressIndicatorMetadata\x120\n" +
+	"\x13progressDescription\x18\x01 \x01(\tR\x13progressDescription\x12f\n" +
+	"\rstepsMetadata\x18\x02 \x03(\v2@.WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadataR\rstepsMetadata\x1a\xfb\v\n" +
+	"\x17BotPlanningStepMetadata\x12 \n" +
+	"\vstatusTitle\x18\x01 \x01(\tR\vstatusTitle\x12\x1e\n" +
+	"\n" +
+	"statusBody\x18\x02 \x01(\tR\n" +
+	"statusBody\x12\x8b\x01\n" +
+	"\x0fsourcesMetadata\x18\x03 \x03(\v2a.WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourcesMetadataR\x0fsourcesMetadata\x12k\n" +
+	"\x06status\x18\x04 \x01(\x0e2S.WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.PlanningStepStatusR\x06status\x12 \n" +
+	"\visReasoning\x18\x05 \x01(\bR\visReasoning\x12*\n" +
+	"\x10isEnhancedSearch\x18\x06 \x01(\bR\x10isEnhancedSearch\x12{\n" +
+	"\bsections\x18\a \x03(\v2_.WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningStepSectionMetadataR\bsections\x1a\xd4\x02\n" +
+	" BotPlanningSearchSourcesMetadata\x12 \n" +
+	"\vsourceTitle\x18\x01 \x01(\tR\vsourceTitle\x12\x9e\x01\n" +
+	"\bprovider\x18\x02 \x01(\x0e2\x81\x01.WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourcesMetadata.BotPlanningSearchSourceProviderR\bprovider\x12\x1c\n" +
+	"\tsourceURL\x18\x03 \x01(\tR\tsourceURL\"O\n" +
+	"\x1fBotPlanningSearchSourceProvider\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\t\n" +
+	"\x05OTHER\x10\x01\x12\n" +
+	"\n" +
+	"\x06GOOGLE\x10\x02\x12\b\n" +
+	"\x04BING\x10\x03\x1a\xf3\x01\n" +
+	"\x1eBotPlanningStepSectionMetadata\x12\"\n" +
+	"\fsectionTitle\x18\x01 \x01(\tR\fsectionTitle\x12 \n" +
+	"\vsectionBody\x18\x02 \x01(\tR\vsectionBody\x12\x8a\x01\n" +
+	"\x0fsourcesMetadata\x18\x03 \x03(\v2`.WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourceMetadataR\x0fsourcesMetadata\x1a\xeb\x01\n" +
+	"\x1fBotPlanningSearchSourceMetadata\x12\x14\n" +
+	"\x05title\x18\x01 \x01(\tR\x05title\x12t\n" +
+	"\bprovider\x18\x02 \x01(\x0e2X.WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotSearchSourceProviderR\bprovider\x12\x1c\n" +
+	"\tsourceURL\x18\x03 \x01(\tR\tsourceURL\x12\x1e\n" +
+	"\n" +
+	"favIconURL\x18\x04 \x01(\tR\n" +
+	"favIconURL\"P\n" +
+	"\x17BotSearchSourceProvider\x12\x14\n" +
+	"\x10UNKNOWN_PROVIDER\x10\x00\x12\t\n" +
+	"\x05OTHER\x10\x01\x12\n" +
+	"\n" +
+	"\x06GOOGLE\x10\x02\x12\b\n" +
+	"\x04BING\x10\x03\"K\n" +
+	"\x12PlanningStepStatus\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\v\n" +
+	"\aPLANNED\x10\x01\x12\r\n" +
+	"\tEXECUTING\x10\x02\x12\f\n" +
+	"\bFINISHED\x10\x03\"\xc7\r\n" +
+	"\x15BotCapabilityMetadata\x12W\n" +
+	"\fcapabilities\x18\x01 \x03(\x0e23.WAAICommon.BotCapabilityMetadata.BotCapabilityTypeR\fcapabilities\"\xd4\f\n" +
+	"\x11BotCapabilityType\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\x16\n" +
+	"\x12PROGRESS_INDICATOR\x10\x01\x12\x19\n" +
+	"\x15RICH_RESPONSE_HEADING\x10\x02\x12\x1d\n" +
+	"\x19RICH_RESPONSE_NESTED_LIST\x10\x03\x12\r\n" +
+	"\tAI_MEMORY\x10\x04\x12 \n" +
+	"\x1cRICH_RESPONSE_THREAD_SURFING\x10\x05\x12\x17\n" +
+	"\x13RICH_RESPONSE_TABLE\x10\x06\x12\x16\n" +
+	"\x12RICH_RESPONSE_CODE\x10\a\x12%\n" +
+	"!RICH_RESPONSE_STRUCTURED_RESPONSE\x10\b\x12\x1e\n" +
+	"\x1aRICH_RESPONSE_INLINE_IMAGE\x10\t\x12#\n" +
+	"\x1fWA_IG_1P_PLUGIN_RANKING_CONTROL\x10\n" +
+	"\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_1\x10\v\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_2\x10\f\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_3\x10\r\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_4\x10\x0e\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_5\x10\x0f\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_6\x10\x10\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_7\x10\x11\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_8\x10\x12\x12$\n" +
+	" WA_IG_1P_PLUGIN_RANKING_UPDATE_9\x10\x13\x12%\n" +
+	"!WA_IG_1P_PLUGIN_RANKING_UPDATE_10\x10\x14\x12\x1d\n" +
+	"\x19RICH_RESPONSE_SUB_HEADING\x10\x15\x12\x1c\n" +
+	"\x18RICH_RESPONSE_GRID_IMAGE\x10\x16\x12\x18\n" +
+	"\x14AI_STUDIO_UGC_MEMORY\x10\x17\x12\x17\n" +
+	"\x13RICH_RESPONSE_LATEX\x10\x18\x12\x16\n" +
+	"\x12RICH_RESPONSE_MAPS\x10\x19\x12\x1e\n" +
+	"\x1aRICH_RESPONSE_INLINE_REELS\x10\x1a\x12\x14\n" +
+	"\x10AGENTIC_PLANNING\x10\x1b\x12\x13\n" +
+	"\x0fACCOUNT_LINKING\x10\x1c\x12\x1c\n" +
+	"\x18STREAMING_DISAGGREGATION\x10\x1d\x12\x1f\n" +
+	"\x1bRICH_RESPONSE_GRID_IMAGE_3P\x10\x1e\x12\x1e\n" +
+	"\x1aRICH_RESPONSE_LATEX_INLINE\x10\x1f\x12\x0e\n" +
+	"\n" +
+	"QUERY_PLAN\x10 \x12\x15\n" +
+	"\x11PROACTIVE_MESSAGE\x10!\x12\"\n" +
+	"\x1eRICH_RESPONSE_UNIFIED_RESPONSE\x10\"\x12\x15\n" +
+	"\x11PROMOTION_MESSAGE\x10#\x12\x1b\n" +
+	"\x17SIMPLIFIED_PROFILE_PAGE\x10$\x12$\n" +
+	" RICH_RESPONSE_SOURCES_IN_MESSAGE\x10%\x12%\n" +
+	"!RICH_RESPONSE_SIDE_BY_SIDE_SURVEY\x10&\x12(\n" +
+	"$RICH_RESPONSE_UNIFIED_TEXT_COMPONENT\x10'\x12\x14\n" +
+	"\x10AI_SHARED_MEMORY\x10(\x12!\n" +
+	"\x1dRICH_RESPONSE_UNIFIED_SOURCES\x10)\x12*\n" +
+	"&RICH_RESPONSE_UNIFIED_DOMAIN_CITATIONS\x10*\x12)\n" +
+	"%RICH_RESPONSE_UR_INLINE_REELS_ENABLED\x10+\x12'\n" +
+	"#RICH_RESPONSE_UR_MEDIA_GRID_ENABLED\x10,\x12*\n" +
+	"&RICH_RESPONSE_UR_TIMESTAMP_PLACEHOLDER\x10-\x12\x1f\n" +
+	"\x1bRICH_RESPONSE_IN_APP_SURVEY\x10.\x12\x1e\n" +
+	"\x1aAI_RESPONSE_MODEL_BRANDING\x10/\x12'\n" +
+	"#SESSION_TRANSPARENCY_SYSTEM_MESSAGE\x100\x12\x1e\n" +
+	"\x1aRICH_RESPONSE_UR_REASONING\x101\"\xa7\x01\n" +
+	"\x18BotModeSelectionMetadata\x12M\n" +
+	"\x04mode\x18\x01 \x03(\x0e29.WAAICommon.BotModeSelectionMetadata.BotUserSelectionModeR\x04mode\"<\n" +
+	"\x14BotUserSelectionMode\x12\x10\n" +
+	"\fUNKNOWN_MODE\x10\x00\x12\x12\n" +
+	"\x0eREASONING_MODE\x10\x01\"\x9d\x03\n" +
+	"\x10BotQuotaMetadata\x12n\n" +
+	"\x17botFeatureQuotaMetadata\x18\x01 \x03(\v24.WAAICommon.BotQuotaMetadata.BotFeatureQuotaMetadataR\x17botFeatureQuotaMetadata\x1a\x98\x02\n" +
+	"\x17BotFeatureQuotaMetadata\x12e\n" +
+	"\vfeatureType\x18\x01 \x01(\x0e2C.WAAICommon.BotQuotaMetadata.BotFeatureQuotaMetadata.BotFeatureTypeR\vfeatureType\x12&\n" +
+	"\x0eremainingQuota\x18\x02 \x01(\rR\x0eremainingQuota\x120\n" +
+	"\x13expirationTimestamp\x18\x03 \x01(\x04R\x13expirationTimestamp\"<\n" +
+	"\x0eBotFeatureType\x12\x13\n" +
+	"\x0fUNKNOWN_FEATURE\x10\x00\x12\x15\n" +
+	"\x11REASONING_FEATURE\x10\x01\"\xaa\x01\n" +
+	"\x12BotImagineMetadata\x12L\n" +
+	"\vimagineType\x18\x01 \x01(\x0e2*.WAAICommon.BotImagineMetadata.ImagineTypeR\vimagineType\"F\n" +
+	"\vImagineType\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\v\n" +
+	"\aIMAGINE\x10\x01\x12\b\n" +
+	"\x04MEMU\x10\x02\x12\t\n" +
+	"\x05FLASH\x10\x03\x12\b\n" +
+	"\x04EDIT\x10\x04\"\xb7\x02\n" +
+	"\x18BotAgeCollectionMetadata\x124\n" +
+	"\x15ageCollectionEligible\x18\x01 \x01(\bR\x15ageCollectionEligible\x12N\n" +
+	"\"shouldTriggerAgeCollectionOnClient\x18\x02 \x01(\bR\"shouldTriggerAgeCollectionOnClient\x12d\n" +
+	"\x11ageCollectionType\x18\x03 \x01(\x0e26.WAAICommon.BotAgeCollectionMetadata.AgeCollectionTypeR\x11ageCollectionType\"/\n" +
+	"\x11AgeCollectionType\x12\x0e\n" +
+	"\n" +
+	"O18_BINARY\x10\x00\x12\n" +
+	"\n" +
+	"\x06WAFFLE\x10\x01\"\xfe\x03\n" +
+	"\x12BotSourcesMetadata\x12F\n" +
+	"\asources\x18\x01 \x03(\v2,.WAAICommon.BotSourcesMetadata.BotSourceItemR\asources\x1a\x9f\x03\n" +
+	"\rBotSourceItem\x12W\n" +
+	"\bprovider\x18\x01 \x01(\x0e2;.WAAICommon.BotSourcesMetadata.BotSourceItem.SourceProviderR\bprovider\x12(\n" +
+	"\x0fthumbnailCDNURL\x18\x02 \x01(\tR\x0fthumbnailCDNURL\x12,\n" +
+	"\x11sourceProviderURL\x18\x03 \x01(\tR\x11sourceProviderURL\x12 \n" +
+	"\vsourceQuery\x18\x04 \x01(\tR\vsourceQuery\x12$\n" +
+	"\rfaviconCDNURL\x18\x05 \x01(\tR\rfaviconCDNURL\x12&\n" +
+	"\x0ecitationNumber\x18\x06 \x01(\rR\x0ecitationNumber\x12 \n" +
+	"\vsourceTitle\x18\a \x01(\tR\vsourceTitle\"K\n" +
+	"\x0eSourceProvider\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\b\n" +
+	"\x04BING\x10\x01\x12\n" +
+	"\n" +
+	"\x06GOOGLE\x10\x02\x12\v\n" +
+	"\aSUPPORT\x10\x03\x12\t\n" +
+	"\x05OTHER\x10\x04\"\x9b\x01\n" +
+	"\x10BotMessageOrigin\x12E\n" +
+	"\x04type\x18\x01 \x01(\x0e21.WAAICommon.BotMessageOrigin.BotMessageOriginTypeR\x04type\"@\n" +
+	"\x14BotMessageOriginType\x12(\n" +
+	"$BOT_MESSAGE_ORIGIN_TYPE_AI_INITIATED\x10\x00\"\xf2\x02\n" +
+	"\fAIThreadInfo\x12K\n" +
+	"\n" +
+	"serverInfo\x18\x01 \x01(\v2+.WAAICommon.AIThreadInfo.AIThreadServerInfoR\n" +
+	"serverInfo\x12K\n" +
+	"\n" +
+	"clientInfo\x18\x02 \x01(\v2+.WAAICommon.AIThreadInfo.AIThreadClientInfoR\n" +
+	"clientInfo\x1a\x9b\x01\n" +
+	"\x12AIThreadClientInfo\x12L\n" +
+	"\x04type\x18\x01 \x01(\x0e28.WAAICommon.AIThreadInfo.AIThreadClientInfo.AIThreadTypeR\x04type\"7\n" +
+	"\fAIThreadType\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\v\n" +
+	"\aDEFAULT\x10\x01\x12\r\n" +
+	"\tINCOGNITO\x10\x02\x1a*\n" +
+	"\x12AIThreadServerInfo\x12\x14\n" +
+	"\x05title\x18\x01 \x01(\tR\x05title\"\xe5\x1e\n" +
+	"\x12BotFeedbackMessage\x124\n" +
+	"\n" +
+	"messageKey\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\n" +
+	"messageKey\x12B\n" +
+	"\x04kind\x18\x02 \x01(\x0e2..WAAICommon.BotFeedbackMessage.BotFeedbackKindR\x04kind\x12\x12\n" +
+	"\x04text\x18\x03 \x01(\tR\x04text\x12\"\n" +
+	"\fkindNegative\x18\x04 \x01(\x04R\fkindNegative\x12\"\n" +
+	"\fkindPositive\x18\x05 \x01(\x04R\fkindPositive\x12I\n" +
+	"\n" +
+	"kindReport\x18\x06 \x01(\x0e2).WAAICommon.BotFeedbackMessage.ReportKindR\n" +
+	"kindReport\x12s\n" +
+	"\x18sideBySideSurveyMetadata\x18\a \x01(\v27.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadataR\x18sideBySideSurveyMetadata\x1a\x9c\x12\n" +
+	"\x18SideBySideSurveyMetadata\x12,\n" +
+	"\x11selectedRequestID\x18\x01 \x01(\tR\x11selectedRequestID\x12\x1a\n" +
+	"\bsurveyID\x18\x02 \x01(\rR\bsurveyID\x12*\n" +
+	"\x10simonSessionFbid\x18\x03 \x01(\tR\x10simonSessionFbid\x12\"\n" +
+	"\fresponseOtid\x18\x04 \x01(\tR\fresponseOtid\x12<\n" +
+	"\x19responseTimestampMSString\x18\x05 \x01(\tR\x19responseTimestampMSString\x12<\n" +
+	"\x19isSelectedResponsePrimary\x18\x06 \x01(\bR\x19isSelectedResponsePrimary\x12(\n" +
+	"\x0fmessageIDToEdit\x18\a \x01(\tR\x0fmessageIDToEdit\x12{\n" +
+	"\ranalyticsData\x18\b \x01(\v2U.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SideBySideSurveyAnalyticsDataR\ranalyticsData\x12\x8d\x01\n" +
+	"\x13metaAiAnalyticsData\x18\t \x01(\v2[.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsDataR\x13metaAiAnalyticsData\x1a\x98\f\n" +
+	"#SidebySideSurveyMetaAiAnalyticsData\x12\x1a\n" +
+	"\bsurveyID\x18\x01 \x01(\rR\bsurveyID\x12,\n" +
+	"\x11primaryResponseID\x18\x02 \x01(\tR\x11primaryResponseID\x12 \n" +
+	"\vtestArmName\x18\x03 \x01(\tR\vtestArmName\x12,\n" +
+	"\x11timestampMSString\x18\x04 \x01(\tR\x11timestampMSString\x12\xb3\x01\n" +
+	"\x12ctaImpressionEvent\x18\x05 \x01(\v2\x82\x01.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCTAImpressionEventDataR\x12ctaImpressionEvent\x12\xa3\x01\n" +
+	"\rctaClickEvent\x18\x06 \x01(\v2}.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCTAClickEventDataR\rctaClickEvent\x12\xb6\x01\n" +
+	"\x13cardImpressionEvent\x18\a \x01(\v2\x83\x01.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCardImpressionEventDataR\x13cardImpressionEvent\x12\xa3\x01\n" +
+	"\rresponseEvent\x18\b \x01(\v2}.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyResponseEventDataR\rresponseEvent\x12\xa0\x01\n" +
+	"\fabandonEvent\x18\t \x01(\v2|.WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyAbandonEventDataR\fabandonEvent\x1a^\n" +
+	" SideBySideSurveyAbandonEventData\x12:\n" +
+	"\x18abandonDwellTimeMSString\x18\x01 \x01(\tR\x18abandonDwellTimeMSString\x1a\x91\x01\n" +
+	"!SideBySideSurveyResponseEventData\x12<\n" +
+	"\x19responseDwellTimeMSString\x18\x01 \x01(\tR\x19responseDwellTimeMSString\x12.\n" +
+	"\x12selectedResponseID\x18\x02 \x01(\tR\x12selectedResponseID\x1a)\n" +
+	"'SideBySideSurveyCardImpressionEventData\x1a\x85\x01\n" +
+	"!SideBySideSurveyCTAClickEventData\x12(\n" +
+	"\x0fisSurveyExpired\x18\x01 \x01(\bR\x0fisSurveyExpired\x126\n" +
+	"\x16clickDwellTimeMSString\x18\x02 \x01(\tR\x16clickDwellTimeMSString\x1aR\n" +
+	"&SideBySideSurveyCTAImpressionEventData\x12(\n" +
+	"\x0fisSurveyExpired\x18\x01 \x01(\bR\x0fisSurveyExpired\x1a\x97\x01\n" +
+	"\x1dSideBySideSurveyAnalyticsData\x12\x1e\n" +
+	"\n" +
+	"tessaEvent\x18\x01 \x01(\tR\n" +
+	"tessaEvent\x12*\n" +
+	"\x10tessaSessionFbid\x18\x02 \x01(\tR\x10tessaSessionFbid\x12*\n" +
+	"\x10simonSessionFbid\x18\x03 \x01(\tR\x10simonSessionFbid\"#\n" +
+	"\n" +
+	"ReportKind\x12\b\n" +
+	"\x04NONE\x10\x00\x12\v\n" +
+	"\aGENERIC\x10\x01\"M\n" +
+	"\x1fBotFeedbackKindMultiplePositive\x12*\n" +
+	"&BOT_FEEDBACK_MULTIPLE_POSITIVE_GENERIC\x10\x01\"\xcb\x03\n" +
+	"\x1fBotFeedbackKindMultipleNegative\x12*\n" +
+	"&BOT_FEEDBACK_MULTIPLE_NEGATIVE_GENERIC\x10\x01\x12*\n" +
+	"&BOT_FEEDBACK_MULTIPLE_NEGATIVE_HELPFUL\x10\x02\x12.\n" +
+	"*BOT_FEEDBACK_MULTIPLE_NEGATIVE_INTERESTING\x10\x04\x12+\n" +
+	"'BOT_FEEDBACK_MULTIPLE_NEGATIVE_ACCURATE\x10\b\x12'\n" +
+	"#BOT_FEEDBACK_MULTIPLE_NEGATIVE_SAFE\x10\x10\x12(\n" +
+	"$BOT_FEEDBACK_MULTIPLE_NEGATIVE_OTHER\x10 \x12*\n" +
+	"&BOT_FEEDBACK_MULTIPLE_NEGATIVE_REFUSED\x10@\x12:\n" +
+	"5BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_VISUALLY_APPEALING\x10\x80\x01\x128\n" +
+	"3BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_RELEVANT_TO_TEXT\x10\x80\x02\"\xd7\x04\n" +
+	"\x0fBotFeedbackKind\x12\x19\n" +
+	"\x15BOT_FEEDBACK_POSITIVE\x10\x00\x12!\n" +
+	"\x1dBOT_FEEDBACK_NEGATIVE_GENERIC\x10\x01\x12!\n" +
+	"\x1dBOT_FEEDBACK_NEGATIVE_HELPFUL\x10\x02\x12%\n" +
+	"!BOT_FEEDBACK_NEGATIVE_INTERESTING\x10\x03\x12\"\n" +
+	"\x1eBOT_FEEDBACK_NEGATIVE_ACCURATE\x10\x04\x12\x1e\n" +
+	"\x1aBOT_FEEDBACK_NEGATIVE_SAFE\x10\x05\x12\x1f\n" +
+	"\x1bBOT_FEEDBACK_NEGATIVE_OTHER\x10\x06\x12!\n" +
+	"\x1dBOT_FEEDBACK_NEGATIVE_REFUSED\x10\a\x120\n" +
+	",BOT_FEEDBACK_NEGATIVE_NOT_VISUALLY_APPEALING\x10\b\x12.\n" +
+	"*BOT_FEEDBACK_NEGATIVE_NOT_RELEVANT_TO_TEXT\x10\t\x12&\n" +
+	"\"BOT_FEEDBACK_NEGATIVE_PERSONALIZED\x10\n" +
+	"\x12!\n" +
+	"\x1dBOT_FEEDBACK_NEGATIVE_CLARITY\x10\v\x125\n" +
+	"1BOT_FEEDBACK_NEGATIVE_DOESNT_LOOK_LIKE_THE_PERSON\x10\f\x125\n" +
+	"1BOT_FEEDBACK_NEGATIVE_HALLUCINATION_INTERNAL_ONLY\x10\r\x12\x19\n" +
+	"\x15BOT_FEEDBACK_NEGATIVE\x10\x0e\"\xc5\x03\n" +
+	"!AIRichResponseInlineImageMetadata\x12>\n" +
+	"\bimageURL\x18\x01 \x01(\v2\".WAAICommon.AIRichResponseImageURLR\bimageURL\x12\x1c\n" +
+	"\timageText\x18\x02 \x01(\tR\timageText\x12h\n" +
+	"\talignment\x18\x03 \x01(\x0e2J.WAAICommon.AIRichResponseInlineImageMetadata.AIRichResponseImageAlignmentR\talignment\x12\x1e\n" +
+	"\n" +
+	"tapLinkURL\x18\x04 \x01(\tR\n" +
+	"tapLinkURL\"\xb7\x01\n" +
+	"\x1cAIRichResponseImageAlignment\x121\n" +
+	"-AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED\x10\x00\x122\n" +
+	".AI_RICH_RESPONSE_IMAGE_LAYOUT_TRAILING_ALIGNED\x10\x01\x120\n" +
+	",AI_RICH_RESPONSE_IMAGE_LAYOUT_CENTER_ALIGNED\x10\x02\"\xfb\x04\n" +
+	"\x1aAIRichResponseCodeMetadata\x12\"\n" +
+	"\fcodeLanguage\x18\x01 \x01(\tR\fcodeLanguage\x12^\n" +
+	"\n" +
+	"codeBlocks\x18\x02 \x03(\v2>.WAAICommon.AIRichResponseCodeMetadata.AIRichResponseCodeBlockR\n" +
+	"codeBlocks\x1a\xa9\x01\n" +
+	"\x17AIRichResponseCodeBlock\x12l\n" +
+	"\rhighlightType\x18\x01 \x01(\x0e2F.WAAICommon.AIRichResponseCodeMetadata.AIRichResponseCodeHighlightTypeR\rhighlightType\x12 \n" +
+	"\vcodeContent\x18\x02 \x01(\tR\vcodeContent\"\xac\x02\n" +
+	"\x1fAIRichResponseCodeHighlightType\x12+\n" +
+	"'AI_RICH_RESPONSE_CODE_HIGHLIGHT_DEFAULT\x10\x00\x12+\n" +
+	"'AI_RICH_RESPONSE_CODE_HIGHLIGHT_KEYWORD\x10\x01\x12*\n" +
+	"&AI_RICH_RESPONSE_CODE_HIGHLIGHT_METHOD\x10\x02\x12*\n" +
+	"&AI_RICH_RESPONSE_CODE_HIGHLIGHT_STRING\x10\x03\x12*\n" +
+	"&AI_RICH_RESPONSE_CODE_HIGHLIGHT_NUMBER\x10\x04\x12+\n" +
+	"'AI_RICH_RESPONSE_CODE_HIGHLIGHT_COMMENT\x10\x05\"\x86\x03\n" +
+	"\x1dAIRichResponseDynamicMetadata\x12_\n" +
+	"\x04type\x18\x01 \x01(\x0e2K.WAAICommon.AIRichResponseDynamicMetadata.AIRichResponseDynamicMetadataTypeR\x04type\x12\x18\n" +
+	"\aversion\x18\x02 \x01(\x04R\aversion\x12\x10\n" +
+	"\x03URL\x18\x03 \x01(\tR\x03URL\x12\x1c\n" +
+	"\tloopCount\x18\x04 \x01(\rR\tloopCount\"\xb9\x01\n" +
+	"!AIRichResponseDynamicMetadataType\x122\n" +
+	".AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_UNKNOWN\x10\x00\x120\n" +
+	",AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_IMAGE\x10\x01\x12.\n" +
+	"*AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF\x10\x02\"\xe5\x04\n" +
+	"\"AIRichResponseContentItemsMetadata\x12v\n" +
+	"\ritemsMetadata\x18\x01 \x03(\v2P.WAAICommon.AIRichResponseContentItemsMetadata.AIRichResponseContentItemMetadataR\ritemsMetadata\x12\\\n" +
+	"\vcontentType\x18\x02 \x01(\x0e2:.WAAICommon.AIRichResponseContentItemsMetadata.ContentTypeR\vcontentType\x1a\xa5\x01\n" +
+	"!AIRichResponseContentItemMetadata\x12c\n" +
+	"\breelItem\x18\x01 \x01(\v2E.WAAICommon.AIRichResponseContentItemsMetadata.AIRichResponseReelItemH\x00R\breelItemB\x1b\n" +
+	"\x19aIRichResponseContentItem\x1a\x96\x01\n" +
+	"\x16AIRichResponseReelItem\x12\x14\n" +
+	"\x05title\x18\x01 \x01(\tR\x05title\x12&\n" +
+	"\x0eprofileIconURL\x18\x02 \x01(\tR\x0eprofileIconURL\x12\"\n" +
+	"\fthumbnailURL\x18\x03 \x01(\tR\fthumbnailURL\x12\x1a\n" +
+	"\bvideoURL\x18\x04 \x01(\tR\bvideoURL\"(\n" +
+	"\vContentType\x12\v\n" +
+	"\aDEFAULT\x10\x00\x12\f\n" +
+	"\bCAROUSEL\x10\x01\"\xb6\x01\n" +
+	"\x1aBotDocumentMessageMetadata\x12Y\n" +
+	"\n" +
+	"pluginType\x18\x01 \x01(\x0e29.WAAICommon.BotDocumentMessageMetadata.DocumentPluginTypeR\n" +
+	"pluginType\"=\n" +
+	"\x12DocumentPluginType\x12\x13\n" +
+	"\x0fTEXT_EXTRACTION\x10\x00\x12\x12\n" +
+	"\x0eOCR_AND_IMAGES\x10\x01\"\xf2\x04\n" +
+	"\vAIHomeState\x12$\n" +
+	"\rlastFetchTime\x18\x01 \x01(\x03R\rlastFetchTime\x12R\n" +
+	"\x11capabilityOptions\x18\x02 \x03(\v2$.WAAICommon.AIHomeState.AIHomeOptionR\x11capabilityOptions\x12V\n" +
+	"\x13conversationOptions\x18\x03 \x03(\v2$.WAAICommon.AIHomeState.AIHomeOptionR\x13conversationOptions\x1a\x90\x03\n" +
+	"\fAIHomeOption\x12I\n" +
+	"\x04type\x18\x01 \x01(\x0e25.WAAICommon.AIHomeState.AIHomeOption.AIHomeActionTypeR\x04type\x12\x14\n" +
+	"\x05title\x18\x02 \x01(\tR\x05title\x12\x1e\n" +
+	"\n" +
+	"promptText\x18\x03 \x01(\tR\n" +
+	"promptText\x12\x1c\n" +
+	"\tsessionID\x18\x04 \x01(\tR\tsessionID\x12.\n" +
+	"\x12imageWdsIdentifier\x18\x05 \x01(\tR\x12imageWdsIdentifier\x12&\n" +
+	"\x0eimageTintColor\x18\x06 \x01(\tR\x0eimageTintColor\x122\n" +
+	"\x14imageBackgroundColor\x18\a \x01(\tR\x14imageBackgroundColor\"U\n" +
+	"\x10AIHomeActionType\x12\n" +
+	"\n" +
+	"\x06PROMPT\x10\x00\x12\x10\n" +
+	"\fCREATE_IMAGE\x10\x01\x12\x11\n" +
+	"\rANIMATE_PHOTO\x10\x02\x12\x10\n" +
+	"\fANALYZE_FILE\x10\x03\"\xab\x01\n" +
+	"\x11BotAvatarMetadata\x12\x1c\n" +
+	"\tsentiment\x18\x01 \x01(\rR\tsentiment\x12$\n" +
+	"\rbehaviorGraph\x18\x02 \x01(\tR\rbehaviorGraph\x12\x16\n" +
+	"\x06action\x18\x03 \x01(\rR\x06action\x12\x1c\n" +
+	"\tintensity\x18\x04 \x01(\rR\tintensity\x12\x1c\n" +
+	"\twordCount\x18\x05 \x01(\rR\twordCount\"\xf6\x01\n" +
+	"\x1aBotSuggestedPromptMetadata\x12*\n" +
+	"\x10suggestedPrompts\x18\x01 \x03(\tR\x10suggestedPrompts\x120\n" +
+	"\x13selectedPromptIndex\x18\x02 \x01(\rR\x13selectedPromptIndex\x12N\n" +
+	"\x11promptSuggestions\x18\x03 \x01(\v2 .WAAICommon.BotPromptSuggestionsR\x11promptSuggestions\x12*\n" +
+	"\x10selectedPromptID\x18\x04 \x01(\tR\x10selectedPromptID\"Y\n" +
+	"\x14BotPromptSuggestions\x12A\n" +
+	"\vsuggestions\x18\x01 \x03(\v2\x1f.WAAICommon.BotPromptSuggestionR\vsuggestions\"I\n" +
+	"\x13BotPromptSuggestion\x12\x16\n" +
+	"\x06prompt\x18\x01 \x01(\tR\x06prompt\x12\x1a\n" +
+	"\bpromptID\x18\x02 \x01(\tR\bpromptID\"\x9b\x01\n" +
+	"\x19BotLinkedAccountsMetadata\x128\n" +
+	"\baccounts\x18\x01 \x03(\v2\x1c.WAAICommon.BotLinkedAccountR\baccounts\x12\"\n" +
+	"\facAuthTokens\x18\x02 \x01(\fR\facAuthTokens\x12 \n" +
+	"\vacErrorCode\x18\x03 \x01(\x05R\vacErrorCode\"\xad\x01\n" +
+	"\x11BotMemoryMetadata\x129\n" +
+	"\n" +
+	"addedFacts\x18\x01 \x03(\v2\x19.WAAICommon.BotMemoryFactR\n" +
+	"addedFacts\x12=\n" +
+	"\fremovedFacts\x18\x02 \x03(\v2\x19.WAAICommon.BotMemoryFactR\fremovedFacts\x12\x1e\n" +
+	"\n" +
+	"disclaimer\x18\x03 \x01(\tR\n" +
+	"disclaimer\";\n" +
+	"\rBotMemoryFact\x12\x12\n" +
+	"\x04fact\x18\x01 \x01(\tR\x04fact\x12\x16\n" +
+	"\x06factID\x18\x02 \x01(\tR\x06factID\"l\n" +
+	" BotSignatureVerificationMetadata\x12H\n" +
+	"\x06proofs\x18\x01 \x03(\v20.WAAICommon.BotSignatureVerificationUseCaseProofR\x06proofs\"\xab\x01\n" +
+	"\x14BotRenderingMetadata\x12D\n" +
+	"\bkeywords\x18\x01 \x03(\v2(.WAAICommon.BotRenderingMetadata.KeywordR\bkeywords\x1aM\n" +
+	"\aKeyword\x12\x14\n" +
+	"\x05value\x18\x01 \x01(\tR\x05value\x12,\n" +
+	"\x11associatedPrompts\x18\x02 \x03(\tR\x11associatedPrompts\"\xde\x01\n" +
+	"\x12BotMetricsMetadata\x12$\n" +
+	"\rdestinationID\x18\x01 \x01(\tR\rdestinationID\x12V\n" +
+	"\x15destinationEntryPoint\x18\x02 \x01(\x0e2 .WAAICommon.BotMetricsEntryPointR\x15destinationEntryPoint\x12J\n" +
+	"\fthreadOrigin\x18\x03 \x01(\x0e2&.WAAICommon.BotMetricsThreadEntryPointR\fthreadOrigin\"v\n" +
+	"\x12BotSessionMetadata\x12\x1c\n" +
+	"\tsessionID\x18\x01 \x01(\tR\tsessionID\x12B\n" +
+	"\rsessionSource\x18\x02 \x01(\x0e2\x1c.WAAICommon.BotSessionSourceR\rsessionSource\"O\n" +
+	"\x0fBotMemuMetadata\x12<\n" +
+	"\n" +
+	"faceImages\x18\x01 \x03(\v2\x1c.WAAICommon.BotMediaMetadataR\n" +
+	"faceImages\"\xbf\n" +
+	"\n" +
+	"\x16InThreadSurveyMetadata\x12&\n" +
+	"\x0etessaSessionID\x18\x01 \x01(\tR\x0etessaSessionID\x12&\n" +
+	"\x0esimonSessionID\x18\x02 \x01(\tR\x0esimonSessionID\x12$\n" +
+	"\rsimonSurveyID\x18\x03 \x01(\tR\rsimonSurveyID\x12 \n" +
+	"\vtessaRootID\x18\x04 \x01(\tR\vtessaRootID\x12\x1c\n" +
+	"\trequestID\x18\x05 \x01(\tR\trequestID\x12\x1e\n" +
+	"\n" +
+	"tessaEvent\x18\x06 \x01(\tR\n" +
+	"tessaEvent\x122\n" +
+	"\x14invitationHeaderText\x18\a \x01(\tR\x14invitationHeaderText\x12.\n" +
+	"\x12invitationBodyText\x18\b \x01(\tR\x12invitationBodyText\x12,\n" +
+	"\x11invitationCtaText\x18\t \x01(\tR\x11invitationCtaText\x12*\n" +
+	"\x10invitationCtaURL\x18\n" +
+	" \x01(\tR\x10invitationCtaURL\x12 \n" +
+	"\vsurveyTitle\x18\v \x01(\tR\vsurveyTitle\x12W\n" +
+	"\tquestions\x18\f \x03(\v29.WAAICommon.InThreadSurveyMetadata.InThreadSurveyQuestionR\tquestions\x12:\n" +
+	"\x18surveyContinueButtonText\x18\r \x01(\tR\x18surveyContinueButtonText\x126\n" +
+	"\x16surveySubmitButtonText\x18\x0e \x01(\tR\x16surveySubmitButtonText\x122\n" +
+	"\x14privacyStatementFull\x18\x0f \x01(\tR\x14privacyStatementFull\x12{\n" +
+	"\x15privacyStatementParts\x18\x10 \x03(\v2E.WAAICommon.InThreadSurveyMetadata.InThreadSurveyPrivacyStatementPartR\x15privacyStatementParts\x12,\n" +
+	"\x11feedbackToastText\x18\x11 \x01(\tR\x11feedbackToastText\x12.\n" +
+	"\x12startQuestionIndex\x18\x12 \x01(\x05R\x12startQuestionIndex\x1aJ\n" +
+	"\"InThreadSurveyPrivacyStatementPart\x12\x12\n" +
+	"\x04text\x18\x01 \x01(\tR\x04text\x12\x10\n" +
+	"\x03URL\x18\x02 \x01(\tR\x03URL\x1a\x84\x01\n" +
+	"\x14InThreadSurveyOption\x12 \n" +
+	"\vstringValue\x18\x01 \x01(\tR\vstringValue\x12\"\n" +
+	"\fnumericValue\x18\x02 \x01(\rR\fnumericValue\x12&\n" +
+	"\x0etextTranslated\x18\x03 \x01(\tR\x0etextTranslated\x1a\xbf\x01\n" +
+	"\x16InThreadSurveyQuestion\x12\"\n" +
+	"\fquestionText\x18\x01 \x01(\tR\fquestionText\x12\x1e\n" +
+	"\n" +
+	"questionID\x18\x02 \x01(\tR\n" +
+	"questionID\x12a\n" +
+	"\x0fquestionOptions\x18\x03 \x03(\v27.WAAICommon.InThreadSurveyMetadata.InThreadSurveyOptionR\x0fquestionOptions\"R\n" +
+	"\x18BotMessageOriginMetadata\x126\n" +
+	"\aorigins\x18\x01 \x03(\v2\x1c.WAAICommon.BotMessageOriginR\aorigins\"\x97\x04\n" +
+	"\x1aBotUnifiedResponseMutation\x12[\n" +
+	"\vsbsMetadata\x18\x01 \x01(\v29.WAAICommon.BotUnifiedResponseMutation.SideBySideMetadataR\vsbsMetadata\x12w\n" +
+	"\x18mediaDetailsMetadataList\x18\x02 \x03(\v2;.WAAICommon.BotUnifiedResponseMutation.MediaDetailsMetadataR\x18mediaDetailsMetadataList\x1a\xaa\x01\n" +
+	"\x14MediaDetailsMetadata\x12\x0e\n" +
+	"\x02ID\x18\x01 \x01(\tR\x02ID\x12@\n" +
+	"\fhighResMedia\x18\x02 \x01(\v2\x1c.WAAICommon.BotMediaMetadataR\fhighResMedia\x12@\n" +
+	"\fpreviewMedia\x18\x03 \x01(\v2\x1c.WAAICommon.BotMediaMetadataR\fpreviewMedia\x1av\n" +
+	"\x12SideBySideMetadata\x12,\n" +
+	"\x11primaryResponseID\x18\x01 \x01(\tR\x11primaryResponseID\x122\n" +
+	"\x14surveyCtaHasRendered\x18\x02 \x01(\bR\x14surveyCtaHasRendered\"\x87\x15\n" +
+	"\vBotMetadata\x12E\n" +
+	"\x0eavatarMetadata\x18\x01 \x01(\v2\x1d.WAAICommon.BotAvatarMetadataR\x0eavatarMetadata\x12\x1c\n" +
+	"\tpersonaID\x18\x02 \x01(\tR\tpersonaID\x12E\n" +
+	"\x0epluginMetadata\x18\x03 \x01(\v2\x1d.WAAICommon.BotPluginMetadataR\x0epluginMetadata\x12`\n" +
+	"\x17suggestedPromptMetadata\x18\x04 \x01(\v2&.WAAICommon.BotSuggestedPromptMetadataR\x17suggestedPromptMetadata\x12\x1e\n" +
+	"\n" +
+	"invokerJID\x18\x05 \x01(\tR\n" +
+	"invokerJID\x12H\n" +
+	"\x0fsessionMetadata\x18\x06 \x01(\v2\x1e.WAAICommon.BotSessionMetadataR\x0fsessionMetadata\x12?\n" +
+	"\fmemuMetadata\x18\a \x01(\v2\x1b.WAAICommon.BotMemuMetadataR\fmemuMetadata\x12\x1a\n" +
+	"\btimezone\x18\b \x01(\tR\btimezone\x12K\n" +
+	"\x10reminderMetadata\x18\t \x01(\v2\x1f.WAAICommon.BotReminderMetadataR\x10reminderMetadata\x12B\n" +
+	"\rmodelMetadata\x18\n" +
+	" \x01(\v2\x1c.WAAICommon.BotModelMetadataR\rmodelMetadata\x124\n" +
+	"\x15messageDisclaimerText\x18\v \x01(\tR\x15messageDisclaimerText\x12f\n" +
+	"\x19progressIndicatorMetadata\x18\f \x01(\v2(.WAAICommon.BotProgressIndicatorMetadataR\x19progressIndicatorMetadata\x12Q\n" +
+	"\x12capabilityMetadata\x18\r \x01(\v2!.WAAICommon.BotCapabilityMetadataR\x12capabilityMetadata\x12H\n" +
+	"\x0fimagineMetadata\x18\x0e \x01(\v2\x1e.WAAICommon.BotImagineMetadataR\x0fimagineMetadata\x12E\n" +
+	"\x0ememoryMetadata\x18\x0f \x01(\v2\x1d.WAAICommon.BotMemoryMetadataR\x0ememoryMetadata\x12N\n" +
+	"\x11renderingMetadata\x18\x10 \x01(\v2 .WAAICommon.BotRenderingMetadataR\x11renderingMetadata\x12N\n" +
+	"\x12botMetricsMetadata\x18\x11 \x01(\v2\x1e.WAAICommon.BotMetricsMetadataR\x12botMetricsMetadata\x12c\n" +
+	"\x19botLinkedAccountsMetadata\x18\x12 \x01(\v2%.WAAICommon.BotLinkedAccountsMetadataR\x19botLinkedAccountsMetadata\x12`\n" +
+	"\x1brichResponseSourcesMetadata\x18\x13 \x01(\v2\x1e.WAAICommon.BotSourcesMetadataR\x1brichResponseSourcesMetadata\x124\n" +
+	"\x15aiConversationContext\x18\x14 \x01(\fR\x15aiConversationContext\x12i\n" +
+	"\x1bbotPromotionMessageMetadata\x18\x15 \x01(\v2'.WAAICommon.BotPromotionMessageMetadataR\x1bbotPromotionMessageMetadata\x12`\n" +
+	"\x18botModeSelectionMetadata\x18\x16 \x01(\v2$.WAAICommon.BotModeSelectionMetadataR\x18botModeSelectionMetadata\x12H\n" +
+	"\x10botQuotaMetadata\x18\x17 \x01(\v2\x1c.WAAICommon.BotQuotaMetadataR\x10botQuotaMetadata\x12`\n" +
+	"\x18botAgeCollectionMetadata\x18\x18 \x01(\v2$.WAAICommon.BotAgeCollectionMetadataR\x18botAgeCollectionMetadata\x12@\n" +
+	"\x1bconversationStarterPromptID\x18\x19 \x01(\tR\x1bconversationStarterPromptID\x12$\n" +
+	"\rbotResponseID\x18\x1a \x01(\tR\rbotResponseID\x12`\n" +
+	"\x14verificationMetadata\x18\x1b \x01(\v2,.WAAICommon.BotSignatureVerificationMetadataR\x14verificationMetadata\x12`\n" +
+	"\x17unifiedResponseMutation\x18\x1c \x01(\v2&.WAAICommon.BotUnifiedResponseMutationR\x17unifiedResponseMutation\x12`\n" +
+	"\x18botMessageOriginMetadata\x18\x1d \x01(\v2$.WAAICommon.BotMessageOriginMetadataR\x18botMessageOriginMetadata\x12Z\n" +
+	"\x16inThreadSurveyMetadata\x18\x1e \x01(\v2\".WAAICommon.InThreadSurveyMetadataR\x16inThreadSurveyMetadata\x12>\n" +
+	"\rbotThreadInfo\x18\x1f \x01(\v2\x18.WAAICommon.AIThreadInfoR\rbotThreadInfo\x12P\n" +
+	"\x12regenerateMetadata\x18  \x01(\v2 .WAAICommon.AIRegenerateMetadataR\x12regenerateMetadata\x12i\n" +
+	"\x1bsessionTransparencyMetadata\x18! \x01(\v2'.WAAICommon.SessionTransparencyMetadataR\x1bsessionTransparencyMetadata\x12f\n" +
+	"\x1abotDocumentMessageMetadata\x18\" \x01(\v2&.WAAICommon.BotDocumentMessageMetadataR\x1abotDocumentMessageMetadata\x12+\n" +
+	"\x10internalMetadata\x18\xe7\a \x01(\fR\x10internalMetadata\"o\n" +
+	"\x19ForwardedAIBotMessageInfo\x12\x18\n" +
+	"\abotName\x18\x01 \x01(\tR\abotName\x12\x16\n" +
+	"\x06botJID\x18\x02 \x01(\tR\x06botJID\x12 \n" +
+	"\vcreatorName\x18\x03 \x01(\tR\vcreatorName\"\x8f\x01\n" +
+	"\x15BotMessageSharingInfo\x12R\n" +
+	"\x13botEntryPointOrigin\x18\x01 \x01(\x0e2 .WAAICommon.BotMetricsEntryPointR\x13botEntryPointOrigin\x12\"\n" +
+	"\fforwardScore\x18\x02 \x01(\rR\fforwardScore\"\x8a\x01\n" +
+	"\x16AIRichResponseImageURL\x12(\n" +
+	"\x0fimagePreviewURL\x18\x01 \x01(\tR\x0fimagePreviewURL\x12(\n" +
+	"\x0fimageHighResURL\x18\x02 \x01(\tR\x0fimageHighResURL\x12\x1c\n" +
+	"\tsourceURL\x18\x03 \x01(\tR\tsourceURL\"\xab\x01\n" +
+	"\x1fAIRichResponseGridImageMetadata\x12F\n" +
+	"\fgridImageURL\x18\x01 \x01(\v2\".WAAICommon.AIRichResponseImageURLR\fgridImageURL\x12@\n" +
+	"\timageURLs\x18\x02 \x03(\v2\".WAAICommon.AIRichResponseImageURLR\timageURLs\"\xd5\x01\n" +
+	"\x1bAIRichResponseTableMetadata\x12R\n" +
+	"\x04rows\x18\x01 \x03(\v2>.WAAICommon.AIRichResponseTableMetadata.AIRichResponseTableRowR\x04rows\x12\x14\n" +
+	"\x05title\x18\x02 \x01(\tR\x05title\x1aL\n" +
+	"\x16AIRichResponseTableRow\x12\x14\n" +
+	"\x05items\x18\x01 \x03(\tR\x05items\x12\x1c\n" +
+	"\tisHeading\x18\x02 \x01(\bR\tisHeading\"3\n" +
+	"\x1dAIRichResponseUnifiedResponse\x12\x12\n" +
+	"\x04data\x18\x01 \x01(\fR\x04data\"\x86\x04\n" +
+	"\x1bAIRichResponseLatexMetadata\x12\x12\n" +
+	"\x04text\x18\x01 \x01(\tR\x04text\x12g\n" +
+	"\vexpressions\x18\x02 \x03(\v2E.WAAICommon.AIRichResponseLatexMetadata.AIRichResponseLatexExpressionR\vexpressions\x1a\xe9\x02\n" +
+	"\x1dAIRichResponseLatexExpression\x12(\n" +
+	"\x0flatexExpression\x18\x01 \x01(\tR\x0flatexExpression\x12\x10\n" +
+	"\x03URL\x18\x02 \x01(\tR\x03URL\x12\x14\n" +
+	"\x05width\x18\x03 \x01(\x01R\x05width\x12\x16\n" +
+	"\x06height\x18\x04 \x01(\x01R\x06height\x12\x1e\n" +
+	"\n" +
+	"fontHeight\x18\x05 \x01(\x01R\n" +
+	"fontHeight\x12(\n" +
+	"\x0fimageTopPadding\x18\x06 \x01(\x01R\x0fimageTopPadding\x120\n" +
+	"\x13imageLeadingPadding\x18\a \x01(\x01R\x13imageLeadingPadding\x12.\n" +
+	"\x12imageBottomPadding\x18\b \x01(\x01R\x12imageBottomPadding\x122\n" +
+	"\x14imageTrailingPadding\x18\t \x01(\x01R\x14imageTrailingPadding\"\xf4\x03\n" +
+	"\x19AIRichResponseMapMetadata\x12&\n" +
+	"\x0ecenterLatitude\x18\x01 \x01(\x01R\x0ecenterLatitude\x12(\n" +
+	"\x0fcenterLongitude\x18\x02 \x01(\x01R\x0fcenterLongitude\x12$\n" +
+	"\rlatitudeDelta\x18\x03 \x01(\x01R\rlatitudeDelta\x12&\n" +
+	"\x0elongitudeDelta\x18\x04 \x01(\x01R\x0elongitudeDelta\x12c\n" +
+	"\vannotations\x18\x05 \x03(\v2A.WAAICommon.AIRichResponseMapMetadata.AIRichResponseMapAnnotationR\vannotations\x12\"\n" +
+	"\fshowInfoList\x18\x06 \x01(\bR\fshowInfoList\x1a\xad\x01\n" +
+	"\x1bAIRichResponseMapAnnotation\x12*\n" +
+	"\x10annotationNumber\x18\x01 \x01(\rR\x10annotationNumber\x12\x1a\n" +
+	"\blatitude\x18\x02 \x01(\x01R\blatitude\x12\x1c\n" +
+	"\tlongitude\x18\x03 \x01(\x01R\tlongitude\x12\x14\n" +
+	"\x05title\x18\x04 \x01(\tR\x05title\x12\x12\n" +
+	"\x04body\x18\x05 \x01(\tR\x04body\"\xa4\x06\n" +
+	"\x18AIRichResponseSubMessage\x12J\n" +
+	"\vmessageType\x18\x01 \x01(\x0e2(.WAAICommon.AIRichResponseSubMessageTypeR\vmessageType\x12Y\n" +
+	"\x11gridImageMetadata\x18\x02 \x01(\v2+.WAAICommon.AIRichResponseGridImageMetadataR\x11gridImageMetadata\x12 \n" +
+	"\vmessageText\x18\x03 \x01(\tR\vmessageText\x12S\n" +
+	"\rimageMetadata\x18\x04 \x01(\v2-.WAAICommon.AIRichResponseInlineImageMetadataR\rimageMetadata\x12J\n" +
+	"\fcodeMetadata\x18\x05 \x01(\v2&.WAAICommon.AIRichResponseCodeMetadataR\fcodeMetadata\x12M\n" +
+	"\rtableMetadata\x18\x06 \x01(\v2'.WAAICommon.AIRichResponseTableMetadataR\rtableMetadata\x12S\n" +
+	"\x0fdynamicMetadata\x18\a \x01(\v2).WAAICommon.AIRichResponseDynamicMetadataR\x0fdynamicMetadata\x12M\n" +
+	"\rlatexMetadata\x18\b \x01(\v2'.WAAICommon.AIRichResponseLatexMetadataR\rlatexMetadata\x12G\n" +
+	"\vmapMetadata\x18\t \x01(\v2%.WAAICommon.AIRichResponseMapMetadataR\vmapMetadata\x12b\n" +
+	"\x14contentItemsMetadata\x18\n" +
+	" \x01(\v2..WAAICommon.AIRichResponseContentItemsMetadataR\x14contentItemsMetadata\"~\n" +
+	"\x14AIRegenerateMetadata\x124\n" +
+	"\n" +
+	"messageKey\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\n" +
+	"messageKey\x120\n" +
+	"\x13responseTimestampMS\x18\x02 \x01(\x03R\x13responseTimestampMS\"\xba\x01\n" +
+	"\x1bSessionTransparencyMetadata\x12&\n" +
+	"\x0edisclaimerText\x18\x01 \x01(\tR\x0edisclaimerText\x12\x14\n" +
+	"\x05hcaID\x18\x02 \x01(\tR\x05hcaID\x12]\n" +
+	"\x17sessionTransparencyType\x18\x03 \x01(\x0e2#.WAAICommon.SessionTransparencyTypeR\x17sessionTransparencyType*\xb3\b\n" +
+	"\x14BotMetricsEntryPoint\x12\x19\n" +
+	"\x15UNDEFINED_ENTRY_POINT\x10\x00\x12\v\n" +
+	"\aFAVICON\x10\x01\x12\f\n" +
+	"\bCHATLIST\x10\x02\x12#\n" +
+	"\x1fAISEARCH_NULL_STATE_PAPER_PLANE\x10\x03\x12\"\n" +
+	"\x1eAISEARCH_NULL_STATE_SUGGESTION\x10\x04\x12\"\n" +
+	"\x1eAISEARCH_TYPE_AHEAD_SUGGESTION\x10\x05\x12#\n" +
+	"\x1fAISEARCH_TYPE_AHEAD_PAPER_PLANE\x10\x06\x12'\n" +
+	"#AISEARCH_TYPE_AHEAD_RESULT_CHATLIST\x10\a\x12'\n" +
+	"#AISEARCH_TYPE_AHEAD_RESULT_MESSAGES\x10\b\x12\x16\n" +
+	"\x12AIVOICE_SEARCH_BAR\x10\t\x12\x13\n" +
+	"\x0fAIVOICE_FAVICON\x10\n" +
+	"\x12\f\n" +
+	"\bAISTUDIO\x10\v\x12\f\n" +
+	"\bDEEPLINK\x10\f\x12\x10\n" +
+	"\fNOTIFICATION\x10\r\x12\x1a\n" +
+	"\x16PROFILE_MESSAGE_BUTTON\x10\x0e\x12\v\n" +
+	"\aFORWARD\x10\x0f\x12\x10\n" +
+	"\fAPP_SHORTCUT\x10\x10\x12\r\n" +
+	"\tFF_FAMILY\x10\x11\x12\n" +
+	"\n" +
+	"\x06AI_TAB\x10\x12\x12\v\n" +
+	"\aAI_HOME\x10\x13\x12\x19\n" +
+	"\x15AI_DEEPLINK_IMMERSIVE\x10\x14\x12\x0f\n" +
+	"\vAI_DEEPLINK\x10\x15\x12#\n" +
+	"\x1fMETA_AI_CHAT_SHORTCUT_AI_STUDIO\x10\x16\x12\x1f\n" +
+	"\x1bUGC_CHAT_SHORTCUT_AI_STUDIO\x10\x17\x12\x16\n" +
+	"\x12NEW_CHAT_AI_STUDIO\x10\x18\x12 \n" +
+	"\x1cAIVOICE_FAVICON_CALL_HISTORY\x10\x19\x12\x1c\n" +
+	"\x18ASK_META_AI_CONTEXT_MENU\x10\x1a\x12!\n" +
+	"\x1dASK_META_AI_CONTEXT_MENU_1ON1\x10\x1b\x12\"\n" +
+	"\x1eASK_META_AI_CONTEXT_MENU_GROUP\x10\x1c\x12\x17\n" +
+	"\x13INVOKE_META_AI_1ON1\x10\x1d\x12\x18\n" +
+	"\x14INVOKE_META_AI_GROUP\x10\x1e\x12\x13\n" +
+	"\x0fMETA_AI_FORWARD\x10\x1f\x12\x17\n" +
+	"\x13NEW_CHAT_AI_CONTACT\x10 \x12$\n" +
+	" MESSAGE_QUICK_ACTION_1_ON_1_CHAT\x10!\x12#\n" +
+	"\x1fMESSAGE_QUICK_ACTION_GROUP_CHAT\x10\"\x12\x1f\n" +
+	"\x1bATTACHMENT_TRAY_1_ON_1_CHAT\x10#\x12\x1e\n" +
+	"\x1aATTACHMENT_TRAY_GROUP_CHAT\x10$\x12!\n" +
+	"\x1dASK_META_AI_MEDIA_VIEWER_1ON1\x10%\x12\"\n" +
+	"\x1eASK_META_AI_MEDIA_VIEWER_GROUP\x10&*\xa2\x01\n" +
+	"\x1aBotMetricsThreadEntryPoint\x12\x11\n" +
+	"\rAI_TAB_THREAD\x10\x01\x12\x12\n" +
+	"\x0eAI_HOME_THREAD\x10\x02\x12 \n" +
+	"\x1cAI_DEEPLINK_IMMERSIVE_THREAD\x10\x03\x12\x16\n" +
+	"\x12AI_DEEPLINK_THREAD\x10\x04\x12#\n" +
+	"\x1fASK_META_AI_CONTEXT_MENU_THREAD\x10\x05*}\n" +
+	"\x10BotSessionSource\x12\b\n" +
+	"\x04NONE\x10\x00\x12\x0e\n" +
+	"\n" +
+	"NULL_STATE\x10\x01\x12\r\n" +
+	"\tTYPEAHEAD\x10\x02\x12\x0e\n" +
+	"\n" +
+	"USER_INPUT\x10\x03\x12\r\n" +
+	"\tEMU_FLASH\x10\x04\x12\x16\n" +
+	"\x12EMU_FLASH_FOLLOWUP\x10\x05\x12\t\n" +
+	"\x05VOICE\x10\x06*b\n" +
+	"\x19AIRichResponseMessageType\x12!\n" +
+	"\x1dAI_RICH_RESPONSE_TYPE_UNKNOWN\x10\x00\x12\"\n" +
+	"\x1eAI_RICH_RESPONSE_TYPE_STANDARD\x10\x01*\xca\x02\n" +
+	"\x1cAIRichResponseSubMessageType\x12\x1c\n" +
+	"\x18AI_RICH_RESPONSE_UNKNOWN\x10\x00\x12\x1f\n" +
+	"\x1bAI_RICH_RESPONSE_GRID_IMAGE\x10\x01\x12\x19\n" +
+	"\x15AI_RICH_RESPONSE_TEXT\x10\x02\x12!\n" +
+	"\x1dAI_RICH_RESPONSE_INLINE_IMAGE\x10\x03\x12\x1a\n" +
+	"\x16AI_RICH_RESPONSE_TABLE\x10\x04\x12\x19\n" +
+	"\x15AI_RICH_RESPONSE_CODE\x10\x05\x12\x1c\n" +
+	"\x18AI_RICH_RESPONSE_DYNAMIC\x10\x06\x12\x18\n" +
+	"\x14AI_RICH_RESPONSE_MAP\x10\a\x12\x1a\n" +
+	"\x16AI_RICH_RESPONSE_LATEX\x10\b\x12\"\n" +
+	"\x1eAI_RICH_RESPONSE_CONTENT_ITEMS\x10\t*H\n" +
+	"\x17SessionTransparencyType\x12\x10\n" +
+	"\fUNKNOWN_TYPE\x10\x00\x12\x1b\n" +
+	"\x17NY_AI_SAFETY_DISCLAIMER\x10\x01B&Z$go.mau.fi/whatsmeow/proto/waAICommon"
+
+var (
+	file_waAICommon_WAAICommon_proto_rawDescOnce sync.Once
+	file_waAICommon_WAAICommon_proto_rawDescData []byte
+)
+
+func file_waAICommon_WAAICommon_proto_rawDescGZIP() []byte {
+	file_waAICommon_WAAICommon_proto_rawDescOnce.Do(func() {
+		file_waAICommon_WAAICommon_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_waAICommon_WAAICommon_proto_rawDesc), len(file_waAICommon_WAAICommon_proto_rawDesc)))
+	})
+	return file_waAICommon_WAAICommon_proto_rawDescData
+}
+
+var file_waAICommon_WAAICommon_proto_enumTypes = make([]protoimpl.EnumInfo, 37)
+var file_waAICommon_WAAICommon_proto_msgTypes = make([]protoimpl.MessageInfo, 79)
+var file_waAICommon_WAAICommon_proto_goTypes = []any{
+	(BotMetricsEntryPoint)(0),                                                         // 0: WAAICommon.BotMetricsEntryPoint
+	(BotMetricsThreadEntryPoint)(0),                                                   // 1: WAAICommon.BotMetricsThreadEntryPoint
+	(BotSessionSource)(0),                                                             // 2: WAAICommon.BotSessionSource
+	(AIRichResponseMessageType)(0),                                                    // 3: WAAICommon.AIRichResponseMessageType
+	(AIRichResponseSubMessageType)(0),                                                 // 4: WAAICommon.AIRichResponseSubMessageType
+	(SessionTransparencyType)(0),                                                      // 5: WAAICommon.SessionTransparencyType
+	(BotPluginMetadata_PluginType)(0),                                                 // 6: WAAICommon.BotPluginMetadata.PluginType
+	(BotPluginMetadata_SearchProvider)(0),                                             // 7: WAAICommon.BotPluginMetadata.SearchProvider
+	(BotLinkedAccount_BotLinkedAccountType)(0),                                        // 8: WAAICommon.BotLinkedAccount.BotLinkedAccountType
+	(BotSignatureVerificationUseCaseProof_BotSignatureUseCase)(0),                     // 9: WAAICommon.BotSignatureVerificationUseCaseProof.BotSignatureUseCase
+	(BotPromotionMessageMetadata_BotPromotionType)(0),                                 // 10: WAAICommon.BotPromotionMessageMetadata.BotPromotionType
+	(BotMediaMetadata_OrientationType)(0),                                             // 11: WAAICommon.BotMediaMetadata.OrientationType
+	(BotReminderMetadata_ReminderFrequency)(0),                                        // 12: WAAICommon.BotReminderMetadata.ReminderFrequency
+	(BotReminderMetadata_ReminderAction)(0),                                           // 13: WAAICommon.BotReminderMetadata.ReminderAction
+	(BotModelMetadata_PremiumModelStatus)(0),                                          // 14: WAAICommon.BotModelMetadata.PremiumModelStatus
+	(BotModelMetadata_ModelType)(0),                                                   // 15: WAAICommon.BotModelMetadata.ModelType
+	(BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotSearchSourceProvider)(0), // 16: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotSearchSourceProvider
+	(BotProgressIndicatorMetadata_BotPlanningStepMetadata_PlanningStepStatus)(0),      // 17: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.PlanningStepStatus
+	(BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata_BotPlanningSearchSourceProvider)(0), // 18: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourcesMetadata.BotPlanningSearchSourceProvider
+	(BotCapabilityMetadata_BotCapabilityType)(0),                         // 19: WAAICommon.BotCapabilityMetadata.BotCapabilityType
+	(BotModeSelectionMetadata_BotUserSelectionMode)(0),                   // 20: WAAICommon.BotModeSelectionMetadata.BotUserSelectionMode
+	(BotQuotaMetadata_BotFeatureQuotaMetadata_BotFeatureType)(0),         // 21: WAAICommon.BotQuotaMetadata.BotFeatureQuotaMetadata.BotFeatureType
+	(BotImagineMetadata_ImagineType)(0),                                  // 22: WAAICommon.BotImagineMetadata.ImagineType
+	(BotAgeCollectionMetadata_AgeCollectionType)(0),                      // 23: WAAICommon.BotAgeCollectionMetadata.AgeCollectionType
+	(BotSourcesMetadata_BotSourceItem_SourceProvider)(0),                 // 24: WAAICommon.BotSourcesMetadata.BotSourceItem.SourceProvider
+	(BotMessageOrigin_BotMessageOriginType)(0),                           // 25: WAAICommon.BotMessageOrigin.BotMessageOriginType
+	(AIThreadInfo_AIThreadClientInfo_AIThreadType)(0),                    // 26: WAAICommon.AIThreadInfo.AIThreadClientInfo.AIThreadType
+	(BotFeedbackMessage_ReportKind)(0),                                   // 27: WAAICommon.BotFeedbackMessage.ReportKind
+	(BotFeedbackMessage_BotFeedbackKindMultiplePositive)(0),              // 28: WAAICommon.BotFeedbackMessage.BotFeedbackKindMultiplePositive
+	(BotFeedbackMessage_BotFeedbackKindMultipleNegative)(0),              // 29: WAAICommon.BotFeedbackMessage.BotFeedbackKindMultipleNegative
+	(BotFeedbackMessage_BotFeedbackKind)(0),                              // 30: WAAICommon.BotFeedbackMessage.BotFeedbackKind
+	(AIRichResponseInlineImageMetadata_AIRichResponseImageAlignment)(0),  // 31: WAAICommon.AIRichResponseInlineImageMetadata.AIRichResponseImageAlignment
+	(AIRichResponseCodeMetadata_AIRichResponseCodeHighlightType)(0),      // 32: WAAICommon.AIRichResponseCodeMetadata.AIRichResponseCodeHighlightType
+	(AIRichResponseDynamicMetadata_AIRichResponseDynamicMetadataType)(0), // 33: WAAICommon.AIRichResponseDynamicMetadata.AIRichResponseDynamicMetadataType
+	(AIRichResponseContentItemsMetadata_ContentType)(0),                  // 34: WAAICommon.AIRichResponseContentItemsMetadata.ContentType
+	(BotDocumentMessageMetadata_DocumentPluginType)(0),                   // 35: WAAICommon.BotDocumentMessageMetadata.DocumentPluginType
+	(AIHomeState_AIHomeOption_AIHomeActionType)(0),                       // 36: WAAICommon.AIHomeState.AIHomeOption.AIHomeActionType
+	(*BotPluginMetadata)(nil),                                            // 37: WAAICommon.BotPluginMetadata
+	(*BotLinkedAccount)(nil),                                             // 38: WAAICommon.BotLinkedAccount
+	(*BotSignatureVerificationUseCaseProof)(nil),                         // 39: WAAICommon.BotSignatureVerificationUseCaseProof
+	(*BotPromotionMessageMetadata)(nil),                                  // 40: WAAICommon.BotPromotionMessageMetadata
+	(*BotMediaMetadata)(nil),                                             // 41: WAAICommon.BotMediaMetadata
+	(*BotReminderMetadata)(nil),                                          // 42: WAAICommon.BotReminderMetadata
+	(*BotModelMetadata)(nil),                                             // 43: WAAICommon.BotModelMetadata
+	(*BotProgressIndicatorMetadata)(nil),                                 // 44: WAAICommon.BotProgressIndicatorMetadata
+	(*BotCapabilityMetadata)(nil),                                        // 45: WAAICommon.BotCapabilityMetadata
+	(*BotModeSelectionMetadata)(nil),                                     // 46: WAAICommon.BotModeSelectionMetadata
+	(*BotQuotaMetadata)(nil),                                             // 47: WAAICommon.BotQuotaMetadata
+	(*BotImagineMetadata)(nil),                                           // 48: WAAICommon.BotImagineMetadata
+	(*BotAgeCollectionMetadata)(nil),                                     // 49: WAAICommon.BotAgeCollectionMetadata
+	(*BotSourcesMetadata)(nil),                                           // 50: WAAICommon.BotSourcesMetadata
+	(*BotMessageOrigin)(nil),                                             // 51: WAAICommon.BotMessageOrigin
+	(*AIThreadInfo)(nil),                                                 // 52: WAAICommon.AIThreadInfo
+	(*BotFeedbackMessage)(nil),                                           // 53: WAAICommon.BotFeedbackMessage
+	(*AIRichResponseInlineImageMetadata)(nil),                            // 54: WAAICommon.AIRichResponseInlineImageMetadata
+	(*AIRichResponseCodeMetadata)(nil),                                   // 55: WAAICommon.AIRichResponseCodeMetadata
+	(*AIRichResponseDynamicMetadata)(nil),                                // 56: WAAICommon.AIRichResponseDynamicMetadata
+	(*AIRichResponseContentItemsMetadata)(nil),                           // 57: WAAICommon.AIRichResponseContentItemsMetadata
+	(*BotDocumentMessageMetadata)(nil),                                   // 58: WAAICommon.BotDocumentMessageMetadata
+	(*AIHomeState)(nil),                                                  // 59: WAAICommon.AIHomeState
+	(*BotAvatarMetadata)(nil),                                            // 60: WAAICommon.BotAvatarMetadata
+	(*BotSuggestedPromptMetadata)(nil),                                   // 61: WAAICommon.BotSuggestedPromptMetadata
+	(*BotPromptSuggestions)(nil),                                         // 62: WAAICommon.BotPromptSuggestions
+	(*BotPromptSuggestion)(nil),                                          // 63: WAAICommon.BotPromptSuggestion
+	(*BotLinkedAccountsMetadata)(nil),                                    // 64: WAAICommon.BotLinkedAccountsMetadata
+	(*BotMemoryMetadata)(nil),                                            // 65: WAAICommon.BotMemoryMetadata
+	(*BotMemoryFact)(nil),                                                // 66: WAAICommon.BotMemoryFact
+	(*BotSignatureVerificationMetadata)(nil),                             // 67: WAAICommon.BotSignatureVerificationMetadata
+	(*BotRenderingMetadata)(nil),                                         // 68: WAAICommon.BotRenderingMetadata
+	(*BotMetricsMetadata)(nil),                                           // 69: WAAICommon.BotMetricsMetadata
+	(*BotSessionMetadata)(nil),                                           // 70: WAAICommon.BotSessionMetadata
+	(*BotMemuMetadata)(nil),                                              // 71: WAAICommon.BotMemuMetadata
+	(*InThreadSurveyMetadata)(nil),                                       // 72: WAAICommon.InThreadSurveyMetadata
+	(*BotMessageOriginMetadata)(nil),                                     // 73: WAAICommon.BotMessageOriginMetadata
+	(*BotUnifiedResponseMutation)(nil),                                   // 74: WAAICommon.BotUnifiedResponseMutation
+	(*BotMetadata)(nil),                                                  // 75: WAAICommon.BotMetadata
+	(*ForwardedAIBotMessageInfo)(nil),                                    // 76: WAAICommon.ForwardedAIBotMessageInfo
+	(*BotMessageSharingInfo)(nil),                                        // 77: WAAICommon.BotMessageSharingInfo
+	(*AIRichResponseImageURL)(nil),                                       // 78: WAAICommon.AIRichResponseImageURL
+	(*AIRichResponseGridImageMetadata)(nil),                              // 79: WAAICommon.AIRichResponseGridImageMetadata
+	(*AIRichResponseTableMetadata)(nil),                                  // 80: WAAICommon.AIRichResponseTableMetadata
+	(*AIRichResponseUnifiedResponse)(nil),                                // 81: WAAICommon.AIRichResponseUnifiedResponse
+	(*AIRichResponseLatexMetadata)(nil),                                  // 82: WAAICommon.AIRichResponseLatexMetadata
+	(*AIRichResponseMapMetadata)(nil),                                    // 83: WAAICommon.AIRichResponseMapMetadata
+	(*AIRichResponseSubMessage)(nil),                                     // 84: WAAICommon.AIRichResponseSubMessage
+	(*AIRegenerateMetadata)(nil),                                         // 85: WAAICommon.AIRegenerateMetadata
+	(*SessionTransparencyMetadata)(nil),                                  // 86: WAAICommon.SessionTransparencyMetadata
+	(*BotProgressIndicatorMetadata_BotPlanningStepMetadata)(nil),         // 87: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata
+	(*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourcesMetadata)(nil),                                   // 88: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourcesMetadata
+	(*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningStepSectionMetadata)(nil),                                     // 89: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningStepSectionMetadata
+	(*BotProgressIndicatorMetadata_BotPlanningStepMetadata_BotPlanningSearchSourceMetadata)(nil),                                    // 90: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourceMetadata
+	(*BotQuotaMetadata_BotFeatureQuotaMetadata)(nil),                                                                                // 91: WAAICommon.BotQuotaMetadata.BotFeatureQuotaMetadata
+	(*BotSourcesMetadata_BotSourceItem)(nil),                                                                                        // 92: WAAICommon.BotSourcesMetadata.BotSourceItem
+	(*AIThreadInfo_AIThreadClientInfo)(nil),                                                                                         // 93: WAAICommon.AIThreadInfo.AIThreadClientInfo
+	(*AIThreadInfo_AIThreadServerInfo)(nil),                                                                                         // 94: WAAICommon.AIThreadInfo.AIThreadServerInfo
+	(*BotFeedbackMessage_SideBySideSurveyMetadata)(nil),                                                                             // 95: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata
+	(*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData)(nil),                                         // 96: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData
+	(*BotFeedbackMessage_SideBySideSurveyMetadata_SideBySideSurveyAnalyticsData)(nil),                                               // 97: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SideBySideSurveyAnalyticsData
+	(*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyAbandonEventData)(nil),        // 98: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyAbandonEventData
+	(*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyResponseEventData)(nil),       // 99: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyResponseEventData
+	(*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCardImpressionEventData)(nil), // 100: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCardImpressionEventData
+	(*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAClickEventData)(nil),       // 101: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCTAClickEventData
+	(*BotFeedbackMessage_SideBySideSurveyMetadata_SidebySideSurveyMetaAiAnalyticsData_SideBySideSurveyCTAImpressionEventData)(nil),  // 102: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCTAImpressionEventData
+	(*AIRichResponseCodeMetadata_AIRichResponseCodeBlock)(nil),                                                                      // 103: WAAICommon.AIRichResponseCodeMetadata.AIRichResponseCodeBlock
+	(*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata)(nil),                                                    // 104: WAAICommon.AIRichResponseContentItemsMetadata.AIRichResponseContentItemMetadata
+	(*AIRichResponseContentItemsMetadata_AIRichResponseReelItem)(nil),                                                               // 105: WAAICommon.AIRichResponseContentItemsMetadata.AIRichResponseReelItem
+	(*AIHomeState_AIHomeOption)(nil),                                                                                                // 106: WAAICommon.AIHomeState.AIHomeOption
+	(*BotRenderingMetadata_Keyword)(nil),                                                                                            // 107: WAAICommon.BotRenderingMetadata.Keyword
+	(*InThreadSurveyMetadata_InThreadSurveyPrivacyStatementPart)(nil),                                                               // 108: WAAICommon.InThreadSurveyMetadata.InThreadSurveyPrivacyStatementPart
+	(*InThreadSurveyMetadata_InThreadSurveyOption)(nil),                                                                             // 109: WAAICommon.InThreadSurveyMetadata.InThreadSurveyOption
+	(*InThreadSurveyMetadata_InThreadSurveyQuestion)(nil),                                                                           // 110: WAAICommon.InThreadSurveyMetadata.InThreadSurveyQuestion
+	(*BotUnifiedResponseMutation_MediaDetailsMetadata)(nil),                                                                         // 111: WAAICommon.BotUnifiedResponseMutation.MediaDetailsMetadata
+	(*BotUnifiedResponseMutation_SideBySideMetadata)(nil),                                                                           // 112: WAAICommon.BotUnifiedResponseMutation.SideBySideMetadata
+	(*AIRichResponseTableMetadata_AIRichResponseTableRow)(nil),                                                                      // 113: WAAICommon.AIRichResponseTableMetadata.AIRichResponseTableRow
+	(*AIRichResponseLatexMetadata_AIRichResponseLatexExpression)(nil),                                                               // 114: WAAICommon.AIRichResponseLatexMetadata.AIRichResponseLatexExpression
+	(*AIRichResponseMapMetadata_AIRichResponseMapAnnotation)(nil),                                                                   // 115: WAAICommon.AIRichResponseMapMetadata.AIRichResponseMapAnnotation
+	(*waCommon.MessageKey)(nil),                                                                                                     // 116: WACommon.MessageKey
+}
+var file_waAICommon_WAAICommon_proto_depIdxs = []int32{
+	7,   // 0: WAAICommon.BotPluginMetadata.provider:type_name -> WAAICommon.BotPluginMetadata.SearchProvider
+	6,   // 1: WAAICommon.BotPluginMetadata.pluginType:type_name -> WAAICommon.BotPluginMetadata.PluginType
+	116, // 2: WAAICommon.BotPluginMetadata.parentPluginMessageKey:type_name -> WACommon.MessageKey
+	6,   // 3: WAAICommon.BotPluginMetadata.deprecatedField:type_name -> WAAICommon.BotPluginMetadata.PluginType
+	6,   // 4: WAAICommon.BotPluginMetadata.parentPluginType:type_name -> WAAICommon.BotPluginMetadata.PluginType
+	8,   // 5: WAAICommon.BotLinkedAccount.type:type_name -> WAAICommon.BotLinkedAccount.BotLinkedAccountType
+	9,   // 6: WAAICommon.BotSignatureVerificationUseCaseProof.useCase:type_name -> WAAICommon.BotSignatureVerificationUseCaseProof.BotSignatureUseCase
+	10,  // 7: WAAICommon.BotPromotionMessageMetadata.promotionType:type_name -> WAAICommon.BotPromotionMessageMetadata.BotPromotionType
+	11,  // 8: WAAICommon.BotMediaMetadata.orientationType:type_name -> WAAICommon.BotMediaMetadata.OrientationType
+	116, // 9: WAAICommon.BotReminderMetadata.requestMessageKey:type_name -> WACommon.MessageKey
+	13,  // 10: WAAICommon.BotReminderMetadata.action:type_name -> WAAICommon.BotReminderMetadata.ReminderAction
+	12,  // 11: WAAICommon.BotReminderMetadata.frequency:type_name -> WAAICommon.BotReminderMetadata.ReminderFrequency
+	15,  // 12: WAAICommon.BotModelMetadata.modelType:type_name -> WAAICommon.BotModelMetadata.ModelType
+	14,  // 13: WAAICommon.BotModelMetadata.premiumModelStatus:type_name -> WAAICommon.BotModelMetadata.PremiumModelStatus
+	87,  // 14: WAAICommon.BotProgressIndicatorMetadata.stepsMetadata:type_name -> WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata
+	19,  // 15: WAAICommon.BotCapabilityMetadata.capabilities:type_name -> WAAICommon.BotCapabilityMetadata.BotCapabilityType
+	20,  // 16: WAAICommon.BotModeSelectionMetadata.mode:type_name -> WAAICommon.BotModeSelectionMetadata.BotUserSelectionMode
+	91,  // 17: WAAICommon.BotQuotaMetadata.botFeatureQuotaMetadata:type_name -> WAAICommon.BotQuotaMetadata.BotFeatureQuotaMetadata
+	22,  // 18: WAAICommon.BotImagineMetadata.imagineType:type_name -> WAAICommon.BotImagineMetadata.ImagineType
+	23,  // 19: WAAICommon.BotAgeCollectionMetadata.ageCollectionType:type_name -> WAAICommon.BotAgeCollectionMetadata.AgeCollectionType
+	92,  // 20: WAAICommon.BotSourcesMetadata.sources:type_name -> WAAICommon.BotSourcesMetadata.BotSourceItem
+	25,  // 21: WAAICommon.BotMessageOrigin.type:type_name -> WAAICommon.BotMessageOrigin.BotMessageOriginType
+	94,  // 22: WAAICommon.AIThreadInfo.serverInfo:type_name -> WAAICommon.AIThreadInfo.AIThreadServerInfo
+	93,  // 23: WAAICommon.AIThreadInfo.clientInfo:type_name -> WAAICommon.AIThreadInfo.AIThreadClientInfo
+	116, // 24: WAAICommon.BotFeedbackMessage.messageKey:type_name -> WACommon.MessageKey
+	30,  // 25: WAAICommon.BotFeedbackMessage.kind:type_name -> WAAICommon.BotFeedbackMessage.BotFeedbackKind
+	27,  // 26: WAAICommon.BotFeedbackMessage.kindReport:type_name -> WAAICommon.BotFeedbackMessage.ReportKind
+	95,  // 27: WAAICommon.BotFeedbackMessage.sideBySideSurveyMetadata:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata
+	78,  // 28: WAAICommon.AIRichResponseInlineImageMetadata.imageURL:type_name -> WAAICommon.AIRichResponseImageURL
+	31,  // 29: WAAICommon.AIRichResponseInlineImageMetadata.alignment:type_name -> WAAICommon.AIRichResponseInlineImageMetadata.AIRichResponseImageAlignment
+	103, // 30: WAAICommon.AIRichResponseCodeMetadata.codeBlocks:type_name -> WAAICommon.AIRichResponseCodeMetadata.AIRichResponseCodeBlock
+	33,  // 31: WAAICommon.AIRichResponseDynamicMetadata.type:type_name -> WAAICommon.AIRichResponseDynamicMetadata.AIRichResponseDynamicMetadataType
+	104, // 32: WAAICommon.AIRichResponseContentItemsMetadata.itemsMetadata:type_name -> WAAICommon.AIRichResponseContentItemsMetadata.AIRichResponseContentItemMetadata
+	34,  // 33: WAAICommon.AIRichResponseContentItemsMetadata.contentType:type_name -> WAAICommon.AIRichResponseContentItemsMetadata.ContentType
+	35,  // 34: WAAICommon.BotDocumentMessageMetadata.pluginType:type_name -> WAAICommon.BotDocumentMessageMetadata.DocumentPluginType
+	106, // 35: WAAICommon.AIHomeState.capabilityOptions:type_name -> WAAICommon.AIHomeState.AIHomeOption
+	106, // 36: WAAICommon.AIHomeState.conversationOptions:type_name -> WAAICommon.AIHomeState.AIHomeOption
+	62,  // 37: WAAICommon.BotSuggestedPromptMetadata.promptSuggestions:type_name -> WAAICommon.BotPromptSuggestions
+	63,  // 38: WAAICommon.BotPromptSuggestions.suggestions:type_name -> WAAICommon.BotPromptSuggestion
+	38,  // 39: WAAICommon.BotLinkedAccountsMetadata.accounts:type_name -> WAAICommon.BotLinkedAccount
+	66,  // 40: WAAICommon.BotMemoryMetadata.addedFacts:type_name -> WAAICommon.BotMemoryFact
+	66,  // 41: WAAICommon.BotMemoryMetadata.removedFacts:type_name -> WAAICommon.BotMemoryFact
+	39,  // 42: WAAICommon.BotSignatureVerificationMetadata.proofs:type_name -> WAAICommon.BotSignatureVerificationUseCaseProof
+	107, // 43: WAAICommon.BotRenderingMetadata.keywords:type_name -> WAAICommon.BotRenderingMetadata.Keyword
+	0,   // 44: WAAICommon.BotMetricsMetadata.destinationEntryPoint:type_name -> WAAICommon.BotMetricsEntryPoint
+	1,   // 45: WAAICommon.BotMetricsMetadata.threadOrigin:type_name -> WAAICommon.BotMetricsThreadEntryPoint
+	2,   // 46: WAAICommon.BotSessionMetadata.sessionSource:type_name -> WAAICommon.BotSessionSource
+	41,  // 47: WAAICommon.BotMemuMetadata.faceImages:type_name -> WAAICommon.BotMediaMetadata
+	110, // 48: WAAICommon.InThreadSurveyMetadata.questions:type_name -> WAAICommon.InThreadSurveyMetadata.InThreadSurveyQuestion
+	108, // 49: WAAICommon.InThreadSurveyMetadata.privacyStatementParts:type_name -> WAAICommon.InThreadSurveyMetadata.InThreadSurveyPrivacyStatementPart
+	51,  // 50: WAAICommon.BotMessageOriginMetadata.origins:type_name -> WAAICommon.BotMessageOrigin
+	112, // 51: WAAICommon.BotUnifiedResponseMutation.sbsMetadata:type_name -> WAAICommon.BotUnifiedResponseMutation.SideBySideMetadata
+	111, // 52: WAAICommon.BotUnifiedResponseMutation.mediaDetailsMetadataList:type_name -> WAAICommon.BotUnifiedResponseMutation.MediaDetailsMetadata
+	60,  // 53: WAAICommon.BotMetadata.avatarMetadata:type_name -> WAAICommon.BotAvatarMetadata
+	37,  // 54: WAAICommon.BotMetadata.pluginMetadata:type_name -> WAAICommon.BotPluginMetadata
+	61,  // 55: WAAICommon.BotMetadata.suggestedPromptMetadata:type_name -> WAAICommon.BotSuggestedPromptMetadata
+	70,  // 56: WAAICommon.BotMetadata.sessionMetadata:type_name -> WAAICommon.BotSessionMetadata
+	71,  // 57: WAAICommon.BotMetadata.memuMetadata:type_name -> WAAICommon.BotMemuMetadata
+	42,  // 58: WAAICommon.BotMetadata.reminderMetadata:type_name -> WAAICommon.BotReminderMetadata
+	43,  // 59: WAAICommon.BotMetadata.modelMetadata:type_name -> WAAICommon.BotModelMetadata
+	44,  // 60: WAAICommon.BotMetadata.progressIndicatorMetadata:type_name -> WAAICommon.BotProgressIndicatorMetadata
+	45,  // 61: WAAICommon.BotMetadata.capabilityMetadata:type_name -> WAAICommon.BotCapabilityMetadata
+	48,  // 62: WAAICommon.BotMetadata.imagineMetadata:type_name -> WAAICommon.BotImagineMetadata
+	65,  // 63: WAAICommon.BotMetadata.memoryMetadata:type_name -> WAAICommon.BotMemoryMetadata
+	68,  // 64: WAAICommon.BotMetadata.renderingMetadata:type_name -> WAAICommon.BotRenderingMetadata
+	69,  // 65: WAAICommon.BotMetadata.botMetricsMetadata:type_name -> WAAICommon.BotMetricsMetadata
+	64,  // 66: WAAICommon.BotMetadata.botLinkedAccountsMetadata:type_name -> WAAICommon.BotLinkedAccountsMetadata
+	50,  // 67: WAAICommon.BotMetadata.richResponseSourcesMetadata:type_name -> WAAICommon.BotSourcesMetadata
+	40,  // 68: WAAICommon.BotMetadata.botPromotionMessageMetadata:type_name -> WAAICommon.BotPromotionMessageMetadata
+	46,  // 69: WAAICommon.BotMetadata.botModeSelectionMetadata:type_name -> WAAICommon.BotModeSelectionMetadata
+	47,  // 70: WAAICommon.BotMetadata.botQuotaMetadata:type_name -> WAAICommon.BotQuotaMetadata
+	49,  // 71: WAAICommon.BotMetadata.botAgeCollectionMetadata:type_name -> WAAICommon.BotAgeCollectionMetadata
+	67,  // 72: WAAICommon.BotMetadata.verificationMetadata:type_name -> WAAICommon.BotSignatureVerificationMetadata
+	74,  // 73: WAAICommon.BotMetadata.unifiedResponseMutation:type_name -> WAAICommon.BotUnifiedResponseMutation
+	73,  // 74: WAAICommon.BotMetadata.botMessageOriginMetadata:type_name -> WAAICommon.BotMessageOriginMetadata
+	72,  // 75: WAAICommon.BotMetadata.inThreadSurveyMetadata:type_name -> WAAICommon.InThreadSurveyMetadata
+	52,  // 76: WAAICommon.BotMetadata.botThreadInfo:type_name -> WAAICommon.AIThreadInfo
+	85,  // 77: WAAICommon.BotMetadata.regenerateMetadata:type_name -> WAAICommon.AIRegenerateMetadata
+	86,  // 78: WAAICommon.BotMetadata.sessionTransparencyMetadata:type_name -> WAAICommon.SessionTransparencyMetadata
+	58,  // 79: WAAICommon.BotMetadata.botDocumentMessageMetadata:type_name -> WAAICommon.BotDocumentMessageMetadata
+	0,   // 80: WAAICommon.BotMessageSharingInfo.botEntryPointOrigin:type_name -> WAAICommon.BotMetricsEntryPoint
+	78,  // 81: WAAICommon.AIRichResponseGridImageMetadata.gridImageURL:type_name -> WAAICommon.AIRichResponseImageURL
+	78,  // 82: WAAICommon.AIRichResponseGridImageMetadata.imageURLs:type_name -> WAAICommon.AIRichResponseImageURL
+	113, // 83: WAAICommon.AIRichResponseTableMetadata.rows:type_name -> WAAICommon.AIRichResponseTableMetadata.AIRichResponseTableRow
+	114, // 84: WAAICommon.AIRichResponseLatexMetadata.expressions:type_name -> WAAICommon.AIRichResponseLatexMetadata.AIRichResponseLatexExpression
+	115, // 85: WAAICommon.AIRichResponseMapMetadata.annotations:type_name -> WAAICommon.AIRichResponseMapMetadata.AIRichResponseMapAnnotation
+	4,   // 86: WAAICommon.AIRichResponseSubMessage.messageType:type_name -> WAAICommon.AIRichResponseSubMessageType
+	79,  // 87: WAAICommon.AIRichResponseSubMessage.gridImageMetadata:type_name -> WAAICommon.AIRichResponseGridImageMetadata
+	54,  // 88: WAAICommon.AIRichResponseSubMessage.imageMetadata:type_name -> WAAICommon.AIRichResponseInlineImageMetadata
+	55,  // 89: WAAICommon.AIRichResponseSubMessage.codeMetadata:type_name -> WAAICommon.AIRichResponseCodeMetadata
+	80,  // 90: WAAICommon.AIRichResponseSubMessage.tableMetadata:type_name -> WAAICommon.AIRichResponseTableMetadata
+	56,  // 91: WAAICommon.AIRichResponseSubMessage.dynamicMetadata:type_name -> WAAICommon.AIRichResponseDynamicMetadata
+	82,  // 92: WAAICommon.AIRichResponseSubMessage.latexMetadata:type_name -> WAAICommon.AIRichResponseLatexMetadata
+	83,  // 93: WAAICommon.AIRichResponseSubMessage.mapMetadata:type_name -> WAAICommon.AIRichResponseMapMetadata
+	57,  // 94: WAAICommon.AIRichResponseSubMessage.contentItemsMetadata:type_name -> WAAICommon.AIRichResponseContentItemsMetadata
+	116, // 95: WAAICommon.AIRegenerateMetadata.messageKey:type_name -> WACommon.MessageKey
+	5,   // 96: WAAICommon.SessionTransparencyMetadata.sessionTransparencyType:type_name -> WAAICommon.SessionTransparencyType
+	88,  // 97: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.sourcesMetadata:type_name -> WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourcesMetadata
+	17,  // 98: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.status:type_name -> WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.PlanningStepStatus
+	89,  // 99: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.sections:type_name -> WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningStepSectionMetadata
+	18,  // 100: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourcesMetadata.provider:type_name -> WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourcesMetadata.BotPlanningSearchSourceProvider
+	90,  // 101: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningStepSectionMetadata.sourcesMetadata:type_name -> WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourceMetadata
+	16,  // 102: WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotPlanningSearchSourceMetadata.provider:type_name -> WAAICommon.BotProgressIndicatorMetadata.BotPlanningStepMetadata.BotSearchSourceProvider
+	21,  // 103: WAAICommon.BotQuotaMetadata.BotFeatureQuotaMetadata.featureType:type_name -> WAAICommon.BotQuotaMetadata.BotFeatureQuotaMetadata.BotFeatureType
+	24,  // 104: WAAICommon.BotSourcesMetadata.BotSourceItem.provider:type_name -> WAAICommon.BotSourcesMetadata.BotSourceItem.SourceProvider
+	26,  // 105: WAAICommon.AIThreadInfo.AIThreadClientInfo.type:type_name -> WAAICommon.AIThreadInfo.AIThreadClientInfo.AIThreadType
+	97,  // 106: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.analyticsData:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SideBySideSurveyAnalyticsData
+	96,  // 107: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.metaAiAnalyticsData:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData
+	102, // 108: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.ctaImpressionEvent:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCTAImpressionEventData
+	101, // 109: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.ctaClickEvent:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCTAClickEventData
+	100, // 110: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.cardImpressionEvent:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyCardImpressionEventData
+	99,  // 111: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.responseEvent:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyResponseEventData
+	98,  // 112: WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.abandonEvent:type_name -> WAAICommon.BotFeedbackMessage.SideBySideSurveyMetadata.SidebySideSurveyMetaAiAnalyticsData.SideBySideSurveyAbandonEventData
+	32,  // 113: WAAICommon.AIRichResponseCodeMetadata.AIRichResponseCodeBlock.highlightType:type_name -> WAAICommon.AIRichResponseCodeMetadata.AIRichResponseCodeHighlightType
+	105, // 114: WAAICommon.AIRichResponseContentItemsMetadata.AIRichResponseContentItemMetadata.reelItem:type_name -> WAAICommon.AIRichResponseContentItemsMetadata.AIRichResponseReelItem
+	36,  // 115: WAAICommon.AIHomeState.AIHomeOption.type:type_name -> WAAICommon.AIHomeState.AIHomeOption.AIHomeActionType
+	109, // 116: WAAICommon.InThreadSurveyMetadata.InThreadSurveyQuestion.questionOptions:type_name -> WAAICommon.InThreadSurveyMetadata.InThreadSurveyOption
+	41,  // 117: WAAICommon.BotUnifiedResponseMutation.MediaDetailsMetadata.highResMedia:type_name -> WAAICommon.BotMediaMetadata
+	41,  // 118: WAAICommon.BotUnifiedResponseMutation.MediaDetailsMetadata.previewMedia:type_name -> WAAICommon.BotMediaMetadata
+	119, // [119:119] is the sub-list for method output_type
+	119, // [119:119] is the sub-list for method input_type
+	119, // [119:119] is the sub-list for extension type_name
+	119, // [119:119] is the sub-list for extension extendee
+	0,   // [0:119] is the sub-list for field type_name
+}
+
+func init() { file_waAICommon_WAAICommon_proto_init() }
+func file_waAICommon_WAAICommon_proto_init() {
+	if File_waAICommon_WAAICommon_proto != nil {
+		return
+	}
+	file_waAICommon_WAAICommon_proto_msgTypes[67].OneofWrappers = []any{
+		(*AIRichResponseContentItemsMetadata_AIRichResponseContentItemMetadata_ReelItem)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_waAICommon_WAAICommon_proto_rawDesc), len(file_waAICommon_WAAICommon_proto_rawDesc)),
+			NumEnums:      37,
+			NumMessages:   79,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_waAICommon_WAAICommon_proto_goTypes,
+		DependencyIndexes: file_waAICommon_WAAICommon_proto_depIdxs,
+		EnumInfos:         file_waAICommon_WAAICommon_proto_enumTypes,
+		MessageInfos:      file_waAICommon_WAAICommon_proto_msgTypes,
+	}.Build()
+	File_waAICommon_WAAICommon_proto = out.File
+	file_waAICommon_WAAICommon_proto_goTypes = nil
+	file_waAICommon_WAAICommon_proto_depIdxs = nil
+}

+ 871 - 0
proto/waAICommon/WAAICommon.proto

@@ -0,0 +1,871 @@
+syntax = "proto2";
+package WAAICommon;
+option go_package = "go.mau.fi/whatsmeow/proto/waAICommon";
+
+import "waCommon/WACommon.proto";
+
+enum BotMetricsEntryPoint {
+	UNDEFINED_ENTRY_POINT = 0;
+	FAVICON = 1;
+	CHATLIST = 2;
+	AISEARCH_NULL_STATE_PAPER_PLANE = 3;
+	AISEARCH_NULL_STATE_SUGGESTION = 4;
+	AISEARCH_TYPE_AHEAD_SUGGESTION = 5;
+	AISEARCH_TYPE_AHEAD_PAPER_PLANE = 6;
+	AISEARCH_TYPE_AHEAD_RESULT_CHATLIST = 7;
+	AISEARCH_TYPE_AHEAD_RESULT_MESSAGES = 8;
+	AIVOICE_SEARCH_BAR = 9;
+	AIVOICE_FAVICON = 10;
+	AISTUDIO = 11;
+	DEEPLINK = 12;
+	NOTIFICATION = 13;
+	PROFILE_MESSAGE_BUTTON = 14;
+	FORWARD = 15;
+	APP_SHORTCUT = 16;
+	FF_FAMILY = 17;
+	AI_TAB = 18;
+	AI_HOME = 19;
+	AI_DEEPLINK_IMMERSIVE = 20;
+	AI_DEEPLINK = 21;
+	META_AI_CHAT_SHORTCUT_AI_STUDIO = 22;
+	UGC_CHAT_SHORTCUT_AI_STUDIO = 23;
+	NEW_CHAT_AI_STUDIO = 24;
+	AIVOICE_FAVICON_CALL_HISTORY = 25;
+	ASK_META_AI_CONTEXT_MENU = 26;
+	ASK_META_AI_CONTEXT_MENU_1ON1 = 27;
+	ASK_META_AI_CONTEXT_MENU_GROUP = 28;
+	INVOKE_META_AI_1ON1 = 29;
+	INVOKE_META_AI_GROUP = 30;
+	META_AI_FORWARD = 31;
+	NEW_CHAT_AI_CONTACT = 32;
+	MESSAGE_QUICK_ACTION_1_ON_1_CHAT = 33;
+	MESSAGE_QUICK_ACTION_GROUP_CHAT = 34;
+	ATTACHMENT_TRAY_1_ON_1_CHAT = 35;
+	ATTACHMENT_TRAY_GROUP_CHAT = 36;
+	ASK_META_AI_MEDIA_VIEWER_1ON1 = 37;
+	ASK_META_AI_MEDIA_VIEWER_GROUP = 38;
+}
+
+enum BotMetricsThreadEntryPoint {
+	AI_TAB_THREAD = 1;
+	AI_HOME_THREAD = 2;
+	AI_DEEPLINK_IMMERSIVE_THREAD = 3;
+	AI_DEEPLINK_THREAD = 4;
+	ASK_META_AI_CONTEXT_MENU_THREAD = 5;
+}
+
+enum BotSessionSource {
+	NONE = 0;
+	NULL_STATE = 1;
+	TYPEAHEAD = 2;
+	USER_INPUT = 3;
+	EMU_FLASH = 4;
+	EMU_FLASH_FOLLOWUP = 5;
+	VOICE = 6;
+}
+
+enum AIRichResponseMessageType {
+	AI_RICH_RESPONSE_TYPE_UNKNOWN = 0;
+	AI_RICH_RESPONSE_TYPE_STANDARD = 1;
+}
+
+enum AIRichResponseSubMessageType {
+	AI_RICH_RESPONSE_UNKNOWN = 0;
+	AI_RICH_RESPONSE_GRID_IMAGE = 1;
+	AI_RICH_RESPONSE_TEXT = 2;
+	AI_RICH_RESPONSE_INLINE_IMAGE = 3;
+	AI_RICH_RESPONSE_TABLE = 4;
+	AI_RICH_RESPONSE_CODE = 5;
+	AI_RICH_RESPONSE_DYNAMIC = 6;
+	AI_RICH_RESPONSE_MAP = 7;
+	AI_RICH_RESPONSE_LATEX = 8;
+	AI_RICH_RESPONSE_CONTENT_ITEMS = 9;
+}
+
+enum SessionTransparencyType {
+	UNKNOWN_TYPE = 0;
+	NY_AI_SAFETY_DISCLAIMER = 1;
+}
+
+message BotPluginMetadata {
+	enum PluginType {
+		UNKNOWN_PLUGIN = 0;
+		REELS = 1;
+		SEARCH = 2;
+	}
+
+	enum SearchProvider {
+		UNKNOWN = 0;
+		BING = 1;
+		GOOGLE = 2;
+		SUPPORT = 3;
+	}
+
+	optional SearchProvider provider = 1;
+	optional PluginType pluginType = 2;
+	optional string thumbnailCDNURL = 3;
+	optional string profilePhotoCDNURL = 4;
+	optional string searchProviderURL = 5;
+	optional uint32 referenceIndex = 6;
+	optional uint32 expectedLinksCount = 7;
+	optional string searchQuery = 9;
+	optional WACommon.MessageKey parentPluginMessageKey = 10;
+	optional PluginType deprecatedField = 11;
+	optional PluginType parentPluginType = 12;
+	optional string faviconCDNURL = 13;
+}
+
+message BotLinkedAccount {
+	enum BotLinkedAccountType {
+		BOT_LINKED_ACCOUNT_TYPE_1P = 0;
+	}
+
+	optional BotLinkedAccountType type = 1;
+}
+
+message BotSignatureVerificationUseCaseProof {
+	enum BotSignatureUseCase {
+		UNSPECIFIED = 0;
+		WA_BOT_MSG = 1;
+	}
+
+	optional int32 version = 1;
+	optional BotSignatureUseCase useCase = 2;
+	optional bytes signature = 3;
+	repeated bytes certificateChain = 4;
+}
+
+message BotPromotionMessageMetadata {
+	enum BotPromotionType {
+		UNKNOWN_TYPE = 0;
+		C50 = 1;
+		SURVEY_PLATFORM = 2;
+	}
+
+	optional BotPromotionType promotionType = 1;
+	optional string buttonTitle = 2;
+}
+
+message BotMediaMetadata {
+	enum OrientationType {
+		CENTER = 1;
+		LEFT = 2;
+		RIGHT = 3;
+	}
+
+	optional string fileSHA256 = 1;
+	optional string mediaKey = 2;
+	optional string fileEncSHA256 = 3;
+	optional string directPath = 4;
+	optional int64 mediaKeyTimestamp = 5;
+	optional string mimetype = 6;
+	optional OrientationType orientationType = 7;
+}
+
+message BotReminderMetadata {
+	enum ReminderFrequency {
+		ONCE = 1;
+		DAILY = 2;
+		WEEKLY = 3;
+		BIWEEKLY = 4;
+		MONTHLY = 5;
+	}
+
+	enum ReminderAction {
+		NOTIFY = 1;
+		CREATE = 2;
+		DELETE = 3;
+		UPDATE = 4;
+	}
+
+	optional WACommon.MessageKey requestMessageKey = 1;
+	optional ReminderAction action = 2;
+	optional string name = 3;
+	optional uint64 nextTriggerTimestamp = 4;
+	optional ReminderFrequency frequency = 5;
+}
+
+message BotModelMetadata {
+	enum PremiumModelStatus {
+		UNKNOWN_STATUS = 0;
+		AVAILABLE = 1;
+		QUOTA_EXCEED_LIMIT = 2;
+	}
+
+	enum ModelType {
+		UNKNOWN_TYPE = 0;
+		LLAMA_PROD = 1;
+		LLAMA_PROD_PREMIUM = 2;
+	}
+
+	optional ModelType modelType = 1;
+	optional PremiumModelStatus premiumModelStatus = 2;
+	optional string modelNameOverride = 3;
+}
+
+message BotProgressIndicatorMetadata {
+	message BotPlanningStepMetadata {
+		enum BotSearchSourceProvider {
+			UNKNOWN_PROVIDER = 0;
+			OTHER = 1;
+			GOOGLE = 2;
+			BING = 3;
+		}
+
+		enum PlanningStepStatus {
+			UNKNOWN = 0;
+			PLANNED = 1;
+			EXECUTING = 2;
+			FINISHED = 3;
+		}
+
+		message BotPlanningSearchSourcesMetadata {
+			enum BotPlanningSearchSourceProvider {
+				UNKNOWN = 0;
+				OTHER = 1;
+				GOOGLE = 2;
+				BING = 3;
+			}
+
+			optional string sourceTitle = 1;
+			optional BotPlanningSearchSourceProvider provider = 2;
+			optional string sourceURL = 3;
+		}
+
+		message BotPlanningStepSectionMetadata {
+			optional string sectionTitle = 1;
+			optional string sectionBody = 2;
+			repeated BotPlanningSearchSourceMetadata sourcesMetadata = 3;
+		}
+
+		message BotPlanningSearchSourceMetadata {
+			optional string title = 1;
+			optional BotSearchSourceProvider provider = 2;
+			optional string sourceURL = 3;
+			optional string favIconURL = 4;
+		}
+
+		optional string statusTitle = 1;
+		optional string statusBody = 2;
+		repeated BotPlanningSearchSourcesMetadata sourcesMetadata = 3;
+		optional PlanningStepStatus status = 4;
+		optional bool isReasoning = 5;
+		optional bool isEnhancedSearch = 6;
+		repeated BotPlanningStepSectionMetadata sections = 7;
+	}
+
+	optional string progressDescription = 1;
+	repeated BotPlanningStepMetadata stepsMetadata = 2;
+}
+
+message BotCapabilityMetadata {
+	enum BotCapabilityType {
+		UNKNOWN = 0;
+		PROGRESS_INDICATOR = 1;
+		RICH_RESPONSE_HEADING = 2;
+		RICH_RESPONSE_NESTED_LIST = 3;
+		AI_MEMORY = 4;
+		RICH_RESPONSE_THREAD_SURFING = 5;
+		RICH_RESPONSE_TABLE = 6;
+		RICH_RESPONSE_CODE = 7;
+		RICH_RESPONSE_STRUCTURED_RESPONSE = 8;
+		RICH_RESPONSE_INLINE_IMAGE = 9;
+		WA_IG_1P_PLUGIN_RANKING_CONTROL = 10;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_1 = 11;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_2 = 12;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_3 = 13;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_4 = 14;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_5 = 15;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_6 = 16;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_7 = 17;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_8 = 18;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_9 = 19;
+		WA_IG_1P_PLUGIN_RANKING_UPDATE_10 = 20;
+		RICH_RESPONSE_SUB_HEADING = 21;
+		RICH_RESPONSE_GRID_IMAGE = 22;
+		AI_STUDIO_UGC_MEMORY = 23;
+		RICH_RESPONSE_LATEX = 24;
+		RICH_RESPONSE_MAPS = 25;
+		RICH_RESPONSE_INLINE_REELS = 26;
+		AGENTIC_PLANNING = 27;
+		ACCOUNT_LINKING = 28;
+		STREAMING_DISAGGREGATION = 29;
+		RICH_RESPONSE_GRID_IMAGE_3P = 30;
+		RICH_RESPONSE_LATEX_INLINE = 31;
+		QUERY_PLAN = 32;
+		PROACTIVE_MESSAGE = 33;
+		RICH_RESPONSE_UNIFIED_RESPONSE = 34;
+		PROMOTION_MESSAGE = 35;
+		SIMPLIFIED_PROFILE_PAGE = 36;
+		RICH_RESPONSE_SOURCES_IN_MESSAGE = 37;
+		RICH_RESPONSE_SIDE_BY_SIDE_SURVEY = 38;
+		RICH_RESPONSE_UNIFIED_TEXT_COMPONENT = 39;
+		AI_SHARED_MEMORY = 40;
+		RICH_RESPONSE_UNIFIED_SOURCES = 41;
+		RICH_RESPONSE_UNIFIED_DOMAIN_CITATIONS = 42;
+		RICH_RESPONSE_UR_INLINE_REELS_ENABLED = 43;
+		RICH_RESPONSE_UR_MEDIA_GRID_ENABLED = 44;
+		RICH_RESPONSE_UR_TIMESTAMP_PLACEHOLDER = 45;
+		RICH_RESPONSE_IN_APP_SURVEY = 46;
+		AI_RESPONSE_MODEL_BRANDING = 47;
+		SESSION_TRANSPARENCY_SYSTEM_MESSAGE = 48;
+		RICH_RESPONSE_UR_REASONING = 49;
+	}
+
+	repeated BotCapabilityType capabilities = 1;
+}
+
+message BotModeSelectionMetadata {
+	enum BotUserSelectionMode {
+		UNKNOWN_MODE = 0;
+		REASONING_MODE = 1;
+	}
+
+	repeated BotUserSelectionMode mode = 1;
+}
+
+message BotQuotaMetadata {
+	message BotFeatureQuotaMetadata {
+		enum BotFeatureType {
+			UNKNOWN_FEATURE = 0;
+			REASONING_FEATURE = 1;
+		}
+
+		optional BotFeatureType featureType = 1;
+		optional uint32 remainingQuota = 2;
+		optional uint64 expirationTimestamp = 3;
+	}
+
+	repeated BotFeatureQuotaMetadata botFeatureQuotaMetadata = 1;
+}
+
+message BotImagineMetadata {
+	enum ImagineType {
+		UNKNOWN = 0;
+		IMAGINE = 1;
+		MEMU = 2;
+		FLASH = 3;
+		EDIT = 4;
+	}
+
+	optional ImagineType imagineType = 1;
+}
+
+message BotAgeCollectionMetadata {
+	enum AgeCollectionType {
+		O18_BINARY = 0;
+		WAFFLE = 1;
+	}
+
+	optional bool ageCollectionEligible = 1;
+	optional bool shouldTriggerAgeCollectionOnClient = 2;
+	optional AgeCollectionType ageCollectionType = 3;
+}
+
+message BotSourcesMetadata {
+	message BotSourceItem {
+		enum SourceProvider {
+			UNKNOWN = 0;
+			BING = 1;
+			GOOGLE = 2;
+			SUPPORT = 3;
+			OTHER = 4;
+		}
+
+		optional SourceProvider provider = 1;
+		optional string thumbnailCDNURL = 2;
+		optional string sourceProviderURL = 3;
+		optional string sourceQuery = 4;
+		optional string faviconCDNURL = 5;
+		optional uint32 citationNumber = 6;
+		optional string sourceTitle = 7;
+	}
+
+	repeated BotSourceItem sources = 1;
+}
+
+message BotMessageOrigin {
+	enum BotMessageOriginType {
+		BOT_MESSAGE_ORIGIN_TYPE_AI_INITIATED = 0;
+	}
+
+	optional BotMessageOriginType type = 1;
+}
+
+message AIThreadInfo {
+	message AIThreadClientInfo {
+		enum AIThreadType {
+			UNKNOWN = 0;
+			DEFAULT = 1;
+			INCOGNITO = 2;
+		}
+
+		optional AIThreadType type = 1;
+	}
+
+	message AIThreadServerInfo {
+		optional string title = 1;
+	}
+
+	optional AIThreadServerInfo serverInfo = 1;
+	optional AIThreadClientInfo clientInfo = 2;
+}
+
+message BotFeedbackMessage {
+	enum ReportKind {
+		NONE = 0;
+		GENERIC = 1;
+	}
+
+	enum BotFeedbackKindMultiplePositive {
+		BOT_FEEDBACK_MULTIPLE_POSITIVE_GENERIC = 1;
+	}
+
+	enum BotFeedbackKindMultipleNegative {
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_GENERIC = 1;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_HELPFUL = 2;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_INTERESTING = 4;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_ACCURATE = 8;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_SAFE = 16;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_OTHER = 32;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_REFUSED = 64;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_VISUALLY_APPEALING = 128;
+		BOT_FEEDBACK_MULTIPLE_NEGATIVE_NOT_RELEVANT_TO_TEXT = 256;
+	}
+
+	enum BotFeedbackKind {
+		BOT_FEEDBACK_POSITIVE = 0;
+		BOT_FEEDBACK_NEGATIVE_GENERIC = 1;
+		BOT_FEEDBACK_NEGATIVE_HELPFUL = 2;
+		BOT_FEEDBACK_NEGATIVE_INTERESTING = 3;
+		BOT_FEEDBACK_NEGATIVE_ACCURATE = 4;
+		BOT_FEEDBACK_NEGATIVE_SAFE = 5;
+		BOT_FEEDBACK_NEGATIVE_OTHER = 6;
+		BOT_FEEDBACK_NEGATIVE_REFUSED = 7;
+		BOT_FEEDBACK_NEGATIVE_NOT_VISUALLY_APPEALING = 8;
+		BOT_FEEDBACK_NEGATIVE_NOT_RELEVANT_TO_TEXT = 9;
+		BOT_FEEDBACK_NEGATIVE_PERSONALIZED = 10;
+		BOT_FEEDBACK_NEGATIVE_CLARITY = 11;
+		BOT_FEEDBACK_NEGATIVE_DOESNT_LOOK_LIKE_THE_PERSON = 12;
+		BOT_FEEDBACK_NEGATIVE_HALLUCINATION_INTERNAL_ONLY = 13;
+		BOT_FEEDBACK_NEGATIVE = 14;
+	}
+
+	message SideBySideSurveyMetadata {
+		message SidebySideSurveyMetaAiAnalyticsData {
+			message SideBySideSurveyAbandonEventData {
+				optional string abandonDwellTimeMSString = 1;
+			}
+
+			message SideBySideSurveyResponseEventData {
+				optional string responseDwellTimeMSString = 1;
+				optional string selectedResponseID = 2;
+			}
+
+			message SideBySideSurveyCardImpressionEventData {
+			}
+
+			message SideBySideSurveyCTAClickEventData {
+				optional bool isSurveyExpired = 1;
+				optional string clickDwellTimeMSString = 2;
+			}
+
+			message SideBySideSurveyCTAImpressionEventData {
+				optional bool isSurveyExpired = 1;
+			}
+
+			optional uint32 surveyID = 1;
+			optional string primaryResponseID = 2;
+			optional string testArmName = 3;
+			optional string timestampMSString = 4;
+			optional SideBySideSurveyCTAImpressionEventData ctaImpressionEvent = 5;
+			optional SideBySideSurveyCTAClickEventData ctaClickEvent = 6;
+			optional SideBySideSurveyCardImpressionEventData cardImpressionEvent = 7;
+			optional SideBySideSurveyResponseEventData responseEvent = 8;
+			optional SideBySideSurveyAbandonEventData abandonEvent = 9;
+		}
+
+		message SideBySideSurveyAnalyticsData {
+			optional string tessaEvent = 1;
+			optional string tessaSessionFbid = 2;
+			optional string simonSessionFbid = 3;
+		}
+
+		optional string selectedRequestID = 1;
+		optional uint32 surveyID = 2;
+		optional string simonSessionFbid = 3;
+		optional string responseOtid = 4;
+		optional string responseTimestampMSString = 5;
+		optional bool isSelectedResponsePrimary = 6;
+		optional string messageIDToEdit = 7;
+		optional SideBySideSurveyAnalyticsData analyticsData = 8;
+		optional SidebySideSurveyMetaAiAnalyticsData metaAiAnalyticsData = 9;
+	}
+
+	optional WACommon.MessageKey messageKey = 1;
+	optional BotFeedbackKind kind = 2;
+	optional string text = 3;
+	optional uint64 kindNegative = 4;
+	optional uint64 kindPositive = 5;
+	optional ReportKind kindReport = 6;
+	optional SideBySideSurveyMetadata sideBySideSurveyMetadata = 7;
+}
+
+message AIRichResponseInlineImageMetadata {
+	enum AIRichResponseImageAlignment {
+		AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED = 0;
+		AI_RICH_RESPONSE_IMAGE_LAYOUT_TRAILING_ALIGNED = 1;
+		AI_RICH_RESPONSE_IMAGE_LAYOUT_CENTER_ALIGNED = 2;
+	}
+
+	optional AIRichResponseImageURL imageURL = 1;
+	optional string imageText = 2;
+	optional AIRichResponseImageAlignment alignment = 3;
+	optional string tapLinkURL = 4;
+}
+
+message AIRichResponseCodeMetadata {
+	enum AIRichResponseCodeHighlightType {
+		AI_RICH_RESPONSE_CODE_HIGHLIGHT_DEFAULT = 0;
+		AI_RICH_RESPONSE_CODE_HIGHLIGHT_KEYWORD = 1;
+		AI_RICH_RESPONSE_CODE_HIGHLIGHT_METHOD = 2;
+		AI_RICH_RESPONSE_CODE_HIGHLIGHT_STRING = 3;
+		AI_RICH_RESPONSE_CODE_HIGHLIGHT_NUMBER = 4;
+		AI_RICH_RESPONSE_CODE_HIGHLIGHT_COMMENT = 5;
+	}
+
+	message AIRichResponseCodeBlock {
+		optional AIRichResponseCodeHighlightType highlightType = 1;
+		optional string codeContent = 2;
+	}
+
+	optional string codeLanguage = 1;
+	repeated AIRichResponseCodeBlock codeBlocks = 2;
+}
+
+message AIRichResponseDynamicMetadata {
+	enum AIRichResponseDynamicMetadataType {
+		AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_UNKNOWN = 0;
+		AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_IMAGE = 1;
+		AI_RICH_RESPONSE_DYNAMIC_METADATA_TYPE_GIF = 2;
+	}
+
+	optional AIRichResponseDynamicMetadataType type = 1;
+	optional uint64 version = 2;
+	optional string URL = 3;
+	optional uint32 loopCount = 4;
+}
+
+message AIRichResponseContentItemsMetadata {
+	enum ContentType {
+		DEFAULT = 0;
+		CAROUSEL = 1;
+	}
+
+	message AIRichResponseContentItemMetadata {
+		oneof aIRichResponseContentItem {
+			AIRichResponseReelItem reelItem = 1;
+		}
+	}
+
+	message AIRichResponseReelItem {
+		optional string title = 1;
+		optional string profileIconURL = 2;
+		optional string thumbnailURL = 3;
+		optional string videoURL = 4;
+	}
+
+	repeated AIRichResponseContentItemMetadata itemsMetadata = 1;
+	optional ContentType contentType = 2;
+}
+
+message BotDocumentMessageMetadata {
+	enum DocumentPluginType {
+		TEXT_EXTRACTION = 0;
+		OCR_AND_IMAGES = 1;
+	}
+
+	optional DocumentPluginType pluginType = 1;
+}
+
+message AIHomeState {
+	message AIHomeOption {
+		enum AIHomeActionType {
+			PROMPT = 0;
+			CREATE_IMAGE = 1;
+			ANIMATE_PHOTO = 2;
+			ANALYZE_FILE = 3;
+		}
+
+		optional AIHomeActionType type = 1;
+		optional string title = 2;
+		optional string promptText = 3;
+		optional string sessionID = 4;
+		optional string imageWdsIdentifier = 5;
+		optional string imageTintColor = 6;
+		optional string imageBackgroundColor = 7;
+	}
+
+	optional int64 lastFetchTime = 1;
+	repeated AIHomeOption capabilityOptions = 2;
+	repeated AIHomeOption conversationOptions = 3;
+}
+
+message BotAvatarMetadata {
+	optional uint32 sentiment = 1;
+	optional string behaviorGraph = 2;
+	optional uint32 action = 3;
+	optional uint32 intensity = 4;
+	optional uint32 wordCount = 5;
+}
+
+message BotSuggestedPromptMetadata {
+	repeated string suggestedPrompts = 1;
+	optional uint32 selectedPromptIndex = 2;
+	optional BotPromptSuggestions promptSuggestions = 3;
+	optional string selectedPromptID = 4;
+}
+
+message BotPromptSuggestions {
+	repeated BotPromptSuggestion suggestions = 1;
+}
+
+message BotPromptSuggestion {
+	optional string prompt = 1;
+	optional string promptID = 2;
+}
+
+message BotLinkedAccountsMetadata {
+	repeated BotLinkedAccount accounts = 1;
+	optional bytes acAuthTokens = 2;
+	optional int32 acErrorCode = 3;
+}
+
+message BotMemoryMetadata {
+	repeated BotMemoryFact addedFacts = 1;
+	repeated BotMemoryFact removedFacts = 2;
+	optional string disclaimer = 3;
+}
+
+message BotMemoryFact {
+	optional string fact = 1;
+	optional string factID = 2;
+}
+
+message BotSignatureVerificationMetadata {
+	repeated BotSignatureVerificationUseCaseProof proofs = 1;
+}
+
+message BotRenderingMetadata {
+	message Keyword {
+		optional string value = 1;
+		repeated string associatedPrompts = 2;
+	}
+
+	repeated Keyword keywords = 1;
+}
+
+message BotMetricsMetadata {
+	optional string destinationID = 1;
+	optional BotMetricsEntryPoint destinationEntryPoint = 2;
+	optional BotMetricsThreadEntryPoint threadOrigin = 3;
+}
+
+message BotSessionMetadata {
+	optional string sessionID = 1;
+	optional BotSessionSource sessionSource = 2;
+}
+
+message BotMemuMetadata {
+	repeated BotMediaMetadata faceImages = 1;
+}
+
+message InThreadSurveyMetadata {
+	message InThreadSurveyPrivacyStatementPart {
+		optional string text = 1;
+		optional string URL = 2;
+	}
+
+	message InThreadSurveyOption {
+		optional string stringValue = 1;
+		optional uint32 numericValue = 2;
+		optional string textTranslated = 3;
+	}
+
+	message InThreadSurveyQuestion {
+		optional string questionText = 1;
+		optional string questionID = 2;
+		repeated InThreadSurveyOption questionOptions = 3;
+	}
+
+	optional string tessaSessionID = 1;
+	optional string simonSessionID = 2;
+	optional string simonSurveyID = 3;
+	optional string tessaRootID = 4;
+	optional string requestID = 5;
+	optional string tessaEvent = 6;
+	optional string invitationHeaderText = 7;
+	optional string invitationBodyText = 8;
+	optional string invitationCtaText = 9;
+	optional string invitationCtaURL = 10;
+	optional string surveyTitle = 11;
+	repeated InThreadSurveyQuestion questions = 12;
+	optional string surveyContinueButtonText = 13;
+	optional string surveySubmitButtonText = 14;
+	optional string privacyStatementFull = 15;
+	repeated InThreadSurveyPrivacyStatementPart privacyStatementParts = 16;
+	optional string feedbackToastText = 17;
+	optional int32 startQuestionIndex = 18;
+}
+
+message BotMessageOriginMetadata {
+	repeated BotMessageOrigin origins = 1;
+}
+
+message BotUnifiedResponseMutation {
+	message MediaDetailsMetadata {
+		optional string ID = 1;
+		optional BotMediaMetadata highResMedia = 2;
+		optional BotMediaMetadata previewMedia = 3;
+	}
+
+	message SideBySideMetadata {
+		optional string primaryResponseID = 1;
+		optional bool surveyCtaHasRendered = 2;
+	}
+
+	optional SideBySideMetadata sbsMetadata = 1;
+	repeated MediaDetailsMetadata mediaDetailsMetadataList = 2;
+}
+
+message BotMetadata {
+	optional BotAvatarMetadata avatarMetadata = 1;
+	optional string personaID = 2;
+	optional BotPluginMetadata pluginMetadata = 3;
+	optional BotSuggestedPromptMetadata suggestedPromptMetadata = 4;
+	optional string invokerJID = 5;
+	optional BotSessionMetadata sessionMetadata = 6;
+	optional BotMemuMetadata memuMetadata = 7;
+	optional string timezone = 8;
+	optional BotReminderMetadata reminderMetadata = 9;
+	optional BotModelMetadata modelMetadata = 10;
+	optional string messageDisclaimerText = 11;
+	optional BotProgressIndicatorMetadata progressIndicatorMetadata = 12;
+	optional BotCapabilityMetadata capabilityMetadata = 13;
+	optional BotImagineMetadata imagineMetadata = 14;
+	optional BotMemoryMetadata memoryMetadata = 15;
+	optional BotRenderingMetadata renderingMetadata = 16;
+	optional BotMetricsMetadata botMetricsMetadata = 17;
+	optional BotLinkedAccountsMetadata botLinkedAccountsMetadata = 18;
+	optional BotSourcesMetadata richResponseSourcesMetadata = 19;
+	optional bytes aiConversationContext = 20;
+	optional BotPromotionMessageMetadata botPromotionMessageMetadata = 21;
+	optional BotModeSelectionMetadata botModeSelectionMetadata = 22;
+	optional BotQuotaMetadata botQuotaMetadata = 23;
+	optional BotAgeCollectionMetadata botAgeCollectionMetadata = 24;
+	optional string conversationStarterPromptID = 25;
+	optional string botResponseID = 26;
+	optional BotSignatureVerificationMetadata verificationMetadata = 27;
+	optional BotUnifiedResponseMutation unifiedResponseMutation = 28;
+	optional BotMessageOriginMetadata botMessageOriginMetadata = 29;
+	optional InThreadSurveyMetadata inThreadSurveyMetadata = 30;
+	optional AIThreadInfo botThreadInfo = 31;
+	optional AIRegenerateMetadata regenerateMetadata = 32;
+	optional SessionTransparencyMetadata sessionTransparencyMetadata = 33;
+	optional BotDocumentMessageMetadata botDocumentMessageMetadata = 34;
+	optional bytes internalMetadata = 999;
+}
+
+message ForwardedAIBotMessageInfo {
+	optional string botName = 1;
+	optional string botJID = 2;
+	optional string creatorName = 3;
+}
+
+message BotMessageSharingInfo {
+	optional BotMetricsEntryPoint botEntryPointOrigin = 1;
+	optional uint32 forwardScore = 2;
+}
+
+message AIRichResponseImageURL {
+	optional string imagePreviewURL = 1;
+	optional string imageHighResURL = 2;
+	optional string sourceURL = 3;
+}
+
+message AIRichResponseGridImageMetadata {
+	optional AIRichResponseImageURL gridImageURL = 1;
+	repeated AIRichResponseImageURL imageURLs = 2;
+}
+
+message AIRichResponseTableMetadata {
+	message AIRichResponseTableRow {
+		repeated string items = 1;
+		optional bool isHeading = 2;
+	}
+
+	repeated AIRichResponseTableRow rows = 1;
+	optional string title = 2;
+}
+
+message AIRichResponseUnifiedResponse {
+	optional bytes data = 1;
+}
+
+message AIRichResponseLatexMetadata {
+	message AIRichResponseLatexExpression {
+		optional string latexExpression = 1;
+		optional string URL = 2;
+		optional double width = 3;
+		optional double height = 4;
+		optional double fontHeight = 5;
+		optional double imageTopPadding = 6;
+		optional double imageLeadingPadding = 7;
+		optional double imageBottomPadding = 8;
+		optional double imageTrailingPadding = 9;
+	}
+
+	optional string text = 1;
+	repeated AIRichResponseLatexExpression expressions = 2;
+}
+
+message AIRichResponseMapMetadata {
+	message AIRichResponseMapAnnotation {
+		optional uint32 annotationNumber = 1;
+		optional double latitude = 2;
+		optional double longitude = 3;
+		optional string title = 4;
+		optional string body = 5;
+	}
+
+	optional double centerLatitude = 1;
+	optional double centerLongitude = 2;
+	optional double latitudeDelta = 3;
+	optional double longitudeDelta = 4;
+	repeated AIRichResponseMapAnnotation annotations = 5;
+	optional bool showInfoList = 6;
+}
+
+message AIRichResponseSubMessage {
+	optional AIRichResponseSubMessageType messageType = 1;
+	optional AIRichResponseGridImageMetadata gridImageMetadata = 2;
+	optional string messageText = 3;
+	optional AIRichResponseInlineImageMetadata imageMetadata = 4;
+	optional AIRichResponseCodeMetadata codeMetadata = 5;
+	optional AIRichResponseTableMetadata tableMetadata = 6;
+	optional AIRichResponseDynamicMetadata dynamicMetadata = 7;
+	optional AIRichResponseLatexMetadata latexMetadata = 8;
+	optional AIRichResponseMapMetadata mapMetadata = 9;
+	optional AIRichResponseContentItemsMetadata contentItemsMetadata = 10;
+}
+
+message AIRegenerateMetadata {
+	optional WACommon.MessageKey messageKey = 1;
+	optional int64 responseTimestampMS = 2;
+}
+
+message SessionTransparencyMetadata {
+	optional string disclaimerText = 1;
+	optional string hcaID = 2;
+	optional SessionTransparencyType sessionTransparencyType = 3;
+}

+ 515 - 0
proto/waAdv/WAAdv.pb.go

@@ -0,0 +1,515 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: waAdv/WAAdv.proto
+
+package waAdv
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ADVEncryptionType int32
+
+const (
+	ADVEncryptionType_E2EE   ADVEncryptionType = 0
+	ADVEncryptionType_HOSTED ADVEncryptionType = 1
+)
+
+// Enum value maps for ADVEncryptionType.
+var (
+	ADVEncryptionType_name = map[int32]string{
+		0: "E2EE",
+		1: "HOSTED",
+	}
+	ADVEncryptionType_value = map[string]int32{
+		"E2EE":   0,
+		"HOSTED": 1,
+	}
+)
+
+func (x ADVEncryptionType) Enum() *ADVEncryptionType {
+	p := new(ADVEncryptionType)
+	*p = x
+	return p
+}
+
+func (x ADVEncryptionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (ADVEncryptionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waAdv_WAAdv_proto_enumTypes[0].Descriptor()
+}
+
+func (ADVEncryptionType) Type() protoreflect.EnumType {
+	return &file_waAdv_WAAdv_proto_enumTypes[0]
+}
+
+func (x ADVEncryptionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *ADVEncryptionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = ADVEncryptionType(num)
+	return nil
+}
+
+// Deprecated: Use ADVEncryptionType.Descriptor instead.
+func (ADVEncryptionType) EnumDescriptor() ([]byte, []int) {
+	return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{0}
+}
+
+type ADVKeyIndexList struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	RawID         *uint32                `protobuf:"varint,1,opt,name=rawID" json:"rawID,omitempty"`
+	Timestamp     *uint64                `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"`
+	CurrentIndex  *uint32                `protobuf:"varint,3,opt,name=currentIndex" json:"currentIndex,omitempty"`
+	ValidIndexes  []uint32               `protobuf:"varint,4,rep,packed,name=validIndexes" json:"validIndexes,omitempty"`
+	AccountType   *ADVEncryptionType     `protobuf:"varint,5,opt,name=accountType,enum=WAAdv.ADVEncryptionType" json:"accountType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ADVKeyIndexList) Reset() {
+	*x = ADVKeyIndexList{}
+	mi := &file_waAdv_WAAdv_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ADVKeyIndexList) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ADVKeyIndexList) ProtoMessage() {}
+
+func (x *ADVKeyIndexList) ProtoReflect() protoreflect.Message {
+	mi := &file_waAdv_WAAdv_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ADVKeyIndexList.ProtoReflect.Descriptor instead.
+func (*ADVKeyIndexList) Descriptor() ([]byte, []int) {
+	return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ADVKeyIndexList) GetRawID() uint32 {
+	if x != nil && x.RawID != nil {
+		return *x.RawID
+	}
+	return 0
+}
+
+func (x *ADVKeyIndexList) GetTimestamp() uint64 {
+	if x != nil && x.Timestamp != nil {
+		return *x.Timestamp
+	}
+	return 0
+}
+
+func (x *ADVKeyIndexList) GetCurrentIndex() uint32 {
+	if x != nil && x.CurrentIndex != nil {
+		return *x.CurrentIndex
+	}
+	return 0
+}
+
+func (x *ADVKeyIndexList) GetValidIndexes() []uint32 {
+	if x != nil {
+		return x.ValidIndexes
+	}
+	return nil
+}
+
+func (x *ADVKeyIndexList) GetAccountType() ADVEncryptionType {
+	if x != nil && x.AccountType != nil {
+		return *x.AccountType
+	}
+	return ADVEncryptionType_E2EE
+}
+
+type ADVSignedKeyIndexList struct {
+	state               protoimpl.MessageState `protogen:"open.v1"`
+	Details             []byte                 `protobuf:"bytes,1,opt,name=details" json:"details,omitempty"`
+	AccountSignature    []byte                 `protobuf:"bytes,2,opt,name=accountSignature" json:"accountSignature,omitempty"`
+	AccountSignatureKey []byte                 `protobuf:"bytes,3,opt,name=accountSignatureKey" json:"accountSignatureKey,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *ADVSignedKeyIndexList) Reset() {
+	*x = ADVSignedKeyIndexList{}
+	mi := &file_waAdv_WAAdv_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ADVSignedKeyIndexList) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ADVSignedKeyIndexList) ProtoMessage() {}
+
+func (x *ADVSignedKeyIndexList) ProtoReflect() protoreflect.Message {
+	mi := &file_waAdv_WAAdv_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ADVSignedKeyIndexList.ProtoReflect.Descriptor instead.
+func (*ADVSignedKeyIndexList) Descriptor() ([]byte, []int) {
+	return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ADVSignedKeyIndexList) GetDetails() []byte {
+	if x != nil {
+		return x.Details
+	}
+	return nil
+}
+
+func (x *ADVSignedKeyIndexList) GetAccountSignature() []byte {
+	if x != nil {
+		return x.AccountSignature
+	}
+	return nil
+}
+
+func (x *ADVSignedKeyIndexList) GetAccountSignatureKey() []byte {
+	if x != nil {
+		return x.AccountSignatureKey
+	}
+	return nil
+}
+
+type ADVDeviceIdentity struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	RawID         *uint32                `protobuf:"varint,1,opt,name=rawID" json:"rawID,omitempty"`
+	Timestamp     *uint64                `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"`
+	KeyIndex      *uint32                `protobuf:"varint,3,opt,name=keyIndex" json:"keyIndex,omitempty"`
+	AccountType   *ADVEncryptionType     `protobuf:"varint,4,opt,name=accountType,enum=WAAdv.ADVEncryptionType" json:"accountType,omitempty"`
+	DeviceType    *ADVEncryptionType     `protobuf:"varint,5,opt,name=deviceType,enum=WAAdv.ADVEncryptionType" json:"deviceType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ADVDeviceIdentity) Reset() {
+	*x = ADVDeviceIdentity{}
+	mi := &file_waAdv_WAAdv_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ADVDeviceIdentity) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ADVDeviceIdentity) ProtoMessage() {}
+
+func (x *ADVDeviceIdentity) ProtoReflect() protoreflect.Message {
+	mi := &file_waAdv_WAAdv_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ADVDeviceIdentity.ProtoReflect.Descriptor instead.
+func (*ADVDeviceIdentity) Descriptor() ([]byte, []int) {
+	return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ADVDeviceIdentity) GetRawID() uint32 {
+	if x != nil && x.RawID != nil {
+		return *x.RawID
+	}
+	return 0
+}
+
+func (x *ADVDeviceIdentity) GetTimestamp() uint64 {
+	if x != nil && x.Timestamp != nil {
+		return *x.Timestamp
+	}
+	return 0
+}
+
+func (x *ADVDeviceIdentity) GetKeyIndex() uint32 {
+	if x != nil && x.KeyIndex != nil {
+		return *x.KeyIndex
+	}
+	return 0
+}
+
+func (x *ADVDeviceIdentity) GetAccountType() ADVEncryptionType {
+	if x != nil && x.AccountType != nil {
+		return *x.AccountType
+	}
+	return ADVEncryptionType_E2EE
+}
+
+func (x *ADVDeviceIdentity) GetDeviceType() ADVEncryptionType {
+	if x != nil && x.DeviceType != nil {
+		return *x.DeviceType
+	}
+	return ADVEncryptionType_E2EE
+}
+
+type ADVSignedDeviceIdentity struct {
+	state               protoimpl.MessageState `protogen:"open.v1"`
+	Details             []byte                 `protobuf:"bytes,1,opt,name=details" json:"details,omitempty"`
+	AccountSignatureKey []byte                 `protobuf:"bytes,2,opt,name=accountSignatureKey" json:"accountSignatureKey,omitempty"`
+	AccountSignature    []byte                 `protobuf:"bytes,3,opt,name=accountSignature" json:"accountSignature,omitempty"`
+	DeviceSignature     []byte                 `protobuf:"bytes,4,opt,name=deviceSignature" json:"deviceSignature,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *ADVSignedDeviceIdentity) Reset() {
+	*x = ADVSignedDeviceIdentity{}
+	mi := &file_waAdv_WAAdv_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ADVSignedDeviceIdentity) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ADVSignedDeviceIdentity) ProtoMessage() {}
+
+func (x *ADVSignedDeviceIdentity) ProtoReflect() protoreflect.Message {
+	mi := &file_waAdv_WAAdv_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ADVSignedDeviceIdentity.ProtoReflect.Descriptor instead.
+func (*ADVSignedDeviceIdentity) Descriptor() ([]byte, []int) {
+	return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ADVSignedDeviceIdentity) GetDetails() []byte {
+	if x != nil {
+		return x.Details
+	}
+	return nil
+}
+
+func (x *ADVSignedDeviceIdentity) GetAccountSignatureKey() []byte {
+	if x != nil {
+		return x.AccountSignatureKey
+	}
+	return nil
+}
+
+func (x *ADVSignedDeviceIdentity) GetAccountSignature() []byte {
+	if x != nil {
+		return x.AccountSignature
+	}
+	return nil
+}
+
+func (x *ADVSignedDeviceIdentity) GetDeviceSignature() []byte {
+	if x != nil {
+		return x.DeviceSignature
+	}
+	return nil
+}
+
+type ADVSignedDeviceIdentityHMAC struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Details       []byte                 `protobuf:"bytes,1,opt,name=details" json:"details,omitempty"`
+	HMAC          []byte                 `protobuf:"bytes,2,opt,name=HMAC" json:"HMAC,omitempty"`
+	AccountType   *ADVEncryptionType     `protobuf:"varint,3,opt,name=accountType,enum=WAAdv.ADVEncryptionType" json:"accountType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ADVSignedDeviceIdentityHMAC) Reset() {
+	*x = ADVSignedDeviceIdentityHMAC{}
+	mi := &file_waAdv_WAAdv_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ADVSignedDeviceIdentityHMAC) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ADVSignedDeviceIdentityHMAC) ProtoMessage() {}
+
+func (x *ADVSignedDeviceIdentityHMAC) ProtoReflect() protoreflect.Message {
+	mi := &file_waAdv_WAAdv_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ADVSignedDeviceIdentityHMAC.ProtoReflect.Descriptor instead.
+func (*ADVSignedDeviceIdentityHMAC) Descriptor() ([]byte, []int) {
+	return file_waAdv_WAAdv_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ADVSignedDeviceIdentityHMAC) GetDetails() []byte {
+	if x != nil {
+		return x.Details
+	}
+	return nil
+}
+
+func (x *ADVSignedDeviceIdentityHMAC) GetHMAC() []byte {
+	if x != nil {
+		return x.HMAC
+	}
+	return nil
+}
+
+func (x *ADVSignedDeviceIdentityHMAC) GetAccountType() ADVEncryptionType {
+	if x != nil && x.AccountType != nil {
+		return *x.AccountType
+	}
+	return ADVEncryptionType_E2EE
+}
+
+var File_waAdv_WAAdv_proto protoreflect.FileDescriptor
+
+const file_waAdv_WAAdv_proto_rawDesc = "" +
+	"\n" +
+	"\x11waAdv/WAAdv.proto\x12\x05WAAdv\"\xcd\x01\n" +
+	"\x0fADVKeyIndexList\x12\x14\n" +
+	"\x05rawID\x18\x01 \x01(\rR\x05rawID\x12\x1c\n" +
+	"\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12\"\n" +
+	"\fcurrentIndex\x18\x03 \x01(\rR\fcurrentIndex\x12&\n" +
+	"\fvalidIndexes\x18\x04 \x03(\rB\x02\x10\x01R\fvalidIndexes\x12:\n" +
+	"\vaccountType\x18\x05 \x01(\x0e2\x18.WAAdv.ADVEncryptionTypeR\vaccountType\"\x8f\x01\n" +
+	"\x15ADVSignedKeyIndexList\x12\x18\n" +
+	"\adetails\x18\x01 \x01(\fR\adetails\x12*\n" +
+	"\x10accountSignature\x18\x02 \x01(\fR\x10accountSignature\x120\n" +
+	"\x13accountSignatureKey\x18\x03 \x01(\fR\x13accountSignatureKey\"\xd9\x01\n" +
+	"\x11ADVDeviceIdentity\x12\x14\n" +
+	"\x05rawID\x18\x01 \x01(\rR\x05rawID\x12\x1c\n" +
+	"\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\x12\x1a\n" +
+	"\bkeyIndex\x18\x03 \x01(\rR\bkeyIndex\x12:\n" +
+	"\vaccountType\x18\x04 \x01(\x0e2\x18.WAAdv.ADVEncryptionTypeR\vaccountType\x128\n" +
+	"\n" +
+	"deviceType\x18\x05 \x01(\x0e2\x18.WAAdv.ADVEncryptionTypeR\n" +
+	"deviceType\"\xbb\x01\n" +
+	"\x17ADVSignedDeviceIdentity\x12\x18\n" +
+	"\adetails\x18\x01 \x01(\fR\adetails\x120\n" +
+	"\x13accountSignatureKey\x18\x02 \x01(\fR\x13accountSignatureKey\x12*\n" +
+	"\x10accountSignature\x18\x03 \x01(\fR\x10accountSignature\x12(\n" +
+	"\x0fdeviceSignature\x18\x04 \x01(\fR\x0fdeviceSignature\"\x87\x01\n" +
+	"\x1bADVSignedDeviceIdentityHMAC\x12\x18\n" +
+	"\adetails\x18\x01 \x01(\fR\adetails\x12\x12\n" +
+	"\x04HMAC\x18\x02 \x01(\fR\x04HMAC\x12:\n" +
+	"\vaccountType\x18\x03 \x01(\x0e2\x18.WAAdv.ADVEncryptionTypeR\vaccountType*)\n" +
+	"\x11ADVEncryptionType\x12\b\n" +
+	"\x04E2EE\x10\x00\x12\n" +
+	"\n" +
+	"\x06HOSTED\x10\x01B!Z\x1fgo.mau.fi/whatsmeow/proto/waAdv"
+
+var (
+	file_waAdv_WAAdv_proto_rawDescOnce sync.Once
+	file_waAdv_WAAdv_proto_rawDescData []byte
+)
+
+func file_waAdv_WAAdv_proto_rawDescGZIP() []byte {
+	file_waAdv_WAAdv_proto_rawDescOnce.Do(func() {
+		file_waAdv_WAAdv_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_waAdv_WAAdv_proto_rawDesc), len(file_waAdv_WAAdv_proto_rawDesc)))
+	})
+	return file_waAdv_WAAdv_proto_rawDescData
+}
+
+var file_waAdv_WAAdv_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_waAdv_WAAdv_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_waAdv_WAAdv_proto_goTypes = []any{
+	(ADVEncryptionType)(0),              // 0: WAAdv.ADVEncryptionType
+	(*ADVKeyIndexList)(nil),             // 1: WAAdv.ADVKeyIndexList
+	(*ADVSignedKeyIndexList)(nil),       // 2: WAAdv.ADVSignedKeyIndexList
+	(*ADVDeviceIdentity)(nil),           // 3: WAAdv.ADVDeviceIdentity
+	(*ADVSignedDeviceIdentity)(nil),     // 4: WAAdv.ADVSignedDeviceIdentity
+	(*ADVSignedDeviceIdentityHMAC)(nil), // 5: WAAdv.ADVSignedDeviceIdentityHMAC
+}
+var file_waAdv_WAAdv_proto_depIdxs = []int32{
+	0, // 0: WAAdv.ADVKeyIndexList.accountType:type_name -> WAAdv.ADVEncryptionType
+	0, // 1: WAAdv.ADVDeviceIdentity.accountType:type_name -> WAAdv.ADVEncryptionType
+	0, // 2: WAAdv.ADVDeviceIdentity.deviceType:type_name -> WAAdv.ADVEncryptionType
+	0, // 3: WAAdv.ADVSignedDeviceIdentityHMAC.accountType:type_name -> WAAdv.ADVEncryptionType
+	4, // [4:4] is the sub-list for method output_type
+	4, // [4:4] is the sub-list for method input_type
+	4, // [4:4] is the sub-list for extension type_name
+	4, // [4:4] is the sub-list for extension extendee
+	0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_waAdv_WAAdv_proto_init() }
+func file_waAdv_WAAdv_proto_init() {
+	if File_waAdv_WAAdv_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_waAdv_WAAdv_proto_rawDesc), len(file_waAdv_WAAdv_proto_rawDesc)),
+			NumEnums:      1,
+			NumMessages:   5,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_waAdv_WAAdv_proto_goTypes,
+		DependencyIndexes: file_waAdv_WAAdv_proto_depIdxs,
+		EnumInfos:         file_waAdv_WAAdv_proto_enumTypes,
+		MessageInfos:      file_waAdv_WAAdv_proto_msgTypes,
+	}.Build()
+	File_waAdv_WAAdv_proto = out.File
+	file_waAdv_WAAdv_proto_goTypes = nil
+	file_waAdv_WAAdv_proto_depIdxs = nil
+}

+ 43 - 0
proto/waAdv/WAAdv.proto

@@ -0,0 +1,43 @@
+syntax = "proto2";
+package WAAdv;
+option go_package = "go.mau.fi/whatsmeow/proto/waAdv";
+
+enum ADVEncryptionType {
+	E2EE = 0;
+	HOSTED = 1;
+}
+
+message ADVKeyIndexList {
+	optional uint32 rawID = 1;
+	optional uint64 timestamp = 2;
+	optional uint32 currentIndex = 3;
+	repeated uint32 validIndexes = 4 [packed=true];
+	optional ADVEncryptionType accountType = 5;
+}
+
+message ADVSignedKeyIndexList {
+	optional bytes details = 1;
+	optional bytes accountSignature = 2;
+	optional bytes accountSignatureKey = 3;
+}
+
+message ADVDeviceIdentity {
+	optional uint32 rawID = 1;
+	optional uint64 timestamp = 2;
+	optional uint32 keyIndex = 3;
+	optional ADVEncryptionType accountType = 4;
+	optional ADVEncryptionType deviceType = 5;
+}
+
+message ADVSignedDeviceIdentity {
+	optional bytes details = 1;
+	optional bytes accountSignatureKey = 2;
+	optional bytes accountSignature = 3;
+	optional bytes deviceSignature = 4;
+}
+
+message ADVSignedDeviceIdentityHMAC {
+	optional bytes details = 1;
+	optional bytes HMAC = 2;
+	optional ADVEncryptionType accountType = 3;
+}

+ 3285 - 0
proto/waArmadilloApplication/WAArmadilloApplication.pb.go

@@ -0,0 +1,3285 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: waArmadilloApplication/WAArmadilloApplication.proto
+
+package waArmadilloApplication
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	waArmadilloXMA "go.mau.fi/whatsmeow/proto/waArmadilloXMA"
+	waCommon "go.mau.fi/whatsmeow/proto/waCommon"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus int32
+
+const (
+	Armadillo_Signal_EncryptedBackupsSecrets_Epoch_ES_OPEN  Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus = 1
+	Armadillo_Signal_EncryptedBackupsSecrets_Epoch_ES_CLOSE Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus = 2
+)
+
+// Enum value maps for Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus.
+var (
+	Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus_name = map[int32]string{
+		1: "ES_OPEN",
+		2: "ES_CLOSE",
+	}
+	Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus_value = map[string]int32{
+		"ES_OPEN":  1,
+		"ES_CLOSE": 2,
+	}
+)
+
+func (x Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus) Enum() *Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus {
+	p := new(Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus)
+	*p = x
+	return p
+}
+
+func (x Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[0].Descriptor()
+}
+
+func (Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[0]
+}
+
+func (x Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus.Descriptor instead.
+func (Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 3, 0, 0, 0}
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType int32
+
+const (
+	Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_UNKNOWN  Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType = 0
+	Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_NUDE     Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType = 1
+	Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_NOT_NUDE Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType = 2
+)
+
+// Enum value maps for Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType.
+var (
+	Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType_name = map[int32]string{
+		0: "UNKNOWN",
+		1: "NUDE",
+		2: "NOT_NUDE",
+	}
+	Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType_value = map[string]int32{
+		"UNKNOWN":  0,
+		"NUDE":     1,
+		"NOT_NUDE": 2,
+	}
+)
+
+func (x Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType) Enum() *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType {
+	p := new(Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType)
+	*p = x
+	return p
+}
+
+func (x Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[1].Descriptor()
+}
+
+func (Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[1]
+}
+
+func (x Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType.Descriptor instead.
+func (Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 0, 0}
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType int32
+
+const (
+	Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_TAKEDOWN Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType = 0
+	Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_RESTORE  Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType = 1
+)
+
+// Enum value maps for Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType.
+var (
+	Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType_name = map[int32]string{
+		0: "TAKEDOWN",
+		1: "RESTORE",
+	}
+	Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType_value = map[string]int32{
+		"TAKEDOWN": 0,
+		"RESTORE":  1,
+	}
+)
+
+func (x Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType) Enum() *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType {
+	p := new(Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType)
+	*p = x
+	return p
+}
+
+func (x Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[2].Descriptor()
+}
+
+func (Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[2]
+}
+
+func (x Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType.Descriptor instead.
+func (Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 1, 0}
+}
+
+type Armadillo_Content_PaymentsTransactionMessage_PaymentStatus int32
+
+const (
+	Armadillo_Content_PaymentsTransactionMessage_PAYMENT_UNKNOWN                                         Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 0
+	Armadillo_Content_PaymentsTransactionMessage_REQUEST_INITED                                          Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 4
+	Armadillo_Content_PaymentsTransactionMessage_REQUEST_DECLINED                                        Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 5
+	Armadillo_Content_PaymentsTransactionMessage_REQUEST_TRANSFER_INITED                                 Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 6
+	Armadillo_Content_PaymentsTransactionMessage_REQUEST_TRANSFER_COMPLETED                              Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 7
+	Armadillo_Content_PaymentsTransactionMessage_REQUEST_TRANSFER_FAILED                                 Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 8
+	Armadillo_Content_PaymentsTransactionMessage_REQUEST_CANCELED                                        Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 9
+	Armadillo_Content_PaymentsTransactionMessage_REQUEST_EXPIRED                                         Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 10
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_INITED                                         Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 11
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_PENDING                                        Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 12
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_PENDING_RECIPIENT_VERIFICATION                 Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 13
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_CANCELED                                       Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 14
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_COMPLETED                                      Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 15
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_CANCELED Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 16
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_OTHER    Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 17
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_REFUNDED                                       Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 18
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_PARTIAL_REFUND                                 Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 19
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_CHARGED_BACK                                   Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 20
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_EXPIRED                                        Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 21
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_DECLINED                                       Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 22
+	Armadillo_Content_PaymentsTransactionMessage_TRANSFER_UNAVAILABLE                                    Armadillo_Content_PaymentsTransactionMessage_PaymentStatus = 23
+)
+
+// Enum value maps for Armadillo_Content_PaymentsTransactionMessage_PaymentStatus.
+var (
+	Armadillo_Content_PaymentsTransactionMessage_PaymentStatus_name = map[int32]string{
+		0:  "PAYMENT_UNKNOWN",
+		4:  "REQUEST_INITED",
+		5:  "REQUEST_DECLINED",
+		6:  "REQUEST_TRANSFER_INITED",
+		7:  "REQUEST_TRANSFER_COMPLETED",
+		8:  "REQUEST_TRANSFER_FAILED",
+		9:  "REQUEST_CANCELED",
+		10: "REQUEST_EXPIRED",
+		11: "TRANSFER_INITED",
+		12: "TRANSFER_PENDING",
+		13: "TRANSFER_PENDING_RECIPIENT_VERIFICATION",
+		14: "TRANSFER_CANCELED",
+		15: "TRANSFER_COMPLETED",
+		16: "TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_CANCELED",
+		17: "TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_OTHER",
+		18: "TRANSFER_REFUNDED",
+		19: "TRANSFER_PARTIAL_REFUND",
+		20: "TRANSFER_CHARGED_BACK",
+		21: "TRANSFER_EXPIRED",
+		22: "TRANSFER_DECLINED",
+		23: "TRANSFER_UNAVAILABLE",
+	}
+	Armadillo_Content_PaymentsTransactionMessage_PaymentStatus_value = map[string]int32{
+		"PAYMENT_UNKNOWN":                         0,
+		"REQUEST_INITED":                          4,
+		"REQUEST_DECLINED":                        5,
+		"REQUEST_TRANSFER_INITED":                 6,
+		"REQUEST_TRANSFER_COMPLETED":              7,
+		"REQUEST_TRANSFER_FAILED":                 8,
+		"REQUEST_CANCELED":                        9,
+		"REQUEST_EXPIRED":                         10,
+		"TRANSFER_INITED":                         11,
+		"TRANSFER_PENDING":                        12,
+		"TRANSFER_PENDING_RECIPIENT_VERIFICATION": 13,
+		"TRANSFER_CANCELED":                       14,
+		"TRANSFER_COMPLETED":                      15,
+		"TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_CANCELED": 16,
+		"TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_OTHER":    17,
+		"TRANSFER_REFUNDED":       18,
+		"TRANSFER_PARTIAL_REFUND": 19,
+		"TRANSFER_CHARGED_BACK":   20,
+		"TRANSFER_EXPIRED":        21,
+		"TRANSFER_DECLINED":       22,
+		"TRANSFER_UNAVAILABLE":    23,
+	}
+)
+
+func (x Armadillo_Content_PaymentsTransactionMessage_PaymentStatus) Enum() *Armadillo_Content_PaymentsTransactionMessage_PaymentStatus {
+	p := new(Armadillo_Content_PaymentsTransactionMessage_PaymentStatus)
+	*p = x
+	return p
+}
+
+func (x Armadillo_Content_PaymentsTransactionMessage_PaymentStatus) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_Content_PaymentsTransactionMessage_PaymentStatus) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[3].Descriptor()
+}
+
+func (Armadillo_Content_PaymentsTransactionMessage_PaymentStatus) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[3]
+}
+
+func (x Armadillo_Content_PaymentsTransactionMessage_PaymentStatus) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_Content_PaymentsTransactionMessage_PaymentStatus) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_Content_PaymentsTransactionMessage_PaymentStatus(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_Content_PaymentsTransactionMessage_PaymentStatus.Descriptor instead.
+func (Armadillo_Content_PaymentsTransactionMessage_PaymentStatus) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 0, 0}
+}
+
+type Armadillo_Content_ScreenshotAction_ScreenshotType int32
+
+const (
+	Armadillo_Content_ScreenshotAction_SCREENSHOT_IMAGE Armadillo_Content_ScreenshotAction_ScreenshotType = 1
+	Armadillo_Content_ScreenshotAction_SCREEN_RECORDING Armadillo_Content_ScreenshotAction_ScreenshotType = 2
+)
+
+// Enum value maps for Armadillo_Content_ScreenshotAction_ScreenshotType.
+var (
+	Armadillo_Content_ScreenshotAction_ScreenshotType_name = map[int32]string{
+		1: "SCREENSHOT_IMAGE",
+		2: "SCREEN_RECORDING",
+	}
+	Armadillo_Content_ScreenshotAction_ScreenshotType_value = map[string]int32{
+		"SCREENSHOT_IMAGE": 1,
+		"SCREEN_RECORDING": 2,
+	}
+)
+
+func (x Armadillo_Content_ScreenshotAction_ScreenshotType) Enum() *Armadillo_Content_ScreenshotAction_ScreenshotType {
+	p := new(Armadillo_Content_ScreenshotAction_ScreenshotType)
+	*p = x
+	return p
+}
+
+func (x Armadillo_Content_ScreenshotAction_ScreenshotType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_Content_ScreenshotAction_ScreenshotType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[4].Descriptor()
+}
+
+func (Armadillo_Content_ScreenshotAction_ScreenshotType) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[4]
+}
+
+func (x Armadillo_Content_ScreenshotAction_ScreenshotType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_Content_ScreenshotAction_ScreenshotType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_Content_ScreenshotAction_ScreenshotType(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_Content_ScreenshotAction_ScreenshotType.Descriptor instead.
+func (Armadillo_Content_ScreenshotAction_ScreenshotType) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 5, 0}
+}
+
+type Armadillo_Content_RavenActionNotifMessage_ActionType int32
+
+const (
+	Armadillo_Content_RavenActionNotifMessage_PLAYED        Armadillo_Content_RavenActionNotifMessage_ActionType = 0
+	Armadillo_Content_RavenActionNotifMessage_SCREENSHOT    Armadillo_Content_RavenActionNotifMessage_ActionType = 1
+	Armadillo_Content_RavenActionNotifMessage_FORCE_DISABLE Armadillo_Content_RavenActionNotifMessage_ActionType = 2
+)
+
+// Enum value maps for Armadillo_Content_RavenActionNotifMessage_ActionType.
+var (
+	Armadillo_Content_RavenActionNotifMessage_ActionType_name = map[int32]string{
+		0: "PLAYED",
+		1: "SCREENSHOT",
+		2: "FORCE_DISABLE",
+	}
+	Armadillo_Content_RavenActionNotifMessage_ActionType_value = map[string]int32{
+		"PLAYED":        0,
+		"SCREENSHOT":    1,
+		"FORCE_DISABLE": 2,
+	}
+)
+
+func (x Armadillo_Content_RavenActionNotifMessage_ActionType) Enum() *Armadillo_Content_RavenActionNotifMessage_ActionType {
+	p := new(Armadillo_Content_RavenActionNotifMessage_ActionType)
+	*p = x
+	return p
+}
+
+func (x Armadillo_Content_RavenActionNotifMessage_ActionType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_Content_RavenActionNotifMessage_ActionType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[5].Descriptor()
+}
+
+func (Armadillo_Content_RavenActionNotifMessage_ActionType) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[5]
+}
+
+func (x Armadillo_Content_RavenActionNotifMessage_ActionType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_Content_RavenActionNotifMessage_ActionType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_Content_RavenActionNotifMessage_ActionType(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_Content_RavenActionNotifMessage_ActionType.Descriptor instead.
+func (Armadillo_Content_RavenActionNotifMessage_ActionType) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 7, 0}
+}
+
+type Armadillo_Content_RavenMessage_EphemeralType int32
+
+const (
+	Armadillo_Content_RavenMessage_VIEW_ONCE    Armadillo_Content_RavenMessage_EphemeralType = 0
+	Armadillo_Content_RavenMessage_ALLOW_REPLAY Armadillo_Content_RavenMessage_EphemeralType = 1
+	Armadillo_Content_RavenMessage_KEEP_IN_CHAT Armadillo_Content_RavenMessage_EphemeralType = 2
+)
+
+// Enum value maps for Armadillo_Content_RavenMessage_EphemeralType.
+var (
+	Armadillo_Content_RavenMessage_EphemeralType_name = map[int32]string{
+		0: "VIEW_ONCE",
+		1: "ALLOW_REPLAY",
+		2: "KEEP_IN_CHAT",
+	}
+	Armadillo_Content_RavenMessage_EphemeralType_value = map[string]int32{
+		"VIEW_ONCE":    0,
+		"ALLOW_REPLAY": 1,
+		"KEEP_IN_CHAT": 2,
+	}
+)
+
+func (x Armadillo_Content_RavenMessage_EphemeralType) Enum() *Armadillo_Content_RavenMessage_EphemeralType {
+	p := new(Armadillo_Content_RavenMessage_EphemeralType)
+	*p = x
+	return p
+}
+
+func (x Armadillo_Content_RavenMessage_EphemeralType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_Content_RavenMessage_EphemeralType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[6].Descriptor()
+}
+
+func (Armadillo_Content_RavenMessage_EphemeralType) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[6]
+}
+
+func (x Armadillo_Content_RavenMessage_EphemeralType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_Content_RavenMessage_EphemeralType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_Content_RavenMessage_EphemeralType(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_Content_RavenMessage_EphemeralType.Descriptor instead.
+func (Armadillo_Content_RavenMessage_EphemeralType) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 8, 0}
+}
+
+type Armadillo_Content_CommonSticker_StickerType int32
+
+const (
+	Armadillo_Content_CommonSticker_SMALL_LIKE  Armadillo_Content_CommonSticker_StickerType = 1
+	Armadillo_Content_CommonSticker_MEDIUM_LIKE Armadillo_Content_CommonSticker_StickerType = 2
+	Armadillo_Content_CommonSticker_LARGE_LIKE  Armadillo_Content_CommonSticker_StickerType = 3
+)
+
+// Enum value maps for Armadillo_Content_CommonSticker_StickerType.
+var (
+	Armadillo_Content_CommonSticker_StickerType_name = map[int32]string{
+		1: "SMALL_LIKE",
+		2: "MEDIUM_LIKE",
+		3: "LARGE_LIKE",
+	}
+	Armadillo_Content_CommonSticker_StickerType_value = map[string]int32{
+		"SMALL_LIKE":  1,
+		"MEDIUM_LIKE": 2,
+		"LARGE_LIKE":  3,
+	}
+)
+
+func (x Armadillo_Content_CommonSticker_StickerType) Enum() *Armadillo_Content_CommonSticker_StickerType {
+	p := new(Armadillo_Content_CommonSticker_StickerType)
+	*p = x
+	return p
+}
+
+func (x Armadillo_Content_CommonSticker_StickerType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Armadillo_Content_CommonSticker_StickerType) Descriptor() protoreflect.EnumDescriptor {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[7].Descriptor()
+}
+
+func (Armadillo_Content_CommonSticker_StickerType) Type() protoreflect.EnumType {
+	return &file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes[7]
+}
+
+func (x Armadillo_Content_CommonSticker_StickerType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Armadillo_Content_CommonSticker_StickerType) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Armadillo_Content_CommonSticker_StickerType(num)
+	return nil
+}
+
+// Deprecated: Use Armadillo_Content_CommonSticker_StickerType.Descriptor instead.
+func (Armadillo_Content_CommonSticker_StickerType) EnumDescriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 9, 0}
+}
+
+type Armadillo struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Payload       *Armadillo_Payload     `protobuf:"bytes,1,opt,name=payload" json:"payload,omitempty"`
+	Metadata      *Armadillo_Metadata    `protobuf:"bytes,2,opt,name=metadata" json:"metadata,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo) Reset() {
+	*x = Armadillo{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo) ProtoMessage() {}
+
+func (x *Armadillo) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo.ProtoReflect.Descriptor instead.
+func (*Armadillo) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Armadillo) GetPayload() *Armadillo_Payload {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *Armadillo) GetMetadata() *Armadillo_Metadata {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+type Armadillo_Metadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Metadata) Reset() {
+	*x = Armadillo_Metadata{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Metadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Metadata) ProtoMessage() {}
+
+func (x *Armadillo_Metadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Metadata.ProtoReflect.Descriptor instead.
+func (*Armadillo_Metadata) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 0}
+}
+
+type Armadillo_Payload struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to Payload:
+	//
+	//	*Armadillo_Payload_Content
+	//	*Armadillo_Payload_ApplicationData
+	//	*Armadillo_Payload_Signal
+	//	*Armadillo_Payload_SubProtocol
+	Payload       isArmadillo_Payload_Payload `protobuf_oneof:"payload"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Payload) Reset() {
+	*x = Armadillo_Payload{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Payload) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Payload) ProtoMessage() {}
+
+func (x *Armadillo_Payload) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Payload.ProtoReflect.Descriptor instead.
+func (*Armadillo_Payload) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 1}
+}
+
+func (x *Armadillo_Payload) GetPayload() isArmadillo_Payload_Payload {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *Armadillo_Payload) GetContent() *Armadillo_Content {
+	if x != nil {
+		if x, ok := x.Payload.(*Armadillo_Payload_Content); ok {
+			return x.Content
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Payload) GetApplicationData() *Armadillo_ApplicationData {
+	if x != nil {
+		if x, ok := x.Payload.(*Armadillo_Payload_ApplicationData); ok {
+			return x.ApplicationData
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Payload) GetSignal() *Armadillo_Signal {
+	if x != nil {
+		if x, ok := x.Payload.(*Armadillo_Payload_Signal); ok {
+			return x.Signal
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Payload) GetSubProtocol() *Armadillo_SubProtocolPayload {
+	if x != nil {
+		if x, ok := x.Payload.(*Armadillo_Payload_SubProtocol); ok {
+			return x.SubProtocol
+		}
+	}
+	return nil
+}
+
+type isArmadillo_Payload_Payload interface {
+	isArmadillo_Payload_Payload()
+}
+
+type Armadillo_Payload_Content struct {
+	Content *Armadillo_Content `protobuf:"bytes,1,opt,name=content,oneof"`
+}
+
+type Armadillo_Payload_ApplicationData struct {
+	ApplicationData *Armadillo_ApplicationData `protobuf:"bytes,2,opt,name=applicationData,oneof"`
+}
+
+type Armadillo_Payload_Signal struct {
+	Signal *Armadillo_Signal `protobuf:"bytes,3,opt,name=signal,oneof"`
+}
+
+type Armadillo_Payload_SubProtocol struct {
+	SubProtocol *Armadillo_SubProtocolPayload `protobuf:"bytes,4,opt,name=subProtocol,oneof"`
+}
+
+func (*Armadillo_Payload_Content) isArmadillo_Payload_Payload() {}
+
+func (*Armadillo_Payload_ApplicationData) isArmadillo_Payload_Payload() {}
+
+func (*Armadillo_Payload_Signal) isArmadillo_Payload_Payload() {}
+
+func (*Armadillo_Payload_SubProtocol) isArmadillo_Payload_Payload() {}
+
+type Armadillo_SubProtocolPayload struct {
+	state         protoimpl.MessageState        `protogen:"open.v1"`
+	FutureProof   *waCommon.FutureProofBehavior `protobuf:"varint,1,opt,name=futureProof,enum=WACommon.FutureProofBehavior" json:"futureProof,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_SubProtocolPayload) Reset() {
+	*x = Armadillo_SubProtocolPayload{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_SubProtocolPayload) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_SubProtocolPayload) ProtoMessage() {}
+
+func (x *Armadillo_SubProtocolPayload) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_SubProtocolPayload.ProtoReflect.Descriptor instead.
+func (*Armadillo_SubProtocolPayload) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 2}
+}
+
+func (x *Armadillo_SubProtocolPayload) GetFutureProof() waCommon.FutureProofBehavior {
+	if x != nil && x.FutureProof != nil {
+		return *x.FutureProof
+	}
+	return waCommon.FutureProofBehavior(0)
+}
+
+type Armadillo_Signal struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to Signal:
+	//
+	//	*Armadillo_Signal_EncryptedBackupsSecrets_
+	Signal        isArmadillo_Signal_Signal `protobuf_oneof:"signal"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Signal) Reset() {
+	*x = Armadillo_Signal{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Signal) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Signal) ProtoMessage() {}
+
+func (x *Armadillo_Signal) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Signal.ProtoReflect.Descriptor instead.
+func (*Armadillo_Signal) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 3}
+}
+
+func (x *Armadillo_Signal) GetSignal() isArmadillo_Signal_Signal {
+	if x != nil {
+		return x.Signal
+	}
+	return nil
+}
+
+func (x *Armadillo_Signal) GetEncryptedBackupsSecrets() *Armadillo_Signal_EncryptedBackupsSecrets {
+	if x != nil {
+		if x, ok := x.Signal.(*Armadillo_Signal_EncryptedBackupsSecrets_); ok {
+			return x.EncryptedBackupsSecrets
+		}
+	}
+	return nil
+}
+
+type isArmadillo_Signal_Signal interface {
+	isArmadillo_Signal_Signal()
+}
+
+type Armadillo_Signal_EncryptedBackupsSecrets_ struct {
+	EncryptedBackupsSecrets *Armadillo_Signal_EncryptedBackupsSecrets `protobuf:"bytes,1,opt,name=encryptedBackupsSecrets,oneof"`
+}
+
+func (*Armadillo_Signal_EncryptedBackupsSecrets_) isArmadillo_Signal_Signal() {}
+
+type Armadillo_ApplicationData struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to ApplicationData:
+	//
+	//	*Armadillo_ApplicationData_MetadataSync
+	//	*Armadillo_ApplicationData_AiBotResponse
+	//	*Armadillo_ApplicationData_MessageHistoryDocumentMessage_
+	ApplicationData isArmadillo_ApplicationData_ApplicationData `protobuf_oneof:"applicationData"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData) Reset() {
+	*x = Armadillo_ApplicationData{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4}
+}
+
+func (x *Armadillo_ApplicationData) GetApplicationData() isArmadillo_ApplicationData_ApplicationData {
+	if x != nil {
+		return x.ApplicationData
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData) GetMetadataSync() *Armadillo_ApplicationData_MetadataSyncNotification {
+	if x != nil {
+		if x, ok := x.ApplicationData.(*Armadillo_ApplicationData_MetadataSync); ok {
+			return x.MetadataSync
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData) GetAiBotResponse() *Armadillo_ApplicationData_AIBotResponseMessage {
+	if x != nil {
+		if x, ok := x.ApplicationData.(*Armadillo_ApplicationData_AiBotResponse); ok {
+			return x.AiBotResponse
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData) GetMessageHistoryDocumentMessage() *Armadillo_ApplicationData_MessageHistoryDocumentMessage {
+	if x != nil {
+		if x, ok := x.ApplicationData.(*Armadillo_ApplicationData_MessageHistoryDocumentMessage_); ok {
+			return x.MessageHistoryDocumentMessage
+		}
+	}
+	return nil
+}
+
+type isArmadillo_ApplicationData_ApplicationData interface {
+	isArmadillo_ApplicationData_ApplicationData()
+}
+
+type Armadillo_ApplicationData_MetadataSync struct {
+	MetadataSync *Armadillo_ApplicationData_MetadataSyncNotification `protobuf:"bytes,1,opt,name=metadataSync,oneof"`
+}
+
+type Armadillo_ApplicationData_AiBotResponse struct {
+	AiBotResponse *Armadillo_ApplicationData_AIBotResponseMessage `protobuf:"bytes,2,opt,name=aiBotResponse,oneof"`
+}
+
+type Armadillo_ApplicationData_MessageHistoryDocumentMessage_ struct {
+	MessageHistoryDocumentMessage *Armadillo_ApplicationData_MessageHistoryDocumentMessage `protobuf:"bytes,3,opt,name=messageHistoryDocumentMessage,oneof"`
+}
+
+func (*Armadillo_ApplicationData_MetadataSync) isArmadillo_ApplicationData_ApplicationData() {}
+
+func (*Armadillo_ApplicationData_AiBotResponse) isArmadillo_ApplicationData_ApplicationData() {}
+
+func (*Armadillo_ApplicationData_MessageHistoryDocumentMessage_) isArmadillo_ApplicationData_ApplicationData() {
+}
+
+type Armadillo_Content struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to Content:
+	//
+	//	*Armadillo_Content_CommonSticker_
+	//	*Armadillo_Content_ScreenshotAction_
+	//	*Armadillo_Content_ExtendedContentMessage
+	//	*Armadillo_Content_RavenMessage_
+	//	*Armadillo_Content_RavenActionNotifMessage_
+	//	*Armadillo_Content_ExtendedMessageContentWithSear
+	//	*Armadillo_Content_ImageGalleryMessage_
+	//	*Armadillo_Content_PaymentsTransactionMessage_
+	//	*Armadillo_Content_BumpExistingMessage_
+	//	*Armadillo_Content_NoteReplyMessage_
+	//	*Armadillo_Content_RavenMessageMsgr
+	//	*Armadillo_Content_NetworkVerificationMessage_
+	Content       isArmadillo_Content_Content `protobuf_oneof:"content"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content) Reset() {
+	*x = Armadillo_Content{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content) ProtoMessage() {}
+
+func (x *Armadillo_Content) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5}
+}
+
+func (x *Armadillo_Content) GetContent() isArmadillo_Content_Content {
+	if x != nil {
+		return x.Content
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetCommonSticker() *Armadillo_Content_CommonSticker {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_CommonSticker_); ok {
+			return x.CommonSticker
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetScreenshotAction() *Armadillo_Content_ScreenshotAction {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_ScreenshotAction_); ok {
+			return x.ScreenshotAction
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetExtendedContentMessage() *waArmadilloXMA.ExtendedContentMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_ExtendedContentMessage); ok {
+			return x.ExtendedContentMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetRavenMessage() *Armadillo_Content_RavenMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_RavenMessage_); ok {
+			return x.RavenMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetRavenActionNotifMessage() *Armadillo_Content_RavenActionNotifMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_RavenActionNotifMessage_); ok {
+			return x.RavenActionNotifMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetExtendedMessageContentWithSear() *Armadillo_Content_ExtendedContentMessageWithSear {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_ExtendedMessageContentWithSear); ok {
+			return x.ExtendedMessageContentWithSear
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetImageGalleryMessage() *Armadillo_Content_ImageGalleryMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_ImageGalleryMessage_); ok {
+			return x.ImageGalleryMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetPaymentsTransactionMessage() *Armadillo_Content_PaymentsTransactionMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_PaymentsTransactionMessage_); ok {
+			return x.PaymentsTransactionMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetBumpExistingMessage() *Armadillo_Content_BumpExistingMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_BumpExistingMessage_); ok {
+			return x.BumpExistingMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetNoteReplyMessage() *Armadillo_Content_NoteReplyMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_NoteReplyMessage_); ok {
+			return x.NoteReplyMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetRavenMessageMsgr() *Armadillo_Content_RavenMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_RavenMessageMsgr); ok {
+			return x.RavenMessageMsgr
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content) GetNetworkVerificationMessage() *Armadillo_Content_NetworkVerificationMessage {
+	if x != nil {
+		if x, ok := x.Content.(*Armadillo_Content_NetworkVerificationMessage_); ok {
+			return x.NetworkVerificationMessage
+		}
+	}
+	return nil
+}
+
+type isArmadillo_Content_Content interface {
+	isArmadillo_Content_Content()
+}
+
+type Armadillo_Content_CommonSticker_ struct {
+	CommonSticker *Armadillo_Content_CommonSticker `protobuf:"bytes,1,opt,name=commonSticker,oneof"`
+}
+
+type Armadillo_Content_ScreenshotAction_ struct {
+	ScreenshotAction *Armadillo_Content_ScreenshotAction `protobuf:"bytes,3,opt,name=screenshotAction,oneof"`
+}
+
+type Armadillo_Content_ExtendedContentMessage struct {
+	ExtendedContentMessage *waArmadilloXMA.ExtendedContentMessage `protobuf:"bytes,4,opt,name=extendedContentMessage,oneof"`
+}
+
+type Armadillo_Content_RavenMessage_ struct {
+	RavenMessage *Armadillo_Content_RavenMessage `protobuf:"bytes,5,opt,name=ravenMessage,oneof"`
+}
+
+type Armadillo_Content_RavenActionNotifMessage_ struct {
+	RavenActionNotifMessage *Armadillo_Content_RavenActionNotifMessage `protobuf:"bytes,6,opt,name=ravenActionNotifMessage,oneof"`
+}
+
+type Armadillo_Content_ExtendedMessageContentWithSear struct {
+	ExtendedMessageContentWithSear *Armadillo_Content_ExtendedContentMessageWithSear `protobuf:"bytes,7,opt,name=extendedMessageContentWithSear,oneof"`
+}
+
+type Armadillo_Content_ImageGalleryMessage_ struct {
+	ImageGalleryMessage *Armadillo_Content_ImageGalleryMessage `protobuf:"bytes,8,opt,name=imageGalleryMessage,oneof"`
+}
+
+type Armadillo_Content_PaymentsTransactionMessage_ struct {
+	PaymentsTransactionMessage *Armadillo_Content_PaymentsTransactionMessage `protobuf:"bytes,10,opt,name=paymentsTransactionMessage,oneof"`
+}
+
+type Armadillo_Content_BumpExistingMessage_ struct {
+	BumpExistingMessage *Armadillo_Content_BumpExistingMessage `protobuf:"bytes,11,opt,name=bumpExistingMessage,oneof"`
+}
+
+type Armadillo_Content_NoteReplyMessage_ struct {
+	NoteReplyMessage *Armadillo_Content_NoteReplyMessage `protobuf:"bytes,13,opt,name=noteReplyMessage,oneof"`
+}
+
+type Armadillo_Content_RavenMessageMsgr struct {
+	RavenMessageMsgr *Armadillo_Content_RavenMessage `protobuf:"bytes,14,opt,name=ravenMessageMsgr,oneof"`
+}
+
+type Armadillo_Content_NetworkVerificationMessage_ struct {
+	NetworkVerificationMessage *Armadillo_Content_NetworkVerificationMessage `protobuf:"bytes,15,opt,name=networkVerificationMessage,oneof"`
+}
+
+func (*Armadillo_Content_CommonSticker_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_ScreenshotAction_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_ExtendedContentMessage) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_RavenMessage_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_RavenActionNotifMessage_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_ExtendedMessageContentWithSear) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_ImageGalleryMessage_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_PaymentsTransactionMessage_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_BumpExistingMessage_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_NoteReplyMessage_) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_RavenMessageMsgr) isArmadillo_Content_Content() {}
+
+func (*Armadillo_Content_NetworkVerificationMessage_) isArmadillo_Content_Content() {}
+
+type Armadillo_Signal_EncryptedBackupsSecrets struct {
+	state                    protoimpl.MessageState                            `protogen:"open.v1"`
+	BackupID                 *uint64                                           `protobuf:"varint,1,opt,name=backupID" json:"backupID,omitempty"`
+	ServerDataID             *uint64                                           `protobuf:"varint,2,opt,name=serverDataID" json:"serverDataID,omitempty"`
+	Epoch                    []*Armadillo_Signal_EncryptedBackupsSecrets_Epoch `protobuf:"bytes,3,rep,name=epoch" json:"epoch,omitempty"`
+	TempOcmfClientState      []byte                                            `protobuf:"bytes,4,opt,name=tempOcmfClientState" json:"tempOcmfClientState,omitempty"`
+	MailboxRootKey           []byte                                            `protobuf:"bytes,5,opt,name=mailboxRootKey" json:"mailboxRootKey,omitempty"`
+	ObliviousValidationToken []byte                                            `protobuf:"bytes,6,opt,name=obliviousValidationToken" json:"obliviousValidationToken,omitempty"`
+	unknownFields            protoimpl.UnknownFields
+	sizeCache                protoimpl.SizeCache
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) Reset() {
+	*x = Armadillo_Signal_EncryptedBackupsSecrets{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[7]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Signal_EncryptedBackupsSecrets) ProtoMessage() {}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[7]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Signal_EncryptedBackupsSecrets.ProtoReflect.Descriptor instead.
+func (*Armadillo_Signal_EncryptedBackupsSecrets) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 3, 0}
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) GetBackupID() uint64 {
+	if x != nil && x.BackupID != nil {
+		return *x.BackupID
+	}
+	return 0
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) GetServerDataID() uint64 {
+	if x != nil && x.ServerDataID != nil {
+		return *x.ServerDataID
+	}
+	return 0
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) GetEpoch() []*Armadillo_Signal_EncryptedBackupsSecrets_Epoch {
+	if x != nil {
+		return x.Epoch
+	}
+	return nil
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) GetTempOcmfClientState() []byte {
+	if x != nil {
+		return x.TempOcmfClientState
+	}
+	return nil
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) GetMailboxRootKey() []byte {
+	if x != nil {
+		return x.MailboxRootKey
+	}
+	return nil
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets) GetObliviousValidationToken() []byte {
+	if x != nil {
+		return x.ObliviousValidationToken
+	}
+	return nil
+}
+
+type Armadillo_Signal_EncryptedBackupsSecrets_Epoch struct {
+	state         protoimpl.MessageState                                      `protogen:"open.v1"`
+	ID            *uint64                                                     `protobuf:"varint,1,opt,name=ID" json:"ID,omitempty"`
+	AnonID        []byte                                                      `protobuf:"bytes,2,opt,name=anonID" json:"anonID,omitempty"`
+	RootKey       []byte                                                      `protobuf:"bytes,3,opt,name=rootKey" json:"rootKey,omitempty"`
+	Status        *Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus `protobuf:"varint,4,opt,name=status,enum=WAArmadilloApplication.Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus" json:"status,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch) Reset() {
+	*x = Armadillo_Signal_EncryptedBackupsSecrets_Epoch{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[8]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Signal_EncryptedBackupsSecrets_Epoch) ProtoMessage() {}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[8]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Signal_EncryptedBackupsSecrets_Epoch.ProtoReflect.Descriptor instead.
+func (*Armadillo_Signal_EncryptedBackupsSecrets_Epoch) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 3, 0, 0}
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch) GetID() uint64 {
+	if x != nil && x.ID != nil {
+		return *x.ID
+	}
+	return 0
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch) GetAnonID() []byte {
+	if x != nil {
+		return x.AnonID
+	}
+	return nil
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch) GetRootKey() []byte {
+	if x != nil {
+		return x.RootKey
+	}
+	return nil
+}
+
+func (x *Armadillo_Signal_EncryptedBackupsSecrets_Epoch) GetStatus() Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus {
+	if x != nil && x.Status != nil {
+		return *x.Status
+	}
+	return Armadillo_Signal_EncryptedBackupsSecrets_Epoch_ES_OPEN
+}
+
+type Armadillo_ApplicationData_MessageHistoryDocumentMessage struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Document      *waCommon.SubProtocol  `protobuf:"bytes,1,opt,name=document" json:"document,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MessageHistoryDocumentMessage) Reset() {
+	*x = Armadillo_ApplicationData_MessageHistoryDocumentMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[9]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MessageHistoryDocumentMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MessageHistoryDocumentMessage) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MessageHistoryDocumentMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[9]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MessageHistoryDocumentMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MessageHistoryDocumentMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 0}
+}
+
+func (x *Armadillo_ApplicationData_MessageHistoryDocumentMessage) GetDocument() *waCommon.SubProtocol {
+	if x != nil {
+		return x.Document
+	}
+	return nil
+}
+
+type Armadillo_ApplicationData_AIBotResponseMessage struct {
+	state            protoimpl.MessageState `protogen:"open.v1"`
+	SummonToken      *string                `protobuf:"bytes,1,opt,name=summonToken" json:"summonToken,omitempty"`
+	MessageText      *string                `protobuf:"bytes,2,opt,name=messageText" json:"messageText,omitempty"`
+	SerializedExtras *string                `protobuf:"bytes,3,opt,name=serializedExtras" json:"serializedExtras,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_AIBotResponseMessage) Reset() {
+	*x = Armadillo_ApplicationData_AIBotResponseMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[10]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_AIBotResponseMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_AIBotResponseMessage) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_AIBotResponseMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[10]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_AIBotResponseMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_AIBotResponseMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 1}
+}
+
+func (x *Armadillo_ApplicationData_AIBotResponseMessage) GetSummonToken() string {
+	if x != nil && x.SummonToken != nil {
+		return *x.SummonToken
+	}
+	return ""
+}
+
+func (x *Armadillo_ApplicationData_AIBotResponseMessage) GetMessageText() string {
+	if x != nil && x.MessageText != nil {
+		return *x.MessageText
+	}
+	return ""
+}
+
+func (x *Armadillo_ApplicationData_AIBotResponseMessage) GetSerializedExtras() string {
+	if x != nil && x.SerializedExtras != nil {
+		return *x.SerializedExtras
+	}
+	return ""
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to ActionType:
+	//
+	//	*Armadillo_ApplicationData_MetadataSyncAction_ChatAction
+	//	*Armadillo_ApplicationData_MetadataSyncAction_MessageAction
+	//	*Armadillo_ApplicationData_MetadataSyncAction_SpectraAction
+	//	*Armadillo_ApplicationData_MetadataSyncAction_AttachmentInterventionAction
+	ActionType      isArmadillo_ApplicationData_MetadataSyncAction_ActionType `protobuf_oneof:"actionType"`
+	ActionTimestamp *int64                                                    `protobuf:"varint,1,opt,name=actionTimestamp" json:"actionTimestamp,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[11]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[11]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) GetActionType() isArmadillo_ApplicationData_MetadataSyncAction_ActionType {
+	if x != nil {
+		return x.ActionType
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) GetChatAction() *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction {
+	if x != nil {
+		if x, ok := x.ActionType.(*Armadillo_ApplicationData_MetadataSyncAction_ChatAction); ok {
+			return x.ChatAction
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) GetMessageAction() *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction {
+	if x != nil {
+		if x, ok := x.ActionType.(*Armadillo_ApplicationData_MetadataSyncAction_MessageAction); ok {
+			return x.MessageAction
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) GetSpectraAction() *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction {
+	if x != nil {
+		if x, ok := x.ActionType.(*Armadillo_ApplicationData_MetadataSyncAction_SpectraAction); ok {
+			return x.SpectraAction
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) GetAttachmentInterventionAction() *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction {
+	if x != nil {
+		if x, ok := x.ActionType.(*Armadillo_ApplicationData_MetadataSyncAction_AttachmentInterventionAction); ok {
+			return x.AttachmentInterventionAction
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction) GetActionTimestamp() int64 {
+	if x != nil && x.ActionTimestamp != nil {
+		return *x.ActionTimestamp
+	}
+	return 0
+}
+
+type isArmadillo_ApplicationData_MetadataSyncAction_ActionType interface {
+	isArmadillo_ApplicationData_MetadataSyncAction_ActionType()
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_ChatAction struct {
+	ChatAction *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction `protobuf:"bytes,101,opt,name=chatAction,oneof"`
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_MessageAction struct {
+	MessageAction *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction `protobuf:"bytes,102,opt,name=messageAction,oneof"`
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SpectraAction struct {
+	SpectraAction *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction `protobuf:"bytes,103,opt,name=spectraAction,oneof"`
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_AttachmentInterventionAction struct {
+	AttachmentInterventionAction *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction `protobuf:"bytes,104,opt,name=attachmentInterventionAction,oneof"`
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_ChatAction) isArmadillo_ApplicationData_MetadataSyncAction_ActionType() {
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_MessageAction) isArmadillo_ApplicationData_MetadataSyncAction_ActionType() {
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SpectraAction) isArmadillo_ApplicationData_MetadataSyncAction_ActionType() {
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_AttachmentInterventionAction) isArmadillo_ApplicationData_MetadataSyncAction_ActionType() {
+}
+
+type Armadillo_ApplicationData_MetadataSyncNotification struct {
+	state         protoimpl.MessageState                          `protogen:"open.v1"`
+	Actions       []*Armadillo_ApplicationData_MetadataSyncAction `protobuf:"bytes,2,rep,name=actions" json:"actions,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncNotification) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncNotification{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[12]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncNotification) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncNotification) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncNotification) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[12]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncNotification.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncNotification) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 3}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncNotification) GetActions() []*Armadillo_ApplicationData_MetadataSyncAction {
+	if x != nil {
+		return x.Actions
+	}
+	return nil
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction struct {
+	state            protoimpl.MessageState                                                                          `protogen:"open.v1"`
+	MessageKey       *waCommon.MessageKey                                                                            `protobuf:"bytes,1,opt,name=messageKey" json:"messageKey,omitempty"`
+	InterventionType *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType `protobuf:"varint,2,opt,name=interventionType,enum=WAArmadilloApplication.Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType" json:"interventionType,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[13]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction) ProtoMessage() {
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[13]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 0}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction) GetMessageKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.MessageKey
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction) GetInterventionType() Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType {
+	if x != nil && x.InterventionType != nil {
+		return *x.InterventionType
+	}
+	return Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_UNKNOWN
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction struct {
+	state            protoimpl.MessageState                                                            `protogen:"open.v1"`
+	Key              *waCommon.MessageKey                                                              `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
+	ActionType       *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType `protobuf:"varint,2,opt,name=actionType,enum=WAArmadilloApplication.Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType" json:"actionType,omitempty"`
+	TakedownActionID *int64                                                                            `protobuf:"varint,3,opt,name=takedownActionID" json:"takedownActionID,omitempty"`
+	Config           *string                                                                           `protobuf:"bytes,4,opt,name=config" json:"config,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[14]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[14]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 1}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) GetKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) GetActionType() Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType {
+	if x != nil && x.ActionType != nil {
+		return *x.ActionType
+	}
+	return Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_TAKEDOWN
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) GetTakedownActionID() int64 {
+	if x != nil && x.TakedownActionID != nil {
+		return *x.TakedownActionID
+	}
+	return 0
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction) GetConfig() string {
+	if x != nil && x.Config != nil {
+		return *x.Config
+	}
+	return ""
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to Action:
+	//
+	//	*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_MessageDelete
+	Action        isArmadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_Action `protobuf_oneof:"action"`
+	Key           *waCommon.MessageKey                                                    `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[15]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[15]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 2}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) GetAction() isArmadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_Action {
+	if x != nil {
+		return x.Action
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) GetMessageDelete() *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete {
+	if x != nil {
+		if x, ok := x.Action.(*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_MessageDelete); ok {
+			return x.MessageDelete
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction) GetKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type isArmadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_Action interface {
+	isArmadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_Action()
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_MessageDelete struct {
+	MessageDelete *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete `protobuf:"bytes,101,opt,name=messageDelete,oneof"`
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_MessageDelete) isArmadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_Action() {
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to Action:
+	//
+	//	*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatArchive
+	//	*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatDelete
+	//	*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatRead
+	Action        isArmadillo_ApplicationData_MetadataSyncAction_SyncChatAction_Action `protobuf_oneof:"action"`
+	ChatID        *string                                                              `protobuf:"bytes,1,opt,name=chatID" json:"chatID,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[16]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[16]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 3}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) GetAction() isArmadillo_ApplicationData_MetadataSyncAction_SyncChatAction_Action {
+	if x != nil {
+		return x.Action
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) GetChatArchive() *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive {
+	if x != nil {
+		if x, ok := x.Action.(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatArchive); ok {
+			return x.ChatArchive
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) GetChatDelete() *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete {
+	if x != nil {
+		if x, ok := x.Action.(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatDelete); ok {
+			return x.ChatDelete
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) GetChatRead() *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead {
+	if x != nil {
+		if x, ok := x.Action.(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatRead); ok {
+			return x.ChatRead
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction) GetChatID() string {
+	if x != nil && x.ChatID != nil {
+		return *x.ChatID
+	}
+	return ""
+}
+
+type isArmadillo_ApplicationData_MetadataSyncAction_SyncChatAction_Action interface {
+	isArmadillo_ApplicationData_MetadataSyncAction_SyncChatAction_Action()
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatArchive struct {
+	ChatArchive *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive `protobuf:"bytes,101,opt,name=chatArchive,oneof"`
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatDelete struct {
+	ChatDelete *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete `protobuf:"bytes,102,opt,name=chatDelete,oneof"`
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatRead struct {
+	ChatRead *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead `protobuf:"bytes,103,opt,name=chatRead,oneof"`
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatArchive) isArmadillo_ApplicationData_MetadataSyncAction_SyncChatAction_Action() {
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatDelete) isArmadillo_ApplicationData_MetadataSyncAction_SyncChatAction_Action() {
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatRead) isArmadillo_ApplicationData_MetadataSyncAction_SyncChatAction_Action() {
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Key           *waCommon.MessageKey   `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
+	Timestamp     *int64                 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[17]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[17]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 4}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage) GetKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage) GetTimestamp() int64 {
+	if x != nil && x.Timestamp != nil {
+		return *x.Timestamp
+	}
+	return 0
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange struct {
+	state                      protoimpl.MessageState                                            `protogen:"open.v1"`
+	LastMessageTimestamp       *int64                                                            `protobuf:"varint,1,opt,name=lastMessageTimestamp" json:"lastMessageTimestamp,omitempty"`
+	LastSystemMessageTimestamp *int64                                                            `protobuf:"varint,2,opt,name=lastSystemMessageTimestamp" json:"lastSystemMessageTimestamp,omitempty"`
+	Messages                   []*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage `protobuf:"bytes,3,rep,name=messages" json:"messages,omitempty"`
+	unknownFields              protoimpl.UnknownFields
+	sizeCache                  protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[18]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[18]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 5}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) GetLastMessageTimestamp() int64 {
+	if x != nil && x.LastMessageTimestamp != nil {
+		return *x.LastMessageTimestamp
+	}
+	return 0
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) GetLastSystemMessageTimestamp() int64 {
+	if x != nil && x.LastSystemMessageTimestamp != nil {
+		return *x.LastSystemMessageTimestamp
+	}
+	return 0
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange) GetMessages() []*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage {
+	if x != nil {
+		return x.Messages
+	}
+	return nil
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[19]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete) ProtoMessage() {
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[19]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 2, 0}
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead struct {
+	state         protoimpl.MessageState                                               `protogen:"open.v1"`
+	MessageRange  *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange `protobuf:"bytes,1,opt,name=messageRange" json:"messageRange,omitempty"`
+	Read          *bool                                                                `protobuf:"varint,2,opt,name=read" json:"read,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[20]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[20]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 3, 0}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead) GetMessageRange() *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange {
+	if x != nil {
+		return x.MessageRange
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead) GetRead() bool {
+	if x != nil && x.Read != nil {
+		return *x.Read
+	}
+	return false
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete struct {
+	state         protoimpl.MessageState                                               `protogen:"open.v1"`
+	MessageRange  *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange `protobuf:"bytes,1,opt,name=messageRange" json:"messageRange,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[21]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete) ProtoMessage() {}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[21]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 3, 1}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete) GetMessageRange() *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange {
+	if x != nil {
+		return x.MessageRange
+	}
+	return nil
+}
+
+type Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive struct {
+	state         protoimpl.MessageState                                               `protogen:"open.v1"`
+	MessageRange  *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange `protobuf:"bytes,1,opt,name=messageRange" json:"messageRange,omitempty"`
+	Archived      *bool                                                                `protobuf:"varint,2,opt,name=archived" json:"archived,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive) Reset() {
+	*x = Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[22]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive) ProtoMessage() {
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[22]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive.ProtoReflect.Descriptor instead.
+func (*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 4, 2, 3, 2}
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive) GetMessageRange() *Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange {
+	if x != nil {
+		return x.MessageRange
+	}
+	return nil
+}
+
+func (x *Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive) GetArchived() bool {
+	if x != nil && x.Archived != nil {
+		return *x.Archived
+	}
+	return false
+}
+
+type Armadillo_Content_PaymentsTransactionMessage struct {
+	state                  protoimpl.MessageState                                      `protogen:"open.v1"`
+	TransactionID          *uint64                                                     `protobuf:"varint,1,opt,name=transactionID" json:"transactionID,omitempty"`
+	Amount                 *string                                                     `protobuf:"bytes,2,opt,name=amount" json:"amount,omitempty"`
+	Currency               *string                                                     `protobuf:"bytes,3,opt,name=currency" json:"currency,omitempty"`
+	PaymentStatus          *Armadillo_Content_PaymentsTransactionMessage_PaymentStatus `protobuf:"varint,4,opt,name=paymentStatus,enum=WAArmadilloApplication.Armadillo_Content_PaymentsTransactionMessage_PaymentStatus" json:"paymentStatus,omitempty"`
+	ExtendedContentMessage *waArmadilloXMA.ExtendedContentMessage                      `protobuf:"bytes,5,opt,name=extendedContentMessage" json:"extendedContentMessage,omitempty"`
+	unknownFields          protoimpl.UnknownFields
+	sizeCache              protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) Reset() {
+	*x = Armadillo_Content_PaymentsTransactionMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[23]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_PaymentsTransactionMessage) ProtoMessage() {}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[23]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_PaymentsTransactionMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_PaymentsTransactionMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 0}
+}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) GetTransactionID() uint64 {
+	if x != nil && x.TransactionID != nil {
+		return *x.TransactionID
+	}
+	return 0
+}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) GetAmount() string {
+	if x != nil && x.Amount != nil {
+		return *x.Amount
+	}
+	return ""
+}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) GetCurrency() string {
+	if x != nil && x.Currency != nil {
+		return *x.Currency
+	}
+	return ""
+}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) GetPaymentStatus() Armadillo_Content_PaymentsTransactionMessage_PaymentStatus {
+	if x != nil && x.PaymentStatus != nil {
+		return *x.PaymentStatus
+	}
+	return Armadillo_Content_PaymentsTransactionMessage_PAYMENT_UNKNOWN
+}
+
+func (x *Armadillo_Content_PaymentsTransactionMessage) GetExtendedContentMessage() *waArmadilloXMA.ExtendedContentMessage {
+	if x != nil {
+		return x.ExtendedContentMessage
+	}
+	return nil
+}
+
+type Armadillo_Content_NetworkVerificationMessage struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	CodeText      *string                `protobuf:"bytes,1,opt,name=codeText" json:"codeText,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_NetworkVerificationMessage) Reset() {
+	*x = Armadillo_Content_NetworkVerificationMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[24]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_NetworkVerificationMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_NetworkVerificationMessage) ProtoMessage() {}
+
+func (x *Armadillo_Content_NetworkVerificationMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[24]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_NetworkVerificationMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_NetworkVerificationMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 1}
+}
+
+func (x *Armadillo_Content_NetworkVerificationMessage) GetCodeText() string {
+	if x != nil && x.CodeText != nil {
+		return *x.CodeText
+	}
+	return ""
+}
+
+type Armadillo_Content_NoteReplyMessage struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to NoteReplyContent:
+	//
+	//	*Armadillo_Content_NoteReplyMessage_TextContent
+	//	*Armadillo_Content_NoteReplyMessage_StickerContent
+	//	*Armadillo_Content_NoteReplyMessage_VideoContent
+	NoteReplyContent isArmadillo_Content_NoteReplyMessage_NoteReplyContent `protobuf_oneof:"noteReplyContent"`
+	NoteID           *string                                               `protobuf:"bytes,1,opt,name=noteID" json:"noteID,omitempty"`
+	NoteText         *waCommon.MessageText                                 `protobuf:"bytes,2,opt,name=noteText" json:"noteText,omitempty"`
+	NoteTimestampMS  *int64                                                `protobuf:"varint,3,opt,name=noteTimestampMS" json:"noteTimestampMS,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) Reset() {
+	*x = Armadillo_Content_NoteReplyMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[25]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_NoteReplyMessage) ProtoMessage() {}
+
+func (x *Armadillo_Content_NoteReplyMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[25]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_NoteReplyMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_NoteReplyMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 2}
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) GetNoteReplyContent() isArmadillo_Content_NoteReplyMessage_NoteReplyContent {
+	if x != nil {
+		return x.NoteReplyContent
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) GetTextContent() *waCommon.MessageText {
+	if x != nil {
+		if x, ok := x.NoteReplyContent.(*Armadillo_Content_NoteReplyMessage_TextContent); ok {
+			return x.TextContent
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) GetStickerContent() *waCommon.SubProtocol {
+	if x != nil {
+		if x, ok := x.NoteReplyContent.(*Armadillo_Content_NoteReplyMessage_StickerContent); ok {
+			return x.StickerContent
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) GetVideoContent() *waCommon.SubProtocol {
+	if x != nil {
+		if x, ok := x.NoteReplyContent.(*Armadillo_Content_NoteReplyMessage_VideoContent); ok {
+			return x.VideoContent
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) GetNoteID() string {
+	if x != nil && x.NoteID != nil {
+		return *x.NoteID
+	}
+	return ""
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) GetNoteText() *waCommon.MessageText {
+	if x != nil {
+		return x.NoteText
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_NoteReplyMessage) GetNoteTimestampMS() int64 {
+	if x != nil && x.NoteTimestampMS != nil {
+		return *x.NoteTimestampMS
+	}
+	return 0
+}
+
+type isArmadillo_Content_NoteReplyMessage_NoteReplyContent interface {
+	isArmadillo_Content_NoteReplyMessage_NoteReplyContent()
+}
+
+type Armadillo_Content_NoteReplyMessage_TextContent struct {
+	TextContent *waCommon.MessageText `protobuf:"bytes,4,opt,name=textContent,oneof"`
+}
+
+type Armadillo_Content_NoteReplyMessage_StickerContent struct {
+	StickerContent *waCommon.SubProtocol `protobuf:"bytes,5,opt,name=stickerContent,oneof"`
+}
+
+type Armadillo_Content_NoteReplyMessage_VideoContent struct {
+	VideoContent *waCommon.SubProtocol `protobuf:"bytes,6,opt,name=videoContent,oneof"`
+}
+
+func (*Armadillo_Content_NoteReplyMessage_TextContent) isArmadillo_Content_NoteReplyMessage_NoteReplyContent() {
+}
+
+func (*Armadillo_Content_NoteReplyMessage_StickerContent) isArmadillo_Content_NoteReplyMessage_NoteReplyContent() {
+}
+
+func (*Armadillo_Content_NoteReplyMessage_VideoContent) isArmadillo_Content_NoteReplyMessage_NoteReplyContent() {
+}
+
+type Armadillo_Content_BumpExistingMessage struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Key           *waCommon.MessageKey   `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_BumpExistingMessage) Reset() {
+	*x = Armadillo_Content_BumpExistingMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[26]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_BumpExistingMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_BumpExistingMessage) ProtoMessage() {}
+
+func (x *Armadillo_Content_BumpExistingMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[26]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_BumpExistingMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_BumpExistingMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 3}
+}
+
+func (x *Armadillo_Content_BumpExistingMessage) GetKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+type Armadillo_Content_ImageGalleryMessage struct {
+	state         protoimpl.MessageState  `protogen:"open.v1"`
+	Images        []*waCommon.SubProtocol `protobuf:"bytes,1,rep,name=images" json:"images,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_ImageGalleryMessage) Reset() {
+	*x = Armadillo_Content_ImageGalleryMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[27]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_ImageGalleryMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_ImageGalleryMessage) ProtoMessage() {}
+
+func (x *Armadillo_Content_ImageGalleryMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[27]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_ImageGalleryMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_ImageGalleryMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 4}
+}
+
+func (x *Armadillo_Content_ImageGalleryMessage) GetImages() []*waCommon.SubProtocol {
+	if x != nil {
+		return x.Images
+	}
+	return nil
+}
+
+type Armadillo_Content_ScreenshotAction struct {
+	state          protoimpl.MessageState                             `protogen:"open.v1"`
+	ScreenshotType *Armadillo_Content_ScreenshotAction_ScreenshotType `protobuf:"varint,1,opt,name=screenshotType,enum=WAArmadilloApplication.Armadillo_Content_ScreenshotAction_ScreenshotType" json:"screenshotType,omitempty"`
+	unknownFields  protoimpl.UnknownFields
+	sizeCache      protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_ScreenshotAction) Reset() {
+	*x = Armadillo_Content_ScreenshotAction{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[28]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_ScreenshotAction) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_ScreenshotAction) ProtoMessage() {}
+
+func (x *Armadillo_Content_ScreenshotAction) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[28]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_ScreenshotAction.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_ScreenshotAction) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 5}
+}
+
+func (x *Armadillo_Content_ScreenshotAction) GetScreenshotType() Armadillo_Content_ScreenshotAction_ScreenshotType {
+	if x != nil && x.ScreenshotType != nil {
+		return *x.ScreenshotType
+	}
+	return Armadillo_Content_ScreenshotAction_SCREENSHOT_IMAGE
+}
+
+type Armadillo_Content_ExtendedContentMessageWithSear struct {
+	state                 protoimpl.MessageState `protogen:"open.v1"`
+	SearID                *string                `protobuf:"bytes,1,opt,name=searID" json:"searID,omitempty"`
+	Payload               []byte                 `protobuf:"bytes,2,opt,name=payload" json:"payload,omitempty"`
+	NativeURL             *string                `protobuf:"bytes,3,opt,name=nativeURL" json:"nativeURL,omitempty"`
+	SearAssociatedMessage *waCommon.SubProtocol  `protobuf:"bytes,4,opt,name=searAssociatedMessage" json:"searAssociatedMessage,omitempty"`
+	SearSentWithMessageID *string                `protobuf:"bytes,5,opt,name=searSentWithMessageID" json:"searSentWithMessageID,omitempty"`
+	unknownFields         protoimpl.UnknownFields
+	sizeCache             protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) Reset() {
+	*x = Armadillo_Content_ExtendedContentMessageWithSear{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[29]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_ExtendedContentMessageWithSear) ProtoMessage() {}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[29]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_ExtendedContentMessageWithSear.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_ExtendedContentMessageWithSear) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 6}
+}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) GetSearID() string {
+	if x != nil && x.SearID != nil {
+		return *x.SearID
+	}
+	return ""
+}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) GetPayload() []byte {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) GetNativeURL() string {
+	if x != nil && x.NativeURL != nil {
+		return *x.NativeURL
+	}
+	return ""
+}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) GetSearAssociatedMessage() *waCommon.SubProtocol {
+	if x != nil {
+		return x.SearAssociatedMessage
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_ExtendedContentMessageWithSear) GetSearSentWithMessageID() string {
+	if x != nil && x.SearSentWithMessageID != nil {
+		return *x.SearSentWithMessageID
+	}
+	return ""
+}
+
+type Armadillo_Content_RavenActionNotifMessage struct {
+	state           protoimpl.MessageState                                `protogen:"open.v1"`
+	Key             *waCommon.MessageKey                                  `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
+	ActionTimestamp *int64                                                `protobuf:"varint,2,opt,name=actionTimestamp" json:"actionTimestamp,omitempty"`
+	ActionType      *Armadillo_Content_RavenActionNotifMessage_ActionType `protobuf:"varint,3,opt,name=actionType,enum=WAArmadilloApplication.Armadillo_Content_RavenActionNotifMessage_ActionType" json:"actionType,omitempty"`
+	unknownFields   protoimpl.UnknownFields
+	sizeCache       protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_RavenActionNotifMessage) Reset() {
+	*x = Armadillo_Content_RavenActionNotifMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[30]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_RavenActionNotifMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_RavenActionNotifMessage) ProtoMessage() {}
+
+func (x *Armadillo_Content_RavenActionNotifMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[30]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_RavenActionNotifMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_RavenActionNotifMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 7}
+}
+
+func (x *Armadillo_Content_RavenActionNotifMessage) GetKey() *waCommon.MessageKey {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_RavenActionNotifMessage) GetActionTimestamp() int64 {
+	if x != nil && x.ActionTimestamp != nil {
+		return *x.ActionTimestamp
+	}
+	return 0
+}
+
+func (x *Armadillo_Content_RavenActionNotifMessage) GetActionType() Armadillo_Content_RavenActionNotifMessage_ActionType {
+	if x != nil && x.ActionType != nil {
+		return *x.ActionType
+	}
+	return Armadillo_Content_RavenActionNotifMessage_PLAYED
+}
+
+type Armadillo_Content_RavenMessage struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to MediaContent:
+	//
+	//	*Armadillo_Content_RavenMessage_ImageMessage
+	//	*Armadillo_Content_RavenMessage_VideoMessage
+	MediaContent  isArmadillo_Content_RavenMessage_MediaContent `protobuf_oneof:"mediaContent"`
+	EphemeralType *Armadillo_Content_RavenMessage_EphemeralType `protobuf:"varint,1,opt,name=ephemeralType,enum=WAArmadilloApplication.Armadillo_Content_RavenMessage_EphemeralType" json:"ephemeralType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_RavenMessage) Reset() {
+	*x = Armadillo_Content_RavenMessage{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[31]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_RavenMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_RavenMessage) ProtoMessage() {}
+
+func (x *Armadillo_Content_RavenMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[31]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_RavenMessage.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_RavenMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 8}
+}
+
+func (x *Armadillo_Content_RavenMessage) GetMediaContent() isArmadillo_Content_RavenMessage_MediaContent {
+	if x != nil {
+		return x.MediaContent
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_RavenMessage) GetImageMessage() *waCommon.SubProtocol {
+	if x != nil {
+		if x, ok := x.MediaContent.(*Armadillo_Content_RavenMessage_ImageMessage); ok {
+			return x.ImageMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_RavenMessage) GetVideoMessage() *waCommon.SubProtocol {
+	if x != nil {
+		if x, ok := x.MediaContent.(*Armadillo_Content_RavenMessage_VideoMessage); ok {
+			return x.VideoMessage
+		}
+	}
+	return nil
+}
+
+func (x *Armadillo_Content_RavenMessage) GetEphemeralType() Armadillo_Content_RavenMessage_EphemeralType {
+	if x != nil && x.EphemeralType != nil {
+		return *x.EphemeralType
+	}
+	return Armadillo_Content_RavenMessage_VIEW_ONCE
+}
+
+type isArmadillo_Content_RavenMessage_MediaContent interface {
+	isArmadillo_Content_RavenMessage_MediaContent()
+}
+
+type Armadillo_Content_RavenMessage_ImageMessage struct {
+	ImageMessage *waCommon.SubProtocol `protobuf:"bytes,2,opt,name=imageMessage,oneof"`
+}
+
+type Armadillo_Content_RavenMessage_VideoMessage struct {
+	VideoMessage *waCommon.SubProtocol `protobuf:"bytes,3,opt,name=videoMessage,oneof"`
+}
+
+func (*Armadillo_Content_RavenMessage_ImageMessage) isArmadillo_Content_RavenMessage_MediaContent() {}
+
+func (*Armadillo_Content_RavenMessage_VideoMessage) isArmadillo_Content_RavenMessage_MediaContent() {}
+
+type Armadillo_Content_CommonSticker struct {
+	state         protoimpl.MessageState                       `protogen:"open.v1"`
+	StickerType   *Armadillo_Content_CommonSticker_StickerType `protobuf:"varint,1,opt,name=stickerType,enum=WAArmadilloApplication.Armadillo_Content_CommonSticker_StickerType" json:"stickerType,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Armadillo_Content_CommonSticker) Reset() {
+	*x = Armadillo_Content_CommonSticker{}
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[32]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Armadillo_Content_CommonSticker) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Armadillo_Content_CommonSticker) ProtoMessage() {}
+
+func (x *Armadillo_Content_CommonSticker) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[32]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Armadillo_Content_CommonSticker.ProtoReflect.Descriptor instead.
+func (*Armadillo_Content_CommonSticker) Descriptor() ([]byte, []int) {
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP(), []int{0, 5, 9}
+}
+
+func (x *Armadillo_Content_CommonSticker) GetStickerType() Armadillo_Content_CommonSticker_StickerType {
+	if x != nil && x.StickerType != nil {
+		return *x.StickerType
+	}
+	return Armadillo_Content_CommonSticker_SMALL_LIKE
+}
+
+var File_waArmadilloApplication_WAArmadilloApplication_proto protoreflect.FileDescriptor
+
+const file_waArmadilloApplication_WAArmadilloApplication_proto_rawDesc = "" +
+	"\n" +
+	"3waArmadilloApplication/WAArmadilloApplication.proto\x12\x16WAArmadilloApplication\x1a#waArmadilloXMA/WAArmadilloXMA.proto\x1a\x17waCommon/WACommon.proto\"\xbbF\n" +
+	"\tArmadillo\x12C\n" +
+	"\apayload\x18\x01 \x01(\v2).WAArmadilloApplication.Armadillo.PayloadR\apayload\x12F\n" +
+	"\bmetadata\x18\x02 \x01(\v2*.WAArmadilloApplication.Armadillo.MetadataR\bmetadata\x1a\n" +
+	"\n" +
+	"\bMetadata\x1a\xd8\x02\n" +
+	"\aPayload\x12E\n" +
+	"\acontent\x18\x01 \x01(\v2).WAArmadilloApplication.Armadillo.ContentH\x00R\acontent\x12]\n" +
+	"\x0fapplicationData\x18\x02 \x01(\v21.WAArmadilloApplication.Armadillo.ApplicationDataH\x00R\x0fapplicationData\x12B\n" +
+	"\x06signal\x18\x03 \x01(\v2(.WAArmadilloApplication.Armadillo.SignalH\x00R\x06signal\x12X\n" +
+	"\vsubProtocol\x18\x04 \x01(\v24.WAArmadilloApplication.Armadillo.SubProtocolPayloadH\x00R\vsubProtocolB\t\n" +
+	"\apayload\x1aU\n" +
+	"\x12SubProtocolPayload\x12?\n" +
+	"\vfutureProof\x18\x01 \x01(\x0e2\x1d.WACommon.FutureProofBehaviorR\vfutureProof\x1a\xc2\x05\n" +
+	"\x06Signal\x12|\n" +
+	"\x17encryptedBackupsSecrets\x18\x01 \x01(\v2@.WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecretsH\x00R\x17encryptedBackupsSecrets\x1a\xaf\x04\n" +
+	"\x17EncryptedBackupsSecrets\x12\x1a\n" +
+	"\bbackupID\x18\x01 \x01(\x04R\bbackupID\x12\"\n" +
+	"\fserverDataID\x18\x02 \x01(\x04R\fserverDataID\x12\\\n" +
+	"\x05epoch\x18\x03 \x03(\v2F.WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.EpochR\x05epoch\x120\n" +
+	"\x13tempOcmfClientState\x18\x04 \x01(\fR\x13tempOcmfClientState\x12&\n" +
+	"\x0emailboxRootKey\x18\x05 \x01(\fR\x0emailboxRootKey\x12:\n" +
+	"\x18obliviousValidationToken\x18\x06 \x01(\fR\x18obliviousValidationToken\x1a\xdf\x01\n" +
+	"\x05Epoch\x12\x0e\n" +
+	"\x02ID\x18\x01 \x01(\x04R\x02ID\x12\x16\n" +
+	"\x06anonID\x18\x02 \x01(\fR\x06anonID\x12\x18\n" +
+	"\arootKey\x18\x03 \x01(\fR\arootKey\x12j\n" +
+	"\x06status\x18\x04 \x01(\x0e2R.WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.Epoch.EpochStatusR\x06status\"(\n" +
+	"\vEpochStatus\x12\v\n" +
+	"\aES_OPEN\x10\x01\x12\f\n" +
+	"\bES_CLOSE\x10\x02B\b\n" +
+	"\x06signal\x1a\xf3\x1b\n" +
+	"\x0fApplicationData\x12p\n" +
+	"\fmetadataSync\x18\x01 \x01(\v2J.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncNotificationH\x00R\fmetadataSync\x12n\n" +
+	"\raiBotResponse\x18\x02 \x01(\v2F.WAArmadilloApplication.Armadillo.ApplicationData.AIBotResponseMessageH\x00R\raiBotResponse\x12\x97\x01\n" +
+	"\x1dmessageHistoryDocumentMessage\x18\x03 \x01(\v2O.WAArmadilloApplication.Armadillo.ApplicationData.MessageHistoryDocumentMessageH\x00R\x1dmessageHistoryDocumentMessage\x1aR\n" +
+	"\x1dMessageHistoryDocumentMessage\x121\n" +
+	"\bdocument\x18\x01 \x01(\v2\x15.WACommon.SubProtocolR\bdocument\x1a\x86\x01\n" +
+	"\x14AIBotResponseMessage\x12 \n" +
+	"\vsummonToken\x18\x01 \x01(\tR\vsummonToken\x12 \n" +
+	"\vmessageText\x18\x02 \x01(\tR\vmessageText\x12*\n" +
+	"\x10serializedExtras\x18\x03 \x01(\tR\x10serializedExtras\x1a\xf7\x15\n" +
+	"\x12MetadataSyncAction\x12u\n" +
+	"\n" +
+	"chatAction\x18e \x01(\v2S.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatActionH\x00R\n" +
+	"chatAction\x12~\n" +
+	"\rmessageAction\x18f \x01(\v2V.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageActionH\x00R\rmessageAction\x12~\n" +
+	"\rspectraAction\x18g \x01(\v2V.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraActionH\x00R\rspectraAction\x12\xab\x01\n" +
+	"\x1cattachmentInterventionAction\x18h \x01(\v2e.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionActionH\x00R\x1cattachmentInterventionAction\x12(\n" +
+	"\x0factionTimestamp\x18\x01 \x01(\x03R\x0factionTimestamp\x1a\xb6\x02\n" +
+	" SyncAttachmentInterventionAction\x124\n" +
+	"\n" +
+	"messageKey\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\n" +
+	"messageKey\x12\xa2\x01\n" +
+	"\x10interventionType\x18\x02 \x01(\x0e2v.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionAction.InterventionTypeR\x10interventionType\"7\n" +
+	"\x10InterventionType\x12\v\n" +
+	"\aUNKNOWN\x10\x00\x12\b\n" +
+	"\x04NUDE\x10\x01\x12\f\n" +
+	"\bNOT_NUDE\x10\x02\x1a\xba\x02\n" +
+	"\x11SyncSpectraAction\x12&\n" +
+	"\x03key\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\x03key\x12\x88\x01\n" +
+	"\n" +
+	"actionType\x18\x02 \x01(\x0e2h.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraAction.SpectraActionTypeR\n" +
+	"actionType\x12*\n" +
+	"\x10takedownActionID\x18\x03 \x01(\x03R\x10takedownActionID\x12\x16\n" +
+	"\x06config\x18\x04 \x01(\tR\x06config\".\n" +
+	"\x11SpectraActionType\x12\f\n" +
+	"\bTAKEDOWN\x10\x00\x12\v\n" +
+	"\aRESTORE\x10\x01\x1a\xf1\x01\n" +
+	"\x11SyncMessageAction\x12\x92\x01\n" +
+	"\rmessageDelete\x18e \x01(\v2j.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageAction.ActionMessageDeleteH\x00R\rmessageDelete\x12&\n" +
+	"\x03key\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\x03key\x1a\x15\n" +
+	"\x13ActionMessageDeleteB\b\n" +
+	"\x06action\x1a\xbb\a\n" +
+	"\x0eSyncChatAction\x12\x89\x01\n" +
+	"\vchatArchive\x18e \x01(\v2e.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatArchiveH\x00R\vchatArchive\x12\x86\x01\n" +
+	"\n" +
+	"chatDelete\x18f \x01(\v2d.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatDeleteH\x00R\n" +
+	"chatDelete\x12\x80\x01\n" +
+	"\bchatRead\x18g \x01(\v2b.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatReadH\x00R\bchatRead\x12\x16\n" +
+	"\x06chatID\x18\x01 \x01(\tR\x06chatID\x1a\xa5\x01\n" +
+	"\x0eActionChatRead\x12\x7f\n" +
+	"\fmessageRange\x18\x01 \x01(\v2[.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRangeR\fmessageRange\x12\x12\n" +
+	"\x04read\x18\x02 \x01(\bR\x04read\x1a\x93\x01\n" +
+	"\x10ActionChatDelete\x12\x7f\n" +
+	"\fmessageRange\x18\x01 \x01(\v2[.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRangeR\fmessageRange\x1a\xb0\x01\n" +
+	"\x11ActionChatArchive\x12\x7f\n" +
+	"\fmessageRange\x18\x01 \x01(\v2[.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRangeR\fmessageRange\x12\x1a\n" +
+	"\barchived\x18\x02 \x01(\bR\barchivedB\b\n" +
+	"\x06action\x1aY\n" +
+	"\x11SyncActionMessage\x12&\n" +
+	"\x03key\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\x03key\x12\x1c\n" +
+	"\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\x1a\x80\x02\n" +
+	"\x16SyncActionMessageRange\x122\n" +
+	"\x14lastMessageTimestamp\x18\x01 \x01(\x03R\x14lastMessageTimestamp\x12>\n" +
+	"\x1alastSystemMessageTimestamp\x18\x02 \x01(\x03R\x1alastSystemMessageTimestamp\x12r\n" +
+	"\bmessages\x18\x03 \x03(\v2V.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageR\bmessagesB\f\n" +
+	"\n" +
+	"actionType\x1az\n" +
+	"\x18MetadataSyncNotification\x12^\n" +
+	"\aactions\x18\x02 \x03(\v2D.WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncActionR\aactionsB\x11\n" +
+	"\x0fapplicationData\x1a\xa7 \n" +
+	"\aContent\x12_\n" +
+	"\rcommonSticker\x18\x01 \x01(\v27.WAArmadilloApplication.Armadillo.Content.CommonStickerH\x00R\rcommonSticker\x12h\n" +
+	"\x10screenshotAction\x18\x03 \x01(\v2:.WAArmadilloApplication.Armadillo.Content.ScreenshotActionH\x00R\x10screenshotAction\x12`\n" +
+	"\x16extendedContentMessage\x18\x04 \x01(\v2&.WAArmadilloXMA.ExtendedContentMessageH\x00R\x16extendedContentMessage\x12\\\n" +
+	"\fravenMessage\x18\x05 \x01(\v26.WAArmadilloApplication.Armadillo.Content.RavenMessageH\x00R\fravenMessage\x12}\n" +
+	"\x17ravenActionNotifMessage\x18\x06 \x01(\v2A.WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessageH\x00R\x17ravenActionNotifMessage\x12\x92\x01\n" +
+	"\x1eextendedMessageContentWithSear\x18\a \x01(\v2H.WAArmadilloApplication.Armadillo.Content.ExtendedContentMessageWithSearH\x00R\x1eextendedMessageContentWithSear\x12q\n" +
+	"\x13imageGalleryMessage\x18\b \x01(\v2=.WAArmadilloApplication.Armadillo.Content.ImageGalleryMessageH\x00R\x13imageGalleryMessage\x12\x86\x01\n" +
+	"\x1apaymentsTransactionMessage\x18\n" +
+	" \x01(\v2D.WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessageH\x00R\x1apaymentsTransactionMessage\x12q\n" +
+	"\x13bumpExistingMessage\x18\v \x01(\v2=.WAArmadilloApplication.Armadillo.Content.BumpExistingMessageH\x00R\x13bumpExistingMessage\x12h\n" +
+	"\x10noteReplyMessage\x18\r \x01(\v2:.WAArmadilloApplication.Armadillo.Content.NoteReplyMessageH\x00R\x10noteReplyMessage\x12d\n" +
+	"\x10ravenMessageMsgr\x18\x0e \x01(\v26.WAArmadilloApplication.Armadillo.Content.RavenMessageH\x00R\x10ravenMessageMsgr\x12\x86\x01\n" +
+	"\x1anetworkVerificationMessage\x18\x0f \x01(\v2D.WAArmadilloApplication.Armadillo.Content.NetworkVerificationMessageH\x00R\x1anetworkVerificationMessage\x1a\xba\a\n" +
+	"\x1aPaymentsTransactionMessage\x12$\n" +
+	"\rtransactionID\x18\x01 \x01(\x04R\rtransactionID\x12\x16\n" +
+	"\x06amount\x18\x02 \x01(\tR\x06amount\x12\x1a\n" +
+	"\bcurrency\x18\x03 \x01(\tR\bcurrency\x12x\n" +
+	"\rpaymentStatus\x18\x04 \x01(\x0e2R.WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessage.PaymentStatusR\rpaymentStatus\x12^\n" +
+	"\x16extendedContentMessage\x18\x05 \x01(\v2&.WAArmadilloXMA.ExtendedContentMessageR\x16extendedContentMessage\"\xe7\x04\n" +
+	"\rPaymentStatus\x12\x13\n" +
+	"\x0fPAYMENT_UNKNOWN\x10\x00\x12\x12\n" +
+	"\x0eREQUEST_INITED\x10\x04\x12\x14\n" +
+	"\x10REQUEST_DECLINED\x10\x05\x12\x1b\n" +
+	"\x17REQUEST_TRANSFER_INITED\x10\x06\x12\x1e\n" +
+	"\x1aREQUEST_TRANSFER_COMPLETED\x10\a\x12\x1b\n" +
+	"\x17REQUEST_TRANSFER_FAILED\x10\b\x12\x14\n" +
+	"\x10REQUEST_CANCELED\x10\t\x12\x13\n" +
+	"\x0fREQUEST_EXPIRED\x10\n" +
+	"\x12\x13\n" +
+	"\x0fTRANSFER_INITED\x10\v\x12\x14\n" +
+	"\x10TRANSFER_PENDING\x10\f\x12+\n" +
+	"'TRANSFER_PENDING_RECIPIENT_VERIFICATION\x10\r\x12\x15\n" +
+	"\x11TRANSFER_CANCELED\x10\x0e\x12\x16\n" +
+	"\x12TRANSFER_COMPLETED\x10\x0f\x12;\n" +
+	"7TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_CANCELED\x10\x10\x128\n" +
+	"4TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_OTHER\x10\x11\x12\x15\n" +
+	"\x11TRANSFER_REFUNDED\x10\x12\x12\x1b\n" +
+	"\x17TRANSFER_PARTIAL_REFUND\x10\x13\x12\x19\n" +
+	"\x15TRANSFER_CHARGED_BACK\x10\x14\x12\x14\n" +
+	"\x10TRANSFER_EXPIRED\x10\x15\x12\x15\n" +
+	"\x11TRANSFER_DECLINED\x10\x16\x12\x18\n" +
+	"\x14TRANSFER_UNAVAILABLE\x10\x17\x1a8\n" +
+	"\x1aNetworkVerificationMessage\x12\x1a\n" +
+	"\bcodeText\x18\x01 \x01(\tR\bcodeText\x1a\xd4\x02\n" +
+	"\x10NoteReplyMessage\x129\n" +
+	"\vtextContent\x18\x04 \x01(\v2\x15.WACommon.MessageTextH\x00R\vtextContent\x12?\n" +
+	"\x0estickerContent\x18\x05 \x01(\v2\x15.WACommon.SubProtocolH\x00R\x0estickerContent\x12;\n" +
+	"\fvideoContent\x18\x06 \x01(\v2\x15.WACommon.SubProtocolH\x00R\fvideoContent\x12\x16\n" +
+	"\x06noteID\x18\x01 \x01(\tR\x06noteID\x121\n" +
+	"\bnoteText\x18\x02 \x01(\v2\x15.WACommon.MessageTextR\bnoteText\x12(\n" +
+	"\x0fnoteTimestampMS\x18\x03 \x01(\x03R\x0fnoteTimestampMSB\x12\n" +
+	"\x10noteReplyContent\x1a=\n" +
+	"\x13BumpExistingMessage\x12&\n" +
+	"\x03key\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\x03key\x1aD\n" +
+	"\x13ImageGalleryMessage\x12-\n" +
+	"\x06images\x18\x01 \x03(\v2\x15.WACommon.SubProtocolR\x06images\x1a\xc3\x01\n" +
+	"\x10ScreenshotAction\x12q\n" +
+	"\x0escreenshotType\x18\x01 \x01(\x0e2I.WAArmadilloApplication.Armadillo.Content.ScreenshotAction.ScreenshotTypeR\x0escreenshotType\"<\n" +
+	"\x0eScreenshotType\x12\x14\n" +
+	"\x10SCREENSHOT_IMAGE\x10\x01\x12\x14\n" +
+	"\x10SCREEN_RECORDING\x10\x02\x1a\xf3\x01\n" +
+	"\x1eExtendedContentMessageWithSear\x12\x16\n" +
+	"\x06searID\x18\x01 \x01(\tR\x06searID\x12\x18\n" +
+	"\apayload\x18\x02 \x01(\fR\apayload\x12\x1c\n" +
+	"\tnativeURL\x18\x03 \x01(\tR\tnativeURL\x12K\n" +
+	"\x15searAssociatedMessage\x18\x04 \x01(\v2\x15.WACommon.SubProtocolR\x15searAssociatedMessage\x124\n" +
+	"\x15searSentWithMessageID\x18\x05 \x01(\tR\x15searSentWithMessageID\x1a\x96\x02\n" +
+	"\x17RavenActionNotifMessage\x12&\n" +
+	"\x03key\x18\x01 \x01(\v2\x14.WACommon.MessageKeyR\x03key\x12(\n" +
+	"\x0factionTimestamp\x18\x02 \x01(\x03R\x0factionTimestamp\x12l\n" +
+	"\n" +
+	"actionType\x18\x03 \x01(\x0e2L.WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessage.ActionTypeR\n" +
+	"actionType\";\n" +
+	"\n" +
+	"ActionType\x12\n" +
+	"\n" +
+	"\x06PLAYED\x10\x00\x12\x0e\n" +
+	"\n" +
+	"SCREENSHOT\x10\x01\x12\x11\n" +
+	"\rFORCE_DISABLE\x10\x02\x1a\xc8\x02\n" +
+	"\fRavenMessage\x12;\n" +
+	"\fimageMessage\x18\x02 \x01(\v2\x15.WACommon.SubProtocolH\x00R\fimageMessage\x12;\n" +
+	"\fvideoMessage\x18\x03 \x01(\v2\x15.WACommon.SubProtocolH\x00R\fvideoMessage\x12j\n" +
+	"\rephemeralType\x18\x01 \x01(\x0e2D.WAArmadilloApplication.Armadillo.Content.RavenMessage.EphemeralTypeR\rephemeralType\"B\n" +
+	"\rEphemeralType\x12\r\n" +
+	"\tVIEW_ONCE\x10\x00\x12\x10\n" +
+	"\fALLOW_REPLAY\x10\x01\x12\x10\n" +
+	"\fKEEP_IN_CHAT\x10\x02B\x0e\n" +
+	"\fmediaContent\x1a\xb6\x01\n" +
+	"\rCommonSticker\x12e\n" +
+	"\vstickerType\x18\x01 \x01(\x0e2C.WAArmadilloApplication.Armadillo.Content.CommonSticker.StickerTypeR\vstickerType\">\n" +
+	"\vStickerType\x12\x0e\n" +
+	"\n" +
+	"SMALL_LIKE\x10\x01\x12\x0f\n" +
+	"\vMEDIUM_LIKE\x10\x02\x12\x0e\n" +
+	"\n" +
+	"LARGE_LIKE\x10\x03B\t\n" +
+	"\acontentB2Z0go.mau.fi/whatsmeow/proto/waArmadilloApplication"
+
+var (
+	file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescOnce sync.Once
+	file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescData []byte
+)
+
+func file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescGZIP() []byte {
+	file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescOnce.Do(func() {
+		file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_waArmadilloApplication_WAArmadilloApplication_proto_rawDesc), len(file_waArmadilloApplication_WAArmadilloApplication_proto_rawDesc)))
+	})
+	return file_waArmadilloApplication_WAArmadilloApplication_proto_rawDescData
+}
+
+var file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes = make([]protoimpl.EnumInfo, 8)
+var file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes = make([]protoimpl.MessageInfo, 33)
+var file_waArmadilloApplication_WAArmadilloApplication_proto_goTypes = []any{
+	(Armadillo_Signal_EncryptedBackupsSecrets_Epoch_EpochStatus)(0),                                     // 0: WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.Epoch.EpochStatus
+	(Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction_InterventionType)(0), // 1: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionAction.InterventionType
+	(Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction_SpectraActionType)(0),               // 2: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraAction.SpectraActionType
+	(Armadillo_Content_PaymentsTransactionMessage_PaymentStatus)(0),                                     // 3: WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessage.PaymentStatus
+	(Armadillo_Content_ScreenshotAction_ScreenshotType)(0),                                              // 4: WAArmadilloApplication.Armadillo.Content.ScreenshotAction.ScreenshotType
+	(Armadillo_Content_RavenActionNotifMessage_ActionType)(0),                                           // 5: WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessage.ActionType
+	(Armadillo_Content_RavenMessage_EphemeralType)(0),                                                   // 6: WAArmadilloApplication.Armadillo.Content.RavenMessage.EphemeralType
+	(Armadillo_Content_CommonSticker_StickerType)(0),                                                    // 7: WAArmadilloApplication.Armadillo.Content.CommonSticker.StickerType
+	(*Armadillo)(nil),                                                                          // 8: WAArmadilloApplication.Armadillo
+	(*Armadillo_Metadata)(nil),                                                                 // 9: WAArmadilloApplication.Armadillo.Metadata
+	(*Armadillo_Payload)(nil),                                                                  // 10: WAArmadilloApplication.Armadillo.Payload
+	(*Armadillo_SubProtocolPayload)(nil),                                                       // 11: WAArmadilloApplication.Armadillo.SubProtocolPayload
+	(*Armadillo_Signal)(nil),                                                                   // 12: WAArmadilloApplication.Armadillo.Signal
+	(*Armadillo_ApplicationData)(nil),                                                          // 13: WAArmadilloApplication.Armadillo.ApplicationData
+	(*Armadillo_Content)(nil),                                                                  // 14: WAArmadilloApplication.Armadillo.Content
+	(*Armadillo_Signal_EncryptedBackupsSecrets)(nil),                                           // 15: WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets
+	(*Armadillo_Signal_EncryptedBackupsSecrets_Epoch)(nil),                                     // 16: WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.Epoch
+	(*Armadillo_ApplicationData_MessageHistoryDocumentMessage)(nil),                            // 17: WAArmadilloApplication.Armadillo.ApplicationData.MessageHistoryDocumentMessage
+	(*Armadillo_ApplicationData_AIBotResponseMessage)(nil),                                     // 18: WAArmadilloApplication.Armadillo.ApplicationData.AIBotResponseMessage
+	(*Armadillo_ApplicationData_MetadataSyncAction)(nil),                                       // 19: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction
+	(*Armadillo_ApplicationData_MetadataSyncNotification)(nil),                                 // 20: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncNotification
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncAttachmentInterventionAction)(nil),      // 21: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionAction
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncSpectraAction)(nil),                     // 22: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraAction
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction)(nil),                     // 23: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageAction
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction)(nil),                        // 24: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessage)(nil),                     // 25: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessage
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncActionMessageRange)(nil),                // 26: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRange
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_ActionMessageDelete)(nil), // 27: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageAction.ActionMessageDelete
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatRead)(nil),         // 28: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatRead
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatDelete)(nil),       // 29: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatDelete
+	(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ActionChatArchive)(nil),      // 30: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatArchive
+	(*Armadillo_Content_PaymentsTransactionMessage)(nil),                                       // 31: WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessage
+	(*Armadillo_Content_NetworkVerificationMessage)(nil),                                       // 32: WAArmadilloApplication.Armadillo.Content.NetworkVerificationMessage
+	(*Armadillo_Content_NoteReplyMessage)(nil),                                                 // 33: WAArmadilloApplication.Armadillo.Content.NoteReplyMessage
+	(*Armadillo_Content_BumpExistingMessage)(nil),                                              // 34: WAArmadilloApplication.Armadillo.Content.BumpExistingMessage
+	(*Armadillo_Content_ImageGalleryMessage)(nil),                                              // 35: WAArmadilloApplication.Armadillo.Content.ImageGalleryMessage
+	(*Armadillo_Content_ScreenshotAction)(nil),                                                 // 36: WAArmadilloApplication.Armadillo.Content.ScreenshotAction
+	(*Armadillo_Content_ExtendedContentMessageWithSear)(nil),                                   // 37: WAArmadilloApplication.Armadillo.Content.ExtendedContentMessageWithSear
+	(*Armadillo_Content_RavenActionNotifMessage)(nil),                                          // 38: WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessage
+	(*Armadillo_Content_RavenMessage)(nil),                                                     // 39: WAArmadilloApplication.Armadillo.Content.RavenMessage
+	(*Armadillo_Content_CommonSticker)(nil),                                                    // 40: WAArmadilloApplication.Armadillo.Content.CommonSticker
+	(waCommon.FutureProofBehavior)(0),                                                          // 41: WACommon.FutureProofBehavior
+	(*waArmadilloXMA.ExtendedContentMessage)(nil),                                              // 42: WAArmadilloXMA.ExtendedContentMessage
+	(*waCommon.SubProtocol)(nil),                                                               // 43: WACommon.SubProtocol
+	(*waCommon.MessageKey)(nil),                                                                // 44: WACommon.MessageKey
+	(*waCommon.MessageText)(nil),                                                               // 45: WACommon.MessageText
+}
+var file_waArmadilloApplication_WAArmadilloApplication_proto_depIdxs = []int32{
+	10, // 0: WAArmadilloApplication.Armadillo.payload:type_name -> WAArmadilloApplication.Armadillo.Payload
+	9,  // 1: WAArmadilloApplication.Armadillo.metadata:type_name -> WAArmadilloApplication.Armadillo.Metadata
+	14, // 2: WAArmadilloApplication.Armadillo.Payload.content:type_name -> WAArmadilloApplication.Armadillo.Content
+	13, // 3: WAArmadilloApplication.Armadillo.Payload.applicationData:type_name -> WAArmadilloApplication.Armadillo.ApplicationData
+	12, // 4: WAArmadilloApplication.Armadillo.Payload.signal:type_name -> WAArmadilloApplication.Armadillo.Signal
+	11, // 5: WAArmadilloApplication.Armadillo.Payload.subProtocol:type_name -> WAArmadilloApplication.Armadillo.SubProtocolPayload
+	41, // 6: WAArmadilloApplication.Armadillo.SubProtocolPayload.futureProof:type_name -> WACommon.FutureProofBehavior
+	15, // 7: WAArmadilloApplication.Armadillo.Signal.encryptedBackupsSecrets:type_name -> WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets
+	20, // 8: WAArmadilloApplication.Armadillo.ApplicationData.metadataSync:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncNotification
+	18, // 9: WAArmadilloApplication.Armadillo.ApplicationData.aiBotResponse:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.AIBotResponseMessage
+	17, // 10: WAArmadilloApplication.Armadillo.ApplicationData.messageHistoryDocumentMessage:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MessageHistoryDocumentMessage
+	40, // 11: WAArmadilloApplication.Armadillo.Content.commonSticker:type_name -> WAArmadilloApplication.Armadillo.Content.CommonSticker
+	36, // 12: WAArmadilloApplication.Armadillo.Content.screenshotAction:type_name -> WAArmadilloApplication.Armadillo.Content.ScreenshotAction
+	42, // 13: WAArmadilloApplication.Armadillo.Content.extendedContentMessage:type_name -> WAArmadilloXMA.ExtendedContentMessage
+	39, // 14: WAArmadilloApplication.Armadillo.Content.ravenMessage:type_name -> WAArmadilloApplication.Armadillo.Content.RavenMessage
+	38, // 15: WAArmadilloApplication.Armadillo.Content.ravenActionNotifMessage:type_name -> WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessage
+	37, // 16: WAArmadilloApplication.Armadillo.Content.extendedMessageContentWithSear:type_name -> WAArmadilloApplication.Armadillo.Content.ExtendedContentMessageWithSear
+	35, // 17: WAArmadilloApplication.Armadillo.Content.imageGalleryMessage:type_name -> WAArmadilloApplication.Armadillo.Content.ImageGalleryMessage
+	31, // 18: WAArmadilloApplication.Armadillo.Content.paymentsTransactionMessage:type_name -> WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessage
+	34, // 19: WAArmadilloApplication.Armadillo.Content.bumpExistingMessage:type_name -> WAArmadilloApplication.Armadillo.Content.BumpExistingMessage
+	33, // 20: WAArmadilloApplication.Armadillo.Content.noteReplyMessage:type_name -> WAArmadilloApplication.Armadillo.Content.NoteReplyMessage
+	39, // 21: WAArmadilloApplication.Armadillo.Content.ravenMessageMsgr:type_name -> WAArmadilloApplication.Armadillo.Content.RavenMessage
+	32, // 22: WAArmadilloApplication.Armadillo.Content.networkVerificationMessage:type_name -> WAArmadilloApplication.Armadillo.Content.NetworkVerificationMessage
+	16, // 23: WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.epoch:type_name -> WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.Epoch
+	0,  // 24: WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.Epoch.status:type_name -> WAArmadilloApplication.Armadillo.Signal.EncryptedBackupsSecrets.Epoch.EpochStatus
+	43, // 25: WAArmadilloApplication.Armadillo.ApplicationData.MessageHistoryDocumentMessage.document:type_name -> WACommon.SubProtocol
+	24, // 26: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.chatAction:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction
+	23, // 27: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.messageAction:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageAction
+	22, // 28: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.spectraAction:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraAction
+	21, // 29: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.attachmentInterventionAction:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionAction
+	19, // 30: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncNotification.actions:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction
+	44, // 31: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionAction.messageKey:type_name -> WACommon.MessageKey
+	1,  // 32: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionAction.interventionType:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncAttachmentInterventionAction.InterventionType
+	44, // 33: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraAction.key:type_name -> WACommon.MessageKey
+	2,  // 34: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraAction.actionType:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncSpectraAction.SpectraActionType
+	27, // 35: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageAction.messageDelete:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageAction.ActionMessageDelete
+	44, // 36: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncMessageAction.key:type_name -> WACommon.MessageKey
+	30, // 37: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.chatArchive:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatArchive
+	29, // 38: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.chatDelete:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatDelete
+	28, // 39: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.chatRead:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatRead
+	44, // 40: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessage.key:type_name -> WACommon.MessageKey
+	25, // 41: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRange.messages:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessage
+	26, // 42: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatRead.messageRange:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRange
+	26, // 43: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatDelete.messageRange:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRange
+	26, // 44: WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncChatAction.ActionChatArchive.messageRange:type_name -> WAArmadilloApplication.Armadillo.ApplicationData.MetadataSyncAction.SyncActionMessageRange
+	3,  // 45: WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessage.paymentStatus:type_name -> WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessage.PaymentStatus
+	42, // 46: WAArmadilloApplication.Armadillo.Content.PaymentsTransactionMessage.extendedContentMessage:type_name -> WAArmadilloXMA.ExtendedContentMessage
+	45, // 47: WAArmadilloApplication.Armadillo.Content.NoteReplyMessage.textContent:type_name -> WACommon.MessageText
+	43, // 48: WAArmadilloApplication.Armadillo.Content.NoteReplyMessage.stickerContent:type_name -> WACommon.SubProtocol
+	43, // 49: WAArmadilloApplication.Armadillo.Content.NoteReplyMessage.videoContent:type_name -> WACommon.SubProtocol
+	45, // 50: WAArmadilloApplication.Armadillo.Content.NoteReplyMessage.noteText:type_name -> WACommon.MessageText
+	44, // 51: WAArmadilloApplication.Armadillo.Content.BumpExistingMessage.key:type_name -> WACommon.MessageKey
+	43, // 52: WAArmadilloApplication.Armadillo.Content.ImageGalleryMessage.images:type_name -> WACommon.SubProtocol
+	4,  // 53: WAArmadilloApplication.Armadillo.Content.ScreenshotAction.screenshotType:type_name -> WAArmadilloApplication.Armadillo.Content.ScreenshotAction.ScreenshotType
+	43, // 54: WAArmadilloApplication.Armadillo.Content.ExtendedContentMessageWithSear.searAssociatedMessage:type_name -> WACommon.SubProtocol
+	44, // 55: WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessage.key:type_name -> WACommon.MessageKey
+	5,  // 56: WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessage.actionType:type_name -> WAArmadilloApplication.Armadillo.Content.RavenActionNotifMessage.ActionType
+	43, // 57: WAArmadilloApplication.Armadillo.Content.RavenMessage.imageMessage:type_name -> WACommon.SubProtocol
+	43, // 58: WAArmadilloApplication.Armadillo.Content.RavenMessage.videoMessage:type_name -> WACommon.SubProtocol
+	6,  // 59: WAArmadilloApplication.Armadillo.Content.RavenMessage.ephemeralType:type_name -> WAArmadilloApplication.Armadillo.Content.RavenMessage.EphemeralType
+	7,  // 60: WAArmadilloApplication.Armadillo.Content.CommonSticker.stickerType:type_name -> WAArmadilloApplication.Armadillo.Content.CommonSticker.StickerType
+	61, // [61:61] is the sub-list for method output_type
+	61, // [61:61] is the sub-list for method input_type
+	61, // [61:61] is the sub-list for extension type_name
+	61, // [61:61] is the sub-list for extension extendee
+	0,  // [0:61] is the sub-list for field type_name
+}
+
+func init() { file_waArmadilloApplication_WAArmadilloApplication_proto_init() }
+func file_waArmadilloApplication_WAArmadilloApplication_proto_init() {
+	if File_waArmadilloApplication_WAArmadilloApplication_proto != nil {
+		return
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[2].OneofWrappers = []any{
+		(*Armadillo_Payload_Content)(nil),
+		(*Armadillo_Payload_ApplicationData)(nil),
+		(*Armadillo_Payload_Signal)(nil),
+		(*Armadillo_Payload_SubProtocol)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[4].OneofWrappers = []any{
+		(*Armadillo_Signal_EncryptedBackupsSecrets_)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[5].OneofWrappers = []any{
+		(*Armadillo_ApplicationData_MetadataSync)(nil),
+		(*Armadillo_ApplicationData_AiBotResponse)(nil),
+		(*Armadillo_ApplicationData_MessageHistoryDocumentMessage_)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[6].OneofWrappers = []any{
+		(*Armadillo_Content_CommonSticker_)(nil),
+		(*Armadillo_Content_ScreenshotAction_)(nil),
+		(*Armadillo_Content_ExtendedContentMessage)(nil),
+		(*Armadillo_Content_RavenMessage_)(nil),
+		(*Armadillo_Content_RavenActionNotifMessage_)(nil),
+		(*Armadillo_Content_ExtendedMessageContentWithSear)(nil),
+		(*Armadillo_Content_ImageGalleryMessage_)(nil),
+		(*Armadillo_Content_PaymentsTransactionMessage_)(nil),
+		(*Armadillo_Content_BumpExistingMessage_)(nil),
+		(*Armadillo_Content_NoteReplyMessage_)(nil),
+		(*Armadillo_Content_RavenMessageMsgr)(nil),
+		(*Armadillo_Content_NetworkVerificationMessage_)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[11].OneofWrappers = []any{
+		(*Armadillo_ApplicationData_MetadataSyncAction_ChatAction)(nil),
+		(*Armadillo_ApplicationData_MetadataSyncAction_MessageAction)(nil),
+		(*Armadillo_ApplicationData_MetadataSyncAction_SpectraAction)(nil),
+		(*Armadillo_ApplicationData_MetadataSyncAction_AttachmentInterventionAction)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[15].OneofWrappers = []any{
+		(*Armadillo_ApplicationData_MetadataSyncAction_SyncMessageAction_MessageDelete)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[16].OneofWrappers = []any{
+		(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatArchive)(nil),
+		(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatDelete)(nil),
+		(*Armadillo_ApplicationData_MetadataSyncAction_SyncChatAction_ChatRead)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[25].OneofWrappers = []any{
+		(*Armadillo_Content_NoteReplyMessage_TextContent)(nil),
+		(*Armadillo_Content_NoteReplyMessage_StickerContent)(nil),
+		(*Armadillo_Content_NoteReplyMessage_VideoContent)(nil),
+	}
+	file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes[31].OneofWrappers = []any{
+		(*Armadillo_Content_RavenMessage_ImageMessage)(nil),
+		(*Armadillo_Content_RavenMessage_VideoMessage)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_waArmadilloApplication_WAArmadilloApplication_proto_rawDesc), len(file_waArmadilloApplication_WAArmadilloApplication_proto_rawDesc)),
+			NumEnums:      8,
+			NumMessages:   33,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_waArmadilloApplication_WAArmadilloApplication_proto_goTypes,
+		DependencyIndexes: file_waArmadilloApplication_WAArmadilloApplication_proto_depIdxs,
+		EnumInfos:         file_waArmadilloApplication_WAArmadilloApplication_proto_enumTypes,
+		MessageInfos:      file_waArmadilloApplication_WAArmadilloApplication_proto_msgTypes,
+	}.Build()
+	File_waArmadilloApplication_WAArmadilloApplication_proto = out.File
+	file_waArmadilloApplication_WAArmadilloApplication_proto_goTypes = nil
+	file_waArmadilloApplication_WAArmadilloApplication_proto_depIdxs = nil
+}

+ 283 - 0
proto/waArmadilloApplication/WAArmadilloApplication.proto

@@ -0,0 +1,283 @@
+syntax = "proto2";
+package WAArmadilloApplication;
+option go_package = "go.mau.fi/whatsmeow/proto/waArmadilloApplication";
+
+import "waArmadilloXMA/WAArmadilloXMA.proto";
+import "waCommon/WACommon.proto";
+
+message Armadillo {
+	message Metadata {
+	}
+
+	message Payload {
+		oneof payload {
+			Content content = 1;
+			ApplicationData applicationData = 2;
+			Signal signal = 3;
+			SubProtocolPayload subProtocol = 4;
+		}
+	}
+
+	message SubProtocolPayload {
+		optional WACommon.FutureProofBehavior futureProof = 1;
+	}
+
+	message Signal {
+		message EncryptedBackupsSecrets {
+			message Epoch {
+				enum EpochStatus {
+					ES_OPEN = 1;
+					ES_CLOSE = 2;
+				}
+
+				optional uint64 ID = 1;
+				optional bytes anonID = 2;
+				optional bytes rootKey = 3;
+				optional EpochStatus status = 4;
+			}
+
+			optional uint64 backupID = 1;
+			optional uint64 serverDataID = 2;
+			repeated Epoch epoch = 3;
+			optional bytes tempOcmfClientState = 4;
+			optional bytes mailboxRootKey = 5;
+			optional bytes obliviousValidationToken = 6;
+		}
+
+		oneof signal {
+			EncryptedBackupsSecrets encryptedBackupsSecrets = 1;
+		}
+	}
+
+	message ApplicationData {
+		message MessageHistoryDocumentMessage {
+			optional WACommon.SubProtocol document = 1;
+		}
+
+		message AIBotResponseMessage {
+			optional string summonToken = 1;
+			optional string messageText = 2;
+			optional string serializedExtras = 3;
+		}
+
+		message MetadataSyncAction {
+			message SyncAttachmentInterventionAction {
+				enum InterventionType {
+					UNKNOWN = 0;
+					NUDE = 1;
+					NOT_NUDE = 2;
+				}
+
+				optional WACommon.MessageKey messageKey = 1;
+				optional InterventionType interventionType = 2;
+			}
+
+			message SyncSpectraAction {
+				enum SpectraActionType {
+					TAKEDOWN = 0;
+					RESTORE = 1;
+				}
+
+				optional WACommon.MessageKey key = 1;
+				optional SpectraActionType actionType = 2;
+				optional int64 takedownActionID = 3;
+				optional string config = 4;
+			}
+
+			message SyncMessageAction {
+				message ActionMessageDelete {
+				}
+
+				oneof action {
+					ActionMessageDelete messageDelete = 101;
+				}
+
+				optional WACommon.MessageKey key = 1;
+			}
+
+			message SyncChatAction {
+				message ActionChatRead {
+					optional SyncActionMessageRange messageRange = 1;
+					optional bool read = 2;
+				}
+
+				message ActionChatDelete {
+					optional SyncActionMessageRange messageRange = 1;
+				}
+
+				message ActionChatArchive {
+					optional SyncActionMessageRange messageRange = 1;
+					optional bool archived = 2;
+				}
+
+				oneof action {
+					ActionChatArchive chatArchive = 101;
+					ActionChatDelete chatDelete = 102;
+					ActionChatRead chatRead = 103;
+				}
+
+				optional string chatID = 1;
+			}
+
+			message SyncActionMessage {
+				optional WACommon.MessageKey key = 1;
+				optional int64 timestamp = 2;
+			}
+
+			message SyncActionMessageRange {
+				optional int64 lastMessageTimestamp = 1;
+				optional int64 lastSystemMessageTimestamp = 2;
+				repeated SyncActionMessage messages = 3;
+			}
+
+			oneof actionType {
+				SyncChatAction chatAction = 101;
+				SyncMessageAction messageAction = 102;
+				SyncSpectraAction spectraAction = 103;
+				SyncAttachmentInterventionAction attachmentInterventionAction = 104;
+			}
+
+			optional int64 actionTimestamp = 1;
+		}
+
+		message MetadataSyncNotification {
+			repeated MetadataSyncAction actions = 2;
+		}
+
+		oneof applicationData {
+			MetadataSyncNotification metadataSync = 1;
+			AIBotResponseMessage aiBotResponse = 2;
+			MessageHistoryDocumentMessage messageHistoryDocumentMessage = 3;
+		}
+	}
+
+	message Content {
+		message PaymentsTransactionMessage {
+			enum PaymentStatus {
+				PAYMENT_UNKNOWN = 0;
+				REQUEST_INITED = 4;
+				REQUEST_DECLINED = 5;
+				REQUEST_TRANSFER_INITED = 6;
+				REQUEST_TRANSFER_COMPLETED = 7;
+				REQUEST_TRANSFER_FAILED = 8;
+				REQUEST_CANCELED = 9;
+				REQUEST_EXPIRED = 10;
+				TRANSFER_INITED = 11;
+				TRANSFER_PENDING = 12;
+				TRANSFER_PENDING_RECIPIENT_VERIFICATION = 13;
+				TRANSFER_CANCELED = 14;
+				TRANSFER_COMPLETED = 15;
+				TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_CANCELED = 16;
+				TRANSFER_NO_RECEIVER_CREDENTIAL_NO_RTS_PENDING_OTHER = 17;
+				TRANSFER_REFUNDED = 18;
+				TRANSFER_PARTIAL_REFUND = 19;
+				TRANSFER_CHARGED_BACK = 20;
+				TRANSFER_EXPIRED = 21;
+				TRANSFER_DECLINED = 22;
+				TRANSFER_UNAVAILABLE = 23;
+			}
+
+			optional uint64 transactionID = 1;
+			optional string amount = 2;
+			optional string currency = 3;
+			optional PaymentStatus paymentStatus = 4;
+			optional WAArmadilloXMA.ExtendedContentMessage extendedContentMessage = 5;
+		}
+
+		message NetworkVerificationMessage {
+			optional string codeText = 1;
+		}
+
+		message NoteReplyMessage {
+			oneof noteReplyContent {
+				WACommon.MessageText textContent = 4;
+				WACommon.SubProtocol stickerContent = 5;
+				WACommon.SubProtocol videoContent = 6;
+			}
+
+			optional string noteID = 1;
+			optional WACommon.MessageText noteText = 2;
+			optional int64 noteTimestampMS = 3;
+		}
+
+		message BumpExistingMessage {
+			optional WACommon.MessageKey key = 1;
+		}
+
+		message ImageGalleryMessage {
+			repeated WACommon.SubProtocol images = 1;
+		}
+
+		message ScreenshotAction {
+			enum ScreenshotType {
+				SCREENSHOT_IMAGE = 1;
+				SCREEN_RECORDING = 2;
+			}
+
+			optional ScreenshotType screenshotType = 1;
+		}
+
+		message ExtendedContentMessageWithSear {
+			optional string searID = 1;
+			optional bytes payload = 2;
+			optional string nativeURL = 3;
+			optional WACommon.SubProtocol searAssociatedMessage = 4;
+			optional string searSentWithMessageID = 5;
+		}
+
+		message RavenActionNotifMessage {
+			enum ActionType {
+				PLAYED = 0;
+				SCREENSHOT = 1;
+				FORCE_DISABLE = 2;
+			}
+
+			optional WACommon.MessageKey key = 1;
+			optional int64 actionTimestamp = 2;
+			optional ActionType actionType = 3;
+		}
+
+		message RavenMessage {
+			enum EphemeralType {
+				VIEW_ONCE = 0;
+				ALLOW_REPLAY = 1;
+				KEEP_IN_CHAT = 2;
+			}
+
+			oneof mediaContent {
+				WACommon.SubProtocol imageMessage = 2;
+				WACommon.SubProtocol videoMessage = 3;
+			}
+
+			optional EphemeralType ephemeralType = 1;
+		}
+
+		message CommonSticker {
+			enum StickerType {
+				SMALL_LIKE = 1;
+				MEDIUM_LIKE = 2;
+				LARGE_LIKE = 3;
+			}
+
+			optional StickerType stickerType = 1;
+		}
+
+		oneof content {
+			CommonSticker commonSticker = 1;
+			ScreenshotAction screenshotAction = 3;
+			WAArmadilloXMA.ExtendedContentMessage extendedContentMessage = 4;
+			RavenMessage ravenMessage = 5;
+			RavenActionNotifMessage ravenActionNotifMessage = 6;
+			ExtendedContentMessageWithSear extendedMessageContentWithSear = 7;
+			ImageGalleryMessage imageGalleryMessage = 8;
+			PaymentsTransactionMessage paymentsTransactionMessage = 10;
+			BumpExistingMessage bumpExistingMessage = 11;
+			NoteReplyMessage noteReplyMessage = 13;
+			RavenMessage ravenMessageMsgr = 14;
+			NetworkVerificationMessage networkVerificationMessage = 15;
+		}
+	}
+
+	optional Payload payload = 1;
+	optional Metadata metadata = 2;
+}

+ 3 - 0
proto/waArmadilloApplication/extra.go

@@ -0,0 +1,3 @@
+package waArmadilloApplication
+
+func (*Armadillo) IsMessageApplicationSub() {}

+ 132 - 0
proto/waArmadilloBackupCommon/WAArmadilloBackupCommon.pb.go

@@ -0,0 +1,132 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: waArmadilloBackupCommon/WAArmadilloBackupCommon.proto
+
+package waArmadilloBackupCommon
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Subprotocol struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Payload       []byte                 `protobuf:"bytes,1,opt,name=payload" json:"payload,omitempty"`
+	Version       *int32                 `protobuf:"varint,2,opt,name=version" json:"version,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Subprotocol) Reset() {
+	*x = Subprotocol{}
+	mi := &file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Subprotocol) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Subprotocol) ProtoMessage() {}
+
+func (x *Subprotocol) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Subprotocol.ProtoReflect.Descriptor instead.
+func (*Subprotocol) Descriptor() ([]byte, []int) {
+	return file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Subprotocol) GetPayload() []byte {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *Subprotocol) GetVersion() int32 {
+	if x != nil && x.Version != nil {
+		return *x.Version
+	}
+	return 0
+}
+
+var File_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto protoreflect.FileDescriptor
+
+const file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDesc = "" +
+	"\n" +
+	"5waArmadilloBackupCommon/WAArmadilloBackupCommon.proto\x12\x17WAArmadilloBackupCommon\"A\n" +
+	"\vSubprotocol\x12\x18\n" +
+	"\apayload\x18\x01 \x01(\fR\apayload\x12\x18\n" +
+	"\aversion\x18\x02 \x01(\x05R\aversionB3Z1go.mau.fi/whatsmeow/proto/waArmadilloBackupCommon"
+
+var (
+	file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDescOnce sync.Once
+	file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDescData []byte
+)
+
+func file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDescGZIP() []byte {
+	file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDescOnce.Do(func() {
+		file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDesc), len(file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDesc)))
+	})
+	return file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDescData
+}
+
+var file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_goTypes = []any{
+	(*Subprotocol)(nil), // 0: WAArmadilloBackupCommon.Subprotocol
+}
+var file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_init() }
+func file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_init() {
+	if File_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDesc), len(file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_goTypes,
+		DependencyIndexes: file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_depIdxs,
+		MessageInfos:      file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_msgTypes,
+	}.Build()
+	File_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto = out.File
+	file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_goTypes = nil
+	file_waArmadilloBackupCommon_WAArmadilloBackupCommon_proto_depIdxs = nil
+}

+ 8 - 0
proto/waArmadilloBackupCommon/WAArmadilloBackupCommon.proto

@@ -0,0 +1,8 @@
+syntax = "proto2";
+package WAArmadilloBackupCommon;
+option go_package = "go.mau.fi/whatsmeow/proto/waArmadilloBackupCommon";
+
+message Subprotocol {
+	optional bytes payload = 1;
+	optional int32 version = 2;
+}

+ 386 - 0
proto/waArmadilloBackupMessage/WAArmadilloBackupMessage.pb.go

@@ -0,0 +1,386 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: waArmadilloBackupMessage/WAArmadilloBackupMessage.proto
+
+package waArmadilloBackupMessage
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+
+	waArmadilloBackupCommon "go.mau.fi/whatsmeow/proto/waArmadilloBackupCommon"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type BackupMessage struct {
+	state protoimpl.MessageState `protogen:"open.v1"`
+	// Types that are valid to be assigned to Payload:
+	//
+	//	*BackupMessage_EncryptedTransportMessage
+	//	*BackupMessage_EncryptedTransportEvent
+	//	*BackupMessage_EncryptedTransportLocallyTransformedMessage
+	//	*BackupMessage_MiTransportAdminMessage
+	Payload       isBackupMessage_Payload `protobuf_oneof:"payload"`
+	Metadata      *BackupMessage_Metadata `protobuf:"bytes,1,opt,name=metadata" json:"metadata,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BackupMessage) Reset() {
+	*x = BackupMessage{}
+	mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BackupMessage) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupMessage) ProtoMessage() {}
+
+func (x *BackupMessage) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupMessage.ProtoReflect.Descriptor instead.
+func (*BackupMessage) Descriptor() ([]byte, []int) {
+	return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *BackupMessage) GetPayload() isBackupMessage_Payload {
+	if x != nil {
+		return x.Payload
+	}
+	return nil
+}
+
+func (x *BackupMessage) GetEncryptedTransportMessage() []byte {
+	if x != nil {
+		if x, ok := x.Payload.(*BackupMessage_EncryptedTransportMessage); ok {
+			return x.EncryptedTransportMessage
+		}
+	}
+	return nil
+}
+
+func (x *BackupMessage) GetEncryptedTransportEvent() *waArmadilloBackupCommon.Subprotocol {
+	if x != nil {
+		if x, ok := x.Payload.(*BackupMessage_EncryptedTransportEvent); ok {
+			return x.EncryptedTransportEvent
+		}
+	}
+	return nil
+}
+
+func (x *BackupMessage) GetEncryptedTransportLocallyTransformedMessage() *waArmadilloBackupCommon.Subprotocol {
+	if x != nil {
+		if x, ok := x.Payload.(*BackupMessage_EncryptedTransportLocallyTransformedMessage); ok {
+			return x.EncryptedTransportLocallyTransformedMessage
+		}
+	}
+	return nil
+}
+
+func (x *BackupMessage) GetMiTransportAdminMessage() *waArmadilloBackupCommon.Subprotocol {
+	if x != nil {
+		if x, ok := x.Payload.(*BackupMessage_MiTransportAdminMessage); ok {
+			return x.MiTransportAdminMessage
+		}
+	}
+	return nil
+}
+
+func (x *BackupMessage) GetMetadata() *BackupMessage_Metadata {
+	if x != nil {
+		return x.Metadata
+	}
+	return nil
+}
+
+type isBackupMessage_Payload interface {
+	isBackupMessage_Payload()
+}
+
+type BackupMessage_EncryptedTransportMessage struct {
+	EncryptedTransportMessage []byte `protobuf:"bytes,2,opt,name=encryptedTransportMessage,oneof"`
+}
+
+type BackupMessage_EncryptedTransportEvent struct {
+	EncryptedTransportEvent *waArmadilloBackupCommon.Subprotocol `protobuf:"bytes,5,opt,name=encryptedTransportEvent,oneof"`
+}
+
+type BackupMessage_EncryptedTransportLocallyTransformedMessage struct {
+	EncryptedTransportLocallyTransformedMessage *waArmadilloBackupCommon.Subprotocol `protobuf:"bytes,6,opt,name=encryptedTransportLocallyTransformedMessage,oneof"`
+}
+
+type BackupMessage_MiTransportAdminMessage struct {
+	MiTransportAdminMessage *waArmadilloBackupCommon.Subprotocol `protobuf:"bytes,7,opt,name=miTransportAdminMessage,oneof"`
+}
+
+func (*BackupMessage_EncryptedTransportMessage) isBackupMessage_Payload() {}
+
+func (*BackupMessage_EncryptedTransportEvent) isBackupMessage_Payload() {}
+
+func (*BackupMessage_EncryptedTransportLocallyTransformedMessage) isBackupMessage_Payload() {}
+
+func (*BackupMessage_MiTransportAdminMessage) isBackupMessage_Payload() {}
+
+type BackupMessage_Metadata struct {
+	state               protoimpl.MessageState                   `protogen:"open.v1"`
+	SenderID            *string                                  `protobuf:"bytes,1,opt,name=senderID" json:"senderID,omitempty"`
+	MessageID           *string                                  `protobuf:"bytes,2,opt,name=messageID" json:"messageID,omitempty"`
+	TimestampMS         *int64                                   `protobuf:"varint,3,opt,name=timestampMS" json:"timestampMS,omitempty"`
+	FrankingMetadata    *BackupMessage_Metadata_FrankingMetadata `protobuf:"bytes,4,opt,name=frankingMetadata" json:"frankingMetadata,omitempty"`
+	PayloadVersion      *int32                                   `protobuf:"varint,5,opt,name=payloadVersion" json:"payloadVersion,omitempty"`
+	FutureProofBehavior *int32                                   `protobuf:"varint,6,opt,name=futureProofBehavior" json:"futureProofBehavior,omitempty"`
+	ThreadTypeTag       *int32                                   `protobuf:"varint,7,opt,name=threadTypeTag" json:"threadTypeTag,omitempty"`
+	ClientTimestampMS   *int64                                   `protobuf:"varint,8,opt,name=clientTimestampMS" json:"clientTimestampMS,omitempty"`
+	unknownFields       protoimpl.UnknownFields
+	sizeCache           protoimpl.SizeCache
+}
+
+func (x *BackupMessage_Metadata) Reset() {
+	*x = BackupMessage_Metadata{}
+	mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BackupMessage_Metadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupMessage_Metadata) ProtoMessage() {}
+
+func (x *BackupMessage_Metadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupMessage_Metadata.ProtoReflect.Descriptor instead.
+func (*BackupMessage_Metadata) Descriptor() ([]byte, []int) {
+	return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *BackupMessage_Metadata) GetSenderID() string {
+	if x != nil && x.SenderID != nil {
+		return *x.SenderID
+	}
+	return ""
+}
+
+func (x *BackupMessage_Metadata) GetMessageID() string {
+	if x != nil && x.MessageID != nil {
+		return *x.MessageID
+	}
+	return ""
+}
+
+func (x *BackupMessage_Metadata) GetTimestampMS() int64 {
+	if x != nil && x.TimestampMS != nil {
+		return *x.TimestampMS
+	}
+	return 0
+}
+
+func (x *BackupMessage_Metadata) GetFrankingMetadata() *BackupMessage_Metadata_FrankingMetadata {
+	if x != nil {
+		return x.FrankingMetadata
+	}
+	return nil
+}
+
+func (x *BackupMessage_Metadata) GetPayloadVersion() int32 {
+	if x != nil && x.PayloadVersion != nil {
+		return *x.PayloadVersion
+	}
+	return 0
+}
+
+func (x *BackupMessage_Metadata) GetFutureProofBehavior() int32 {
+	if x != nil && x.FutureProofBehavior != nil {
+		return *x.FutureProofBehavior
+	}
+	return 0
+}
+
+func (x *BackupMessage_Metadata) GetThreadTypeTag() int32 {
+	if x != nil && x.ThreadTypeTag != nil {
+		return *x.ThreadTypeTag
+	}
+	return 0
+}
+
+func (x *BackupMessage_Metadata) GetClientTimestampMS() int64 {
+	if x != nil && x.ClientTimestampMS != nil {
+		return *x.ClientTimestampMS
+	}
+	return 0
+}
+
+type BackupMessage_Metadata_FrankingMetadata struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	FrankingTag   []byte                 `protobuf:"bytes,3,opt,name=frankingTag" json:"frankingTag,omitempty"`
+	ReportingTag  []byte                 `protobuf:"bytes,4,opt,name=reportingTag" json:"reportingTag,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *BackupMessage_Metadata_FrankingMetadata) Reset() {
+	*x = BackupMessage_Metadata_FrankingMetadata{}
+	mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *BackupMessage_Metadata_FrankingMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupMessage_Metadata_FrankingMetadata) ProtoMessage() {}
+
+func (x *BackupMessage_Metadata_FrankingMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupMessage_Metadata_FrankingMetadata.ProtoReflect.Descriptor instead.
+func (*BackupMessage_Metadata_FrankingMetadata) Descriptor() ([]byte, []int) {
+	return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP(), []int{0, 0, 0}
+}
+
+func (x *BackupMessage_Metadata_FrankingMetadata) GetFrankingTag() []byte {
+	if x != nil {
+		return x.FrankingTag
+	}
+	return nil
+}
+
+func (x *BackupMessage_Metadata_FrankingMetadata) GetReportingTag() []byte {
+	if x != nil {
+		return x.ReportingTag
+	}
+	return nil
+}
+
+var File_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto protoreflect.FileDescriptor
+
+const file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc = "" +
+	"\n" +
+	"7waArmadilloBackupMessage/WAArmadilloBackupMessage.proto\x12\x18WAArmadilloBackupMessage\x1a5waArmadilloBackupCommon/WAArmadilloBackupCommon.proto\"\xd7\a\n" +
+	"\rBackupMessage\x12>\n" +
+	"\x19encryptedTransportMessage\x18\x02 \x01(\fH\x00R\x19encryptedTransportMessage\x12`\n" +
+	"\x17encryptedTransportEvent\x18\x05 \x01(\v2$.WAArmadilloBackupCommon.SubprotocolH\x00R\x17encryptedTransportEvent\x12\x88\x01\n" +
+	"+encryptedTransportLocallyTransformedMessage\x18\x06 \x01(\v2$.WAArmadilloBackupCommon.SubprotocolH\x00R+encryptedTransportLocallyTransformedMessage\x12`\n" +
+	"\x17miTransportAdminMessage\x18\a \x01(\v2$.WAArmadilloBackupCommon.SubprotocolH\x00R\x17miTransportAdminMessage\x12L\n" +
+	"\bmetadata\x18\x01 \x01(\v20.WAArmadilloBackupMessage.BackupMessage.MetadataR\bmetadata\x1a\xdd\x03\n" +
+	"\bMetadata\x12\x1a\n" +
+	"\bsenderID\x18\x01 \x01(\tR\bsenderID\x12\x1c\n" +
+	"\tmessageID\x18\x02 \x01(\tR\tmessageID\x12 \n" +
+	"\vtimestampMS\x18\x03 \x01(\x03R\vtimestampMS\x12m\n" +
+	"\x10frankingMetadata\x18\x04 \x01(\v2A.WAArmadilloBackupMessage.BackupMessage.Metadata.FrankingMetadataR\x10frankingMetadata\x12&\n" +
+	"\x0epayloadVersion\x18\x05 \x01(\x05R\x0epayloadVersion\x120\n" +
+	"\x13futureProofBehavior\x18\x06 \x01(\x05R\x13futureProofBehavior\x12$\n" +
+	"\rthreadTypeTag\x18\a \x01(\x05R\rthreadTypeTag\x12,\n" +
+	"\x11clientTimestampMS\x18\b \x01(\x03R\x11clientTimestampMS\x1aX\n" +
+	"\x10FrankingMetadata\x12 \n" +
+	"\vfrankingTag\x18\x03 \x01(\fR\vfrankingTag\x12\"\n" +
+	"\freportingTag\x18\x04 \x01(\fR\freportingTagB\t\n" +
+	"\apayloadB4Z2go.mau.fi/whatsmeow/proto/waArmadilloBackupMessage"
+
+var (
+	file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescOnce sync.Once
+	file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescData []byte
+)
+
+func file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescGZIP() []byte {
+	file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescOnce.Do(func() {
+		file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc), len(file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc)))
+	})
+	return file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDescData
+}
+
+var file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_goTypes = []any{
+	(*BackupMessage)(nil),                           // 0: WAArmadilloBackupMessage.BackupMessage
+	(*BackupMessage_Metadata)(nil),                  // 1: WAArmadilloBackupMessage.BackupMessage.Metadata
+	(*BackupMessage_Metadata_FrankingMetadata)(nil), // 2: WAArmadilloBackupMessage.BackupMessage.Metadata.FrankingMetadata
+	(*waArmadilloBackupCommon.Subprotocol)(nil),     // 3: WAArmadilloBackupCommon.Subprotocol
+}
+var file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_depIdxs = []int32{
+	3, // 0: WAArmadilloBackupMessage.BackupMessage.encryptedTransportEvent:type_name -> WAArmadilloBackupCommon.Subprotocol
+	3, // 1: WAArmadilloBackupMessage.BackupMessage.encryptedTransportLocallyTransformedMessage:type_name -> WAArmadilloBackupCommon.Subprotocol
+	3, // 2: WAArmadilloBackupMessage.BackupMessage.miTransportAdminMessage:type_name -> WAArmadilloBackupCommon.Subprotocol
+	1, // 3: WAArmadilloBackupMessage.BackupMessage.metadata:type_name -> WAArmadilloBackupMessage.BackupMessage.Metadata
+	2, // 4: WAArmadilloBackupMessage.BackupMessage.Metadata.frankingMetadata:type_name -> WAArmadilloBackupMessage.BackupMessage.Metadata.FrankingMetadata
+	5, // [5:5] is the sub-list for method output_type
+	5, // [5:5] is the sub-list for method input_type
+	5, // [5:5] is the sub-list for extension type_name
+	5, // [5:5] is the sub-list for extension extendee
+	0, // [0:5] is the sub-list for field type_name
+}
+
+func init() { file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_init() }
+func file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_init() {
+	if File_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto != nil {
+		return
+	}
+	file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes[0].OneofWrappers = []any{
+		(*BackupMessage_EncryptedTransportMessage)(nil),
+		(*BackupMessage_EncryptedTransportEvent)(nil),
+		(*BackupMessage_EncryptedTransportLocallyTransformedMessage)(nil),
+		(*BackupMessage_MiTransportAdminMessage)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc), len(file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_goTypes,
+		DependencyIndexes: file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_depIdxs,
+		MessageInfos:      file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_msgTypes,
+	}.Build()
+	File_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto = out.File
+	file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_goTypes = nil
+	file_waArmadilloBackupMessage_WAArmadilloBackupMessage_proto_depIdxs = nil
+}

+ 32 - 0
proto/waArmadilloBackupMessage/WAArmadilloBackupMessage.proto

@@ -0,0 +1,32 @@
+syntax = "proto2";
+package WAArmadilloBackupMessage;
+option go_package = "go.mau.fi/whatsmeow/proto/waArmadilloBackupMessage";
+
+import "waArmadilloBackupCommon/WAArmadilloBackupCommon.proto";
+
+message BackupMessage {
+	message Metadata {
+		message FrankingMetadata {
+			optional bytes frankingTag = 3;
+			optional bytes reportingTag = 4;
+		}
+
+		optional string senderID = 1;
+		optional string messageID = 2;
+		optional int64 timestampMS = 3;
+		optional FrankingMetadata frankingMetadata = 4;
+		optional int32 payloadVersion = 5;
+		optional int32 futureProofBehavior = 6;
+		optional int32 threadTypeTag = 7;
+		optional int64 clientTimestampMS = 8;
+	}
+
+	oneof payload {
+		bytes encryptedTransportMessage = 2;
+		WAArmadilloBackupCommon.Subprotocol encryptedTransportEvent = 5;
+		WAArmadilloBackupCommon.Subprotocol encryptedTransportLocallyTransformedMessage = 6;
+		WAArmadilloBackupCommon.Subprotocol miTransportAdminMessage = 7;
+	}
+
+	optional Metadata metadata = 1;
+}

+ 206 - 0
proto/waArmadilloICDC/WAArmadilloICDC.pb.go

@@ -0,0 +1,206 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.10
+// 	protoc        v3.21.12
+// source: waArmadilloICDC/WAArmadilloICDC.proto
+
+package waArmadilloICDC
+
+import (
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ICDCIdentityList struct {
+	state              protoimpl.MessageState `protogen:"open.v1"`
+	Seq                *int32                 `protobuf:"varint,1,opt,name=seq" json:"seq,omitempty"`
+	Timestamp          *int64                 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"`
+	Devices            [][]byte               `protobuf:"bytes,3,rep,name=devices" json:"devices,omitempty"`
+	SigningDeviceIndex *int32                 `protobuf:"varint,4,opt,name=signingDeviceIndex" json:"signingDeviceIndex,omitempty"`
+	unknownFields      protoimpl.UnknownFields
+	sizeCache          protoimpl.SizeCache
+}
+
+func (x *ICDCIdentityList) Reset() {
+	*x = ICDCIdentityList{}
+	mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ICDCIdentityList) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ICDCIdentityList) ProtoMessage() {}
+
+func (x *ICDCIdentityList) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ICDCIdentityList.ProtoReflect.Descriptor instead.
+func (*ICDCIdentityList) Descriptor() ([]byte, []int) {
+	return file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ICDCIdentityList) GetSeq() int32 {
+	if x != nil && x.Seq != nil {
+		return *x.Seq
+	}
+	return 0
+}
+
+func (x *ICDCIdentityList) GetTimestamp() int64 {
+	if x != nil && x.Timestamp != nil {
+		return *x.Timestamp
+	}
+	return 0
+}
+
+func (x *ICDCIdentityList) GetDevices() [][]byte {
+	if x != nil {
+		return x.Devices
+	}
+	return nil
+}
+
+func (x *ICDCIdentityList) GetSigningDeviceIndex() int32 {
+	if x != nil && x.SigningDeviceIndex != nil {
+		return *x.SigningDeviceIndex
+	}
+	return 0
+}
+
+type SignedICDCIdentityList struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Details       []byte                 `protobuf:"bytes,1,opt,name=details" json:"details,omitempty"`
+	Signature     []byte                 `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *SignedICDCIdentityList) Reset() {
+	*x = SignedICDCIdentityList{}
+	mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *SignedICDCIdentityList) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SignedICDCIdentityList) ProtoMessage() {}
+
+func (x *SignedICDCIdentityList) ProtoReflect() protoreflect.Message {
+	mi := &file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SignedICDCIdentityList.ProtoReflect.Descriptor instead.
+func (*SignedICDCIdentityList) Descriptor() ([]byte, []int) {
+	return file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *SignedICDCIdentityList) GetDetails() []byte {
+	if x != nil {
+		return x.Details
+	}
+	return nil
+}
+
+func (x *SignedICDCIdentityList) GetSignature() []byte {
+	if x != nil {
+		return x.Signature
+	}
+	return nil
+}
+
+var File_waArmadilloICDC_WAArmadilloICDC_proto protoreflect.FileDescriptor
+
+const file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc = "" +
+	"\n" +
+	"%waArmadilloICDC/WAArmadilloICDC.proto\x12\x0fWAArmadilloICDC\"\x8c\x01\n" +
+	"\x10ICDCIdentityList\x12\x10\n" +
+	"\x03seq\x18\x01 \x01(\x05R\x03seq\x12\x1c\n" +
+	"\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\x12\x18\n" +
+	"\adevices\x18\x03 \x03(\fR\adevices\x12.\n" +
+	"\x12signingDeviceIndex\x18\x04 \x01(\x05R\x12signingDeviceIndex\"P\n" +
+	"\x16SignedICDCIdentityList\x12\x18\n" +
+	"\adetails\x18\x01 \x01(\fR\adetails\x12\x1c\n" +
+	"\tsignature\x18\x02 \x01(\fR\tsignatureB+Z)go.mau.fi/whatsmeow/proto/waArmadilloICDC"
+
+var (
+	file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescOnce sync.Once
+	file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescData []byte
+)
+
+func file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescGZIP() []byte {
+	file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescOnce.Do(func() {
+		file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc), len(file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc)))
+	})
+	return file_waArmadilloICDC_WAArmadilloICDC_proto_rawDescData
+}
+
+var file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_waArmadilloICDC_WAArmadilloICDC_proto_goTypes = []any{
+	(*ICDCIdentityList)(nil),       // 0: WAArmadilloICDC.ICDCIdentityList
+	(*SignedICDCIdentityList)(nil), // 1: WAArmadilloICDC.SignedICDCIdentityList
+}
+var file_waArmadilloICDC_WAArmadilloICDC_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_waArmadilloICDC_WAArmadilloICDC_proto_init() }
+func file_waArmadilloICDC_WAArmadilloICDC_proto_init() {
+	if File_waArmadilloICDC_WAArmadilloICDC_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: unsafe.Slice(unsafe.StringData(file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc), len(file_waArmadilloICDC_WAArmadilloICDC_proto_rawDesc)),
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_waArmadilloICDC_WAArmadilloICDC_proto_goTypes,
+		DependencyIndexes: file_waArmadilloICDC_WAArmadilloICDC_proto_depIdxs,
+		MessageInfos:      file_waArmadilloICDC_WAArmadilloICDC_proto_msgTypes,
+	}.Build()
+	File_waArmadilloICDC_WAArmadilloICDC_proto = out.File
+	file_waArmadilloICDC_WAArmadilloICDC_proto_goTypes = nil
+	file_waArmadilloICDC_WAArmadilloICDC_proto_depIdxs = nil
+}

+ 15 - 0
proto/waArmadilloICDC/WAArmadilloICDC.proto

@@ -0,0 +1,15 @@
+syntax = "proto2";
+package WAArmadilloICDC;
+option go_package = "go.mau.fi/whatsmeow/proto/waArmadilloICDC";
+
+message ICDCIdentityList {
+	optional int32 seq = 1;
+	optional int64 timestamp = 2;
+	repeated bytes devices = 3;
+	optional int32 signingDeviceIndex = 4;
+}
+
+message SignedICDCIdentityList {
+	optional bytes details = 1;
+	optional bytes signature = 2;
+}

Some files were not shown because too many files changed in this diff