diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 281108181..b3499878c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,6 +34,34 @@ jobs: components: rustfmt - run: cargo fmt --all -- --check + generated: + name: Generated Artifacts + runs-on: ubuntu-latest + # The vendored whatspec files are regenerated, never edited, and the tool + # that writes them pins the exact IR commit — so a hand-edit or a + # half-refreshed tree is a diff this job can name. Lives beside `format` + # rather than in a build job: it needs rustfmt and git, not protoc (--check + # never rebuilds the descriptor) and not a compiled workspace. + # Bounded because the step fetches an external repository: a hung fetch + # would otherwise hold a required check open for the full six hours. + timeout-minutes: 15 + steps: + # This job never pushes, and the codegen shells out to `git fetch` against + # a different repository; the checkout token has no business being left in + # .git/config for that. + - uses: actions/checkout@v6 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly-2026-06-16 + components: rustfmt + # RUSTC_WRAPPER is set workspace-wide, so cargo needs sccache on PATH even + # in a job this small. + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.10 + - run: cargo run -p whatspec-codegen -- --check + clippy: name: Clippy Linter runs-on: ubuntu-latest diff --git a/AGENTS.md b/AGENTS.md index b92f1c1c1..437f40966 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,7 @@ Ground truth for protocol behavior is WhatsApp Web itself: query the structured - **wacore** — platform-agnostic core: binary protocol, crypto, IQ types, state traits. Also builds for wasm32 and ESP32, so no Tokio here. - **waproto** — prost-generated protobufs from `whatsapp.proto`. No feature logic. - **whatsapp-rust** — Tokio runtime, SQLite persistence (Diesel), high-level API. +- **whatspec-codegen** (`tools/`) — build tooling, never published and outside `default-members`. Regenerates every whatspec-derived file in one pass from a pinned IR commit. Nothing links it. ## Build & verify @@ -32,7 +33,8 @@ Things that look correct and are not: - **Locks.** `session_locks` serializes Signal encrypt/decrypt per protocol address; `chat_lanes` (`ChatLane::enqueue_lock` in `src/client.rs`) serializes *incoming* processing per chat. Outgoing sends are deliberately not per-chat locked — WA Web doesn't lock them either. - **Wire-tagged enums.** Every protocol enum derives `WireEnum`, and its `#[wire = ...]` attribute is the single source of truth for the wire value. Do not also derive `serde::Serialize`/`Deserialize` or add `#[serde(rename_all)]` — the derive owns both. In tagged mode it generates a sibling `Tag`; parsers must dispatch on `Tag::try_from(node.tag.as_ref())` rather than string literals, so renaming a tag stays a one-attribute change. Modes and attributes: `agent_docs/protocol_architecture.md`. - **Event payloads are a frozen API.** Sealed with `#[non_exhaustive]` + `#[derive(bon::Builder)]` and constructed via `Type::builder()…build()`; a maybe-absent field is `Option`, never an empty-string or zero sentinel. The full stability policy is the `Event` doc comment in `wacore/src/types/events.rs`. -- **`whatsapp.proto` is not the whole persisted schema.** It comes from whatspec and is regenerated wholesale, so fields we persist but upstream does not declare live in `LOCAL_FIELDS` in `waproto/build.rs`, spliced into the descriptor at build time. Never hand-edit the `.proto` or `.desc` to add one — the next sync would drop it. +- **Generated files are generated, not edited.** `wacore/src/iq/abprops.rs`, `wacore/src/iq/mex_operations.rs`, `wacore/appstate/src/schemas.rs`, `wacore/binary/src/tokens.json`, `waproto/src/whatsapp.proto` and `wacore/src/version/generated.rs` all come out of `cargo run -p whatspec-codegen`, together, from one pinned whatspec commit. An action or flag the protocol carries but the bundle no longer builds goes in a hand-written sibling (`wacore/appstate/src/schemas_unlisted.rs`, `props::stale`), never in the generated file. +- **`whatsapp.proto` is not the whole persisted schema.** It comes from whatspec and is regenerated wholesale, so fields we persist but upstream does not declare live in `LOCAL_FIELDS` in `waproto/build.rs`, spliced into the descriptor at build time, and whole retained messages in `LOCAL_BLOCKS` in the codegen's proto emitter. Never hand-edit the `.proto` or `.desc` to add one — the next sync would drop it. - **Blocking work** — `ureq`, heavy CPU — belongs in `tokio::task::spawn_blocking`; it shares a runtime with the read loop. - **let-chains**, never nested `if let`. Clippy's `collapsible_if` is denied in CI. - **No real PII in tests**, including vectors derived from production captures. Regenerate them from fictitious JIDs and numbers. diff --git a/Cargo.lock b/Cargo.lock index d13cc2d42..c88d68756 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4375,6 +4375,16 @@ dependencies = [ "whatsapp-rust", ] +[[package]] +name = "whatspec-codegen" +version = "0.0.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "sha2 0.11.0", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index c4659dc0a..a497a3686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ members = [ "storages/sqlite-storage", "tests/bench-integration", "tests/e2e", + "tools/whatspec-codegen", "transports/tokio-transport", "wacore", "wacore/appstate", diff --git a/agent_docs/wa_web_reference.md b/agent_docs/wa_web_reference.md index 887ead354..853af241c 100644 --- a/agent_docs/wa_web_reference.md +++ b/agent_docs/wa_web_reference.md @@ -11,7 +11,27 @@ Before adding or changing protocol logic, check it against what the official cli [`oxidezap/whatspec`](https://github.com/oxidezap/whatspec) parses the WhatsApp Web JS bundle with an `oxc` AST and emits a language-neutral IR: IQ stanzas, protobuf schemas, GraphQL persisted operations, app-state actions, feature flags, wire enums, notification dispatch, binary-protocol token dictionaries. The IR is a derived model of the contract — a static reading of minified code, not the contract itself — and the committed Rust modules are one consumer of that model. Treat it as high-quality evidence, not as a specification; the limits are spelled out below. -This repo already vendors parts of it — `wacore/src/iq/mex_operations.rs` is copied verbatim from `generated/mex/operations.rs`, and the protobuf and app-state work came from the same place. Refreshing a vendored file is a `cp`. +This repo vendors parts of it. whatspec commits only the IR now (`generated/**/*.rs` is gitignored there), so the vendored files are produced here, by `tools/whatspec-codegen`: + +| Vendored file | Domain | +| --- | --- | +| `wacore/src/iq/abprops.rs` | `abprops` | +| `wacore/src/iq/mex_operations.rs` | `mex` | +| `wacore/appstate/src/schemas.rs` | `appstate` | +| `wacore/binary/src/tokens.json` | `tokens` | +| `waproto/src/whatsapp.proto` | `proto` | +| `wacore/src/version/generated.rs` | `manifest.json`'s `waVersion` | + +```sh +cargo run -p whatspec-codegen # regenerate from the pinned commit +cargo run -p whatspec-codegen -- --check # fail if the tree drifted from it +cargo run -p whatspec-codegen -- --from ../whatspec/generated # use a local checkout +cargo run -p whatspec-codegen -- --update-lock --rev main # move to a newer bundle +``` + +The pinned commit and the per-file digests live in `tools/whatspec-codegen/whatspec.lock.json`, and the WhatsApp build every artifact came from is generated as `wacore::version::WA_WEB_VERSION` — which is also the default a fresh device announces. Regeneration is all-or-nothing: refreshing one domain alone is how the tree ended up with abprops and mex describing two different WhatsApp releases, and `whatspec-codegen` refuses to write a set that does not agree. + +Writing the `.proto` also rebuilds `waproto/src/whatsapp.desc`, so `protoc` (the version in `.github/workflows/main.yml`'s `PROTOC_VERSION`) has to be on PATH; `--skip-proto-desc` defers it. Local additions to the schema are not hand-edits: a whole message goes in the emitter's `LOCAL_BLOCKS` (`tools/whatspec-codegen/src/emit/proto.rs`), a single field in `LOCAL_FIELDS` (`waproto/build.rs`). Either way it survives the next sync, and a sync that starts declaring the same name fails the build instead of shadowing it. ```sh git clone https://github.com/oxidezap/whatspec diff --git a/src/version.rs b/src/version.rs index c48c16e57..3aeca2d09 100644 --- a/src/version.rs +++ b/src/version.rs @@ -5,7 +5,7 @@ use anyhow::{Context as _, Result, anyhow}; use log::debug; use std::sync::Arc; -pub use wacore::version::parse_sw_js; +pub use wacore::version::{WA_WEB_VERSION, WA_WEB_VERSION_STR, parse_sw_js}; const SW_URL: &str = "https://web.whatsapp.com/sw.js"; diff --git a/tools/whatspec-codegen/Cargo.toml b/tools/whatspec-codegen/Cargo.toml new file mode 100644 index 000000000..6db0b54cf --- /dev/null +++ b/tools/whatspec-codegen/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "whatspec-codegen" +# 0.0.0 like the other non-published members: nothing links this, so it has no +# version to keep in lockstep with the released crates. +version = "0.0.0" +edition = "2024" +rust-version.workspace = true +# Build tooling, not a library: it exists to rewrite files in this checkout and +# has no meaning outside it. +publish = false +description = "Regenerates the whatspec-derived artifacts committed in this repository." + +[dependencies] +# `std` on each: the workspace pins these with default-features off for the +# no_std/wasm builds, and none of that applies to a host-only binary that reads +# files and shells out. +anyhow = { workspace = true, features = ["std"] } +serde = { workspace = true } +serde_json = { workspace = true, features = ["std"] } +sha2 = { workspace = true } + +[lints] +workspace = true diff --git a/tools/whatspec-codegen/src/emit/abprops.rs b/tools/whatspec-codegen/src/emit/abprops.rs new file mode 100644 index 000000000..785832800 --- /dev/null +++ b/tools/whatspec-codegen/src/emit/abprops.rs @@ -0,0 +1,286 @@ +//! `wacore/src/iq/abprops.rs`: the A/B-props (feature-flag) registry. + +use std::collections::HashSet; + +use anyhow::{Result, ensure}; + +use crate::ir::{AbPropConfig, AbPropType, AbPropsIr, Scalar}; +use crate::naming::{float_lit, rust_lit, snake_case, unique_ident}; + +const HEADER: &str = "\ +//! One `pub mod` per WA Web registry, one `pub const` per flag (screaming-snake of +//! its key) with the numeric `code` sent in the `` IQ, value type, and default; +//! reference only what you use. Each module's `ALL` lists its flags; the top-level +//! `ALL` lists every module's slice. + +#![allow(clippy::all)] + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AbPropType { + Bool, + Int, + Float, + Str, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum AbDefault { + Bool(bool), + Int(i64), + Float(f64), + Str(&'static str), +} + +#[derive(Debug, Clone, Copy)] +pub struct AbProp { + pub name: &'static str, + pub code: u32, + pub value_type: AbPropType, + pub default: AbDefault, +} + +"; + +pub fn generate(ir: &AbPropsIr) -> Result { + let mut out = super::header("A/B-props registry", &ir.wa_version); + out.push_str(HEADER); + + // `configs` arrives sorted by (module, name); one Rust module per run. + let mut module_idents = HashSet::new(); + let mut emitted: Vec = Vec::new(); + // Interleaved modules would visit the same registry twice and split it + // across `web` and `web_2` — a silent API rename that `--check` would then + // bless. Fail on the IR instead. + let mut seen_modules: HashSet<&str> = HashSet::new(); + let mut i = 0; + while i < ir.configs.len() { + let wa_module = ir.configs[i].module.as_str(); + ensure!( + seen_modules.insert(wa_module), + "abprops IR is not grouped by module: {wa_module} appears in two runs" + ); + let mut j = i; + while j < ir.configs.len() && ir.configs[j].module == wa_module { + j += 1; + } + let ident = unique_ident(&module_ident(wa_module), &mut module_idents, "m"); + out.push_str(&render_module(&ident, wa_module, &ir.configs[i..j])); + emitted.push(ident); + i = j; + } + + out.push_str( + "/// Every registry's `ALL`, for whole-catalog iteration:\n\ + /// `ALL.iter().flat_map(|r| r.iter())`.\npub const ALL: &[&[AbProp]] = &[\n", + ); + for m in &emitted { + out.push_str(&format!(" {m}::ALL,\n")); + } + out.push_str("];\n"); + Ok(out) +} + +fn render_module(ident: &str, wa_module: &str, group: &[AbPropConfig]) -> String { + let mut out = format!( + "/// `{wa_module}` — {} flags.\npub mod {ident} {{\n use super::{{AbDefault, AbProp, AbPropType}};\n\n", + group.len() + ); + // Ident scope is per module, so a flag carried by two registries keeps its + // name in each. + let mut used = HashSet::new(); + let names: Vec = group + .iter() + .map(|c| unique_ident(&snake_case(&c.name).to_uppercase(), &mut used, "F")) + .collect(); + for (c, const_name) in group.iter().zip(&names) { + out.push_str(&format!( + " pub const {const_name}: AbProp = AbProp {{ name: {}, code: {}, value_type: AbPropType::{}, default: {} }};\n", + rust_lit(&c.name), + c.code, + type_variant(c.value_type), + default_lit(&c.default), + )); + } + out.push_str(&format!( + "\n /// All {} flags in this registry, sorted by name.\n pub const ALL: &[AbProp] = &[\n", + group.len() + )); + for const_name in &names { + out.push_str(&format!(" {const_name},\n")); + } + out.push_str(" ];\n}\n\n"); + out +} + +/// `WAWebHybridABPropsConfigs` into `hybrid`; the bare registry into `web`. +fn module_ident(wa_module: &str) -> String { + let s = wa_module.strip_prefix("WAWeb").unwrap_or(wa_module); + let s = s.strip_suffix("ABPropsConfigs").unwrap_or(s); + if s.is_empty() { + "web".to_string() + } else { + snake_case(s) + } +} + +fn type_variant(t: AbPropType) -> &'static str { + match t { + AbPropType::Bool => "Bool", + AbPropType::Int => "Int", + AbPropType::String => "Str", + AbPropType::Float => "Float", + } +} + +fn default_lit(s: &Scalar) -> String { + match s { + Scalar::Bool(b) => format!("AbDefault::Bool({b})"), + Scalar::Int(i) => format!("AbDefault::Int({i})"), + Scalar::Float(f) => format!("AbDefault::Float({})", float_lit(*f)), + Scalar::Str(v) => format!("AbDefault::Str({})", rust_lit(v)), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// The emitters are fallible now; a test IR that trips a guard should + /// fail the test, not be silently skipped. + fn emitted(ir: &AbPropsIr) -> String { + generate(ir).expect("emitter rejected the test IR") + } + + fn cfg(module: &str, name: &str, code: u32, ty: AbPropType, default: Scalar) -> AbPropConfig { + AbPropConfig { + module: module.into(), + name: name.into(), + code, + value_type: ty, + default, + } + } + + fn ir(configs: Vec) -> AbPropsIr { + AbPropsIr { + wa_version: "2.3000.1".into(), + configs, + } + } + + #[test] + fn emits_one_tree_shakeable_const_per_flag() { + let code = emitted(&ir(vec![ + cfg( + "WAWebABPropsConfigs", + "flag_b", + 10, + AbPropType::Bool, + Scalar::Bool(false), + ), + cfg( + "WAWebABPropsConfigs", + "flag_f", + 11, + AbPropType::Float, + Scalar::Float(0.5), + ), + ])); + assert!(code.contains("(WhatsApp 2.3000.1). DO NOT EDIT.")); + assert!(code.contains("pub mod web {")); + assert!(code.contains( + "pub const FLAG_B: AbProp = AbProp { name: \"flag_b\", code: 10, value_type: AbPropType::Bool, default: AbDefault::Bool(false) };" + )); + assert!(code.contains("default: AbDefault::Float(0.5) }")); + assert!(code.contains("pub const ALL: &[&[AbProp]] = &[\n web::ALL,\n];")); + } + + #[test] + fn keeps_registries_apart_and_disambiguates_names() { + let code = emitted(&ir(vec![ + cfg( + "WAWebABPropsConfigs", + "shared", + 1, + AbPropType::Bool, + Scalar::Bool(false), + ), + cfg( + "WAWebABPropsConfigs", + "SHARED", + 2, + AbPropType::Bool, + Scalar::Bool(true), + ), + cfg( + "WAWebHybridABPropsConfigs", + "shared", + 1, + AbPropType::Bool, + Scalar::Bool(false), + ), + ])); + assert!(code.contains("pub mod web {")); + assert!(code.contains("pub mod hybrid {")); + // Same key in two registries keeps the same const name in each; a + // within-registry collision gets a suffix instead of a duplicate item. + assert_eq!(code.matches("pub const SHARED: AbProp").count(), 2); + assert_eq!(code.matches("pub const SHARED_2: AbProp").count(), 1); + } + + #[test] + fn an_ir_not_grouped_by_module_is_rejected() { + // The run-grouping loop would visit the same registry twice and split + // it across `web` and `web_2`, renaming half the flags in silence. + let err = generate(&ir(vec![ + cfg( + "WAWebABPropsConfigs", + "a", + 1, + AbPropType::Bool, + Scalar::Bool(false), + ), + cfg( + "WAWebHybridABPropsConfigs", + "b", + 2, + AbPropType::Bool, + Scalar::Bool(false), + ), + cfg( + "WAWebABPropsConfigs", + "c", + 3, + AbPropType::Bool, + Scalar::Bool(false), + ), + ])) + .expect_err("interleaved modules must not be emitted"); + assert!(err.to_string().contains("two runs"), "{err}"); + } + + #[test] + fn a_non_finite_float_default_still_renders_a_literal() { + let code = emitted(&ir(vec![cfg( + "WAWebABPropsConfigs", + "nanflag", + 1, + AbPropType::Float, + Scalar::Float(f64::NAN), + )])); + assert!(code.contains("AbDefault::Float(f64::NAN)"), "{code}"); + assert!(!code.contains("Float(NaN)")); + } + + #[test] + fn a_default_holding_quotes_stays_a_valid_literal() { + let code = emitted(&ir(vec![cfg( + "WAWebABPropsConfigs", + "quoted", + 1, + AbPropType::String, + Scalar::Str("a\"b\\c".into()), + )])); + assert!(code.contains(r#"AbDefault::Str("a\"b\\c")"#), "{code}"); + } +} diff --git a/tools/whatspec-codegen/src/emit/appstate.rs b/tools/whatspec-codegen/src/emit/appstate.rs new file mode 100644 index 000000000..5b3b2a7ed --- /dev/null +++ b/tools/whatspec-codegen/src/emit/appstate.rs @@ -0,0 +1,413 @@ +//! `wacore/appstate/src/schemas.rs`: the syncd action registry. + +use std::collections::{BTreeMap, BTreeSet, HashSet}; + +use anyhow::{Context, Result}; + +use crate::ir::{AppstateIr, IndexPart}; +use crate::naming::{pascal_case, rust_lit, snake_case, unique_ident, unique_type_ident}; + +const HEADER: &str = "\ +//! Typed registry of syncd actions: collection, version, scope, value proto type, +//! enum fields, and the mutation-index parts. `const`/`&'static`, no deps. + +#![allow(clippy::all)] + +"; + +/// The fixed part of the model: the index-part union and the schema record. +const INDEX_PART_AND_SCHEMA: &str = "\ +/// One component of a mutation index key. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum IndexPart { + /// Fixed wire name at position 0. + Literal { value: &'static str }, + /// A WhatsApp JID (legacy-encoded). + Jid { name: &'static str }, + /// '0' or '1' bool encoding. + BoolString { name: &'static str }, + /// Participant slot: a JID, or '0' when fromMe/null. + JidOrZero { name: &'static str }, + /// Stringified protobuf-enum integer; `proto_enum` is the dotted enum path. + Enum { + name: &'static str, + proto_enum: &'static str, + }, + /// Opaque identifier (msg/label/agent id, etc.). + StringPart { name: &'static str }, + /// Unrecognized slot. + Unknown { name: &'static str }, +} + +/// A syncd action schema. +#[derive(Debug, Clone, Copy)] +pub struct Schema { + /// Registry key (e.g. \"Agent\"). + pub key: &'static str, + /// On-wire action name (e.g. \"deviceAgent\"). + pub name: &'static str, + /// Source WA Web module. + pub module: &'static str, + pub collection: Collection, + pub version: u32, + pub scope: Scope, + /// Field on `SyncActionValue` carrying the payload. + pub value_field: Option<&'static str>, + /// Dotted protobuf type of the value (in `waproto`). + pub value_proto_type: Option<&'static str>, + /// `(field, dotted enum path)` for enum-typed value fields. + pub value_enum_fields: &'static [(&'static str, &'static str)], + /// Index position holding the chat JID, if any. + pub chat_jid_index: Option, + pub index_parts: &'static [IndexPart], +} + +"; + +pub fn generate(ir: &AppstateIr) -> Result { + let mut out = super::header("AppState (syncd) action schemas", &ir.wa_version); + out.push_str(HEADER); + + let (collection_enum, collection_variants) = render_enum( + "/// A syncd collection (mutation bucket / priority).", + "Collection", + ir.collections.iter().map(String::as_str), + ); + out.push_str(&collection_enum); + let scopes: BTreeSet<&str> = ir.actions.values().map(|a| a.scope.as_str()).collect(); + let (scope_enum, scope_variants) = render_enum( + "/// The index scope an action applies to.", + "Scope", + scopes.iter().copied(), + ); + out.push_str(&scope_enum); + out.push_str(INDEX_PART_AND_SCHEMA); + + // Every `Collection::` and `Scope::` below has to name the variant the enum + // just declared. Re-deriving it with `pascal_case` is how two wire strings + // that normalize alike end up sharing one variant: the file still compiles + // and one action silently carries the other's value. + let variant = |wire: &str| -> Result { + collection_variants + .get(wire) + .map(|v| format!("Collection::{v}")) + .with_context(|| format!("collection {wire:?} is not in the IR's collection list")) + }; + let scope_variant = |wire: &str| -> Result { + scope_variants + .get(wire) + .map(|v| format!("Scope::{v}")) + .with_context(|| format!("scope {wire:?} is not in the declared scope set")) + }; + let collections: Vec = ir + .collections + .iter() + .map(|c| variant(c)) + .collect::>()?; + out.push_str(&format!( + "/// All syncd collections, in dependency order.\npub const COLLECTIONS: &[Collection] = &[{}];\n\n", + collections.join(", ") + )); + // The bucket an action falls into when the bundle names none. + let default_collection = variant("regular").context( + "the IR declares no `regular` collection, so the no-bucket fallback would not compile", + )?; + + let mut all_entries: Vec = Vec::new(); + let mut used_consts = HashSet::new(); + for (key, action) in &ir.actions { + let const_name = unique_ident(&snake_case(key).to_uppercase(), &mut used_consts, "ACTION"); + let collection = match action.collection.as_deref() { + Some(c) => variant(c).with_context(|| format!("action {key}"))?, + None => default_collection.clone(), + }; + let enum_fields = match &action.value_enum_fields { + Some(m) if !m.is_empty() => format!( + "&[{}]", + m.iter() + .map(|(k, v)| format!("({}, {})", rust_lit(k), rust_lit(v))) + .collect::>() + .join(", ") + ), + _ => "&[]".to_string(), + }; + let index_parts = action + .index_parts + .iter() + .map(render_index_part) + .collect::>() + .join(", "); + + out.push_str(&format!( + "/// `{key}` — module `{module}`.\npub const {const_name}: Schema = Schema {{\n\ + \x20 key: {key_lit},\n name: {name_lit},\n module: {module_lit},\n collection: {collection},\n\ + \x20 version: {version},\n scope: {scope},\n value_field: {value_field},\n\ + \x20 value_proto_type: {value_proto},\n value_enum_fields: {enum_fields},\n\ + \x20 chat_jid_index: {chat_jid_index},\n index_parts: &[{index_parts}],\n}};\n\n", + module = action.module, + key_lit = rust_lit(key), + name_lit = rust_lit(&action.name), + module_lit = rust_lit(&action.module), + version = action.version.unwrap_or(0), + scope = scope_variant(&action.scope).with_context(|| format!("action {key}"))?, + value_field = opt_lit(action.value_field.as_deref()), + value_proto = opt_lit(action.value_proto_type.as_deref()), + chat_jid_index = match action.chat_jid_index { + Some(i) => format!("Some({i})"), + None => "None".to_string(), + }, + )); + all_entries.push(const_name); + } + + out.push_str("/// Every action schema, keyed-sorted.\npub const ALL: &[Schema] = &[\n"); + for name in &all_entries { + out.push_str(&format!(" {name},\n")); + } + out.push_str("];\n\n"); + out.push_str( + "/// Look up a schema by its action key (the registry key, e.g. `\"Agent\"`).\n\ + pub fn by_name(key: &str) -> Option<&'static Schema> {\n\ + \x20 ALL.iter().find(|s| s.key == key)\n}\n", + ); + Ok(out) +} + +fn opt_lit(v: Option<&str>) -> String { + match v { + Some(s) => format!("Some({})", rust_lit(s)), + None => "None".to_string(), + } +} + +/// A C-like enum over wire strings, plus the `as_str` that maps back. +/// +/// Returns the rendered enum and the wire-string-to-variant map, because +/// `pascal_case` is not injective (`critical_block` and `criticalBlock` both +/// give `CriticalBlock`) and every site that names a variant has to agree with +/// the declaration on which of the two got suffixed. +fn render_enum<'a>( + doc: &str, + name: &str, + values: impl Iterator, +) -> (String, BTreeMap) { + let mut used = HashSet::new(); + let variants: Vec<(&str, String)> = values + .map(|v| (v, unique_type_ident(&pascal_case(v), &mut used, "V"))) + .collect(); + + let mut s = + format!("{doc}\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum {name} {{\n"); + for (_, variant) in &variants { + s.push_str(&format!(" {variant},\n")); + } + s.push_str(&format!( + "}}\n\nimpl {name} {{\n pub const fn as_str(self) -> &'static str {{\n match self {{\n" + )); + for (wire, variant) in &variants { + s.push_str(&format!( + " {name}::{variant} => {},\n", + rust_lit(wire) + )); + } + s.push_str(" }\n }\n}\n\n"); + + let map = variants + .into_iter() + .map(|(wire, variant)| (wire.to_string(), variant)) + .collect(); + (s, map) +} + +fn render_index_part(part: &IndexPart) -> String { + match part { + IndexPart::Literal { value } => { + format!("IndexPart::Literal {{ value: {} }}", rust_lit(value)) + } + IndexPart::Jid { name } => format!("IndexPart::Jid {{ name: {} }}", rust_lit(name)), + IndexPart::BoolString { name } => { + format!("IndexPart::BoolString {{ name: {} }}", rust_lit(name)) + } + IndexPart::JidOrZero { name } => { + format!("IndexPart::JidOrZero {{ name: {} }}", rust_lit(name)) + } + IndexPart::Enum { name, proto_enum } => format!( + "IndexPart::Enum {{ name: {}, proto_enum: {} }}", + rust_lit(name), + rust_lit(proto_enum) + ), + IndexPart::StringPart { name } => { + format!("IndexPart::StringPart {{ name: {} }}", rust_lit(name)) + } + IndexPart::Unknown { name } => format!("IndexPart::Unknown {{ name: {} }}", rust_lit(name)), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// The emitters are fallible now; a test IR that trips a guard should + /// fail the test, not be silently skipped. + fn emitted(ir: &AppstateIr) -> String { + generate(ir).expect("emitter rejected the test IR") + } + use crate::ir::AppstateAction; + use std::collections::BTreeMap; + + fn action(name: &str, scope: &str, collection: Option<&str>) -> AppstateAction { + AppstateAction { + module: "WAWebAgentSync".into(), + name: name.into(), + collection: collection.map(Into::into), + version: Some(7), + scope: scope.into(), + value_field: Some("agentAction".into()), + value_proto_type: Some("SyncActionValue.AgentAction".into()), + value_enum_fields: None, + chat_jid_index: None, + index_parts: vec![ + IndexPart::Literal { value: name.into() }, + IndexPart::StringPart { + name: "agentId".into(), + }, + ], + } + } + + fn ir(actions: Vec<(&str, AppstateAction)>) -> AppstateIr { + AppstateIr { + wa_version: "2.3000.1".into(), + collections: vec!["regular".into(), "critical_block".into()], + actions: actions + .into_iter() + .map(|(k, v)| (k.to_string(), v)) + .collect(), + } + } + + #[test] + fn an_action_naming_an_undeclared_collection_is_rejected() { + // The variant would not exist on the enum, so the emitted file would + // not compile and the failure would land on the next build instead. + let err = generate(&ir(vec![( + "Agent", + action("deviceAgent", "account", Some("no_such_bucket")), + )])) + .expect_err("an undeclared collection must not be emitted"); + assert!(format!("{err:#}").contains("no_such_bucket"), "{err:#}"); + } + + #[test] + fn an_ir_without_the_regular_collection_is_rejected() { + // Actions with no declared bucket fall back to it, so its absence is + // the same dangling reference one step removed. + let mut bad = ir(vec![("Nux", action("nux", "account", None))]); + bad.collections = vec!["critical_block".into()]; + let err = generate(&bad).expect_err("the fallback bucket must exist"); + assert!(err.to_string().contains("regular"), "{err}"); + } + + #[test] + fn collection_names_that_pascal_case_alike_stay_distinct_variants() { + let mut ir = ir(vec![("Agent", action("deviceAgent", "account", None))]); + ir.collections = vec![ + "regular".into(), + "criticalBlock".into(), + "critical_block".into(), + ]; + let code = emitted(&ir); + assert!(code.contains(" CriticalBlock,\n"), "{code}"); + assert!(code.contains(" CriticalBlock2,\n"), "{code}"); + // Each variant keeps its own wire string. + assert!(code.contains("Collection::CriticalBlock => \"criticalBlock\",")); + assert!(code.contains("Collection::CriticalBlock2 => \"critical_block\",")); + } + + #[test] + fn scope_names_that_pascal_case_alike_stay_distinct_variants() { + // Worse than the collection case: re-deriving the name would compile + // and silently give one action the other's scope. + let code = emitted(&ir(vec![ + ("A", action("a", "critical_block", None)), + ("B", action("b", "criticalBlock", None)), + ])); + assert!( + code.contains("Scope::CriticalBlock => \"criticalBlock\","), + "{code}" + ); + assert!( + code.contains("Scope::CriticalBlock2 => \"critical_block\","), + "{code}" + ); + assert!(code.contains("scope: Scope::CriticalBlock2,"), "{code}"); + assert!(code.contains("scope: Scope::CriticalBlock,"), "{code}"); + } + + #[test] + fn a_scope_whose_pascal_case_is_escaped_still_names_the_declared_variant() { + // `ensure_ident` escapes `Self` to `Self_`; formatting the variant + // independently would emit `Scope::Self`, which does not exist. + let code = emitted(&ir(vec![("A", action("a", "self", None))])); + assert!(code.contains("Scope::Self_ => \"self\","), "{code}"); + assert!(code.contains("scope: Scope::Self_,"), "{code}"); + } + + #[test] + fn emits_a_const_per_action_with_its_index() { + let code = emitted(&ir(vec![( + "Agent", + action("deviceAgent", "account", Some("regular")), + )])); + assert!(code.contains("pub enum Collection {\n Regular,\n CriticalBlock,\n}")); + assert!(code.contains("Collection::CriticalBlock => \"critical_block\",")); + assert!(code.contains("pub enum Scope {\n Account,\n}")); + assert!(code.contains("pub const AGENT: Schema = Schema {")); + assert!(code.contains("key: \"Agent\",")); + assert!(code.contains("collection: Collection::Regular,")); + assert!(code.contains("scope: Scope::Account,")); + assert!(code.contains( + "index_parts: &[IndexPart::Literal { value: \"deviceAgent\" }, IndexPart::StringPart { name: \"agentId\" }]," + )); + assert!(code.contains("pub const ALL: &[Schema] = &[\n AGENT,\n];")); + } + + #[test] + fn an_action_without_a_collection_falls_back_to_regular() { + // WA Web builds a few actions with no declared bucket; the wire default + // is the regular collection, and emitting `Collection::` alone would not + // compile. + let code = emitted(&ir(vec![("Nux", action("nux", "account", None))])); + assert!(code.contains("collection: Collection::Regular,")); + } + + #[test] + fn enum_index_parts_and_value_enum_fields_survive() { + let mut a = action("settingsSync", "account", Some("regular")); + a.index_parts = vec![IndexPart::Enum { + name: "k".into(), + proto_enum: "SettingsSyncAction.SettingKey".into(), + }]; + a.value_enum_fields = Some(BTreeMap::from([( + "settingKey".to_string(), + "SettingsSyncAction.SettingKey".to_string(), + )])); + let code = emitted(&ir(vec![("SettingsSync", a)])); + assert!(code.contains( + "IndexPart::Enum { name: \"k\", proto_enum: \"SettingsSyncAction.SettingKey\" }" + )); + assert!(code.contains( + "value_enum_fields: &[(\"settingKey\", \"SettingsSyncAction.SettingKey\")]," + )); + } + + #[test] + fn two_keys_that_upper_case_alike_do_not_collide() { + let code = emitted(&ir(vec![ + ("Agent", action("deviceAgent", "account", Some("regular"))), + ("AGENT", action("deviceAgent2", "account", Some("regular"))), + ])); + assert!(code.contains("pub const AGENT: Schema")); + assert!(code.contains("pub const AGENT_2: Schema")); + } +} diff --git a/tools/whatspec-codegen/src/emit/mex.rs b/tools/whatspec-codegen/src/emit/mex.rs new file mode 100644 index 000000000..326df94b7 --- /dev/null +++ b/tools/whatspec-codegen/src/emit/mex.rs @@ -0,0 +1,379 @@ +//! `wacore/src/iq/mex_operations.rs`: typed inputs and outputs for every +//! persisted Relay operation. +//! +//! One `pub mod` per operation, so a caller that names one operation pulls in +//! that operation's types and nothing else. + +use std::collections::{BTreeMap, HashSet}; + +use crate::ir::{MexIr, TypeNode}; +use crate::naming::{pascal_case, rust_ident, rust_lit, snake_case, unique_ident}; + +const HEADER: &str = "\ +//! One module per persisted GraphQL operation: typed `Variables` + `Response` +//! plus `DOC_ID`/`OPERATION_KIND`/`NAME`. Depends only on `serde`. + +#![allow(clippy::all)] + +use serde::{Deserialize, Serialize}; +"; + +pub fn generate(ir: &MexIr) -> String { + let mut out = super::header("typed mex operations", &ir.wa_version); + out.push_str(HEADER); + + let mut used_mods = HashSet::new(); + for (short, op) in &ir.operations { + // An operation named e.g. `match` would otherwise emit `pub mod match`. + let module = unique_ident(&snake_case(short), &mut used_mods, "op"); + let mut b = Builder::default(); + // Both before either walk: a nested object inside `variables_shape` can + // just as easily want the name `Response`. + b.reserve("Variables"); + b.reserve("Response"); + b.register("Variables", &op.variables_shape); + b.register("Response", &op.response); + + let kind = op.operation_kind.as_str(); + out.push_str(&format!("\n/// `{}` ({kind}).\n", op.original_name)); + out.push_str(&format!("pub mod {module} {{\n")); + out.push_str(" use super::{Deserialize, Serialize};\n\n"); + out.push_str(&format!( + " pub const NAME: &str = {};\n", + rust_lit(&op.original_name) + )); + out.push_str(&format!( + " pub const DOC_ID: &str = {};\n", + rust_lit(&op.doc_id) + )); + out.push_str(&format!( + " pub const OPERATION_KIND: &str = {};\n\n", + rust_lit(kind) + )); + for s in &b.structs { + out.push_str(&s.render(" ")); + out.push('\n'); + } + out.push_str("}\n"); + } + out +} + +/// A generated struct: name plus ordered `(rust_field, json_key, type)`. +struct StructDef { + name: String, + fields: Vec<(String, String, String)>, +} + +impl StructDef { + /// Shape signature used to merge identical structs. The JSON key is part of + /// it: two structs with the same Rust fields but different `serde(rename)` + /// keys are different types on the wire. + fn signature(&self) -> String { + self.fields + .iter() + .map(|(r, json, t)| format!("{json}={r}:{t}")) + .collect::>() + .join(",") + } + + fn render(&self, indent: &str) -> String { + let mut s = String::new(); + s.push_str(&format!( + "{indent}#[derive(Debug, Clone, Default, Serialize, Deserialize)]\n" + )); + s.push_str(&format!("{indent}pub struct {} {{\n", self.name)); + for (rust_field, json_key, ty) in &self.fields { + if rust_field.trim_start_matches("r#") != json_key { + s.push_str(&format!( + "{indent} #[serde(rename = {})]\n", + rust_lit(json_key) + )); + } + s.push_str(&format!( + "{indent} #[serde(default, skip_serializing_if = \"Option::is_none\")]\n" + )); + s.push_str(&format!("{indent} pub {rust_field}: {ty},\n")); + } + s.push_str(&format!("{indent}}}\n")); + s + } +} + +#[derive(Default)] +struct Builder { + structs: Vec, + /// Struct name to its signature, to merge identical shapes and disambiguate + /// distinct shapes that want the same name. + by_name: BTreeMap, + /// Names the operation module has to expose verbatim. + reserved: HashSet, +} + +impl Builder { + /// Claim a name for a top-level struct before any nested object can take it. + /// + /// Children are interned before their parent, so without this a response + /// field literally named `response` renames the operation's own `Response` + /// to `Response2` — a generated-API break that depends on field naming luck. + fn reserve(&mut self, name: &str) { + self.reserved.insert(name.to_string()); + } + + fn register(&mut self, name: &str, fields: &BTreeMap) -> String { + let def = self.struct_def(name, fields); + self.intern(def, true) + } + + /// Build one struct, interning any object-typed field as its own struct. + fn struct_def(&mut self, name: &str, fields: &BTreeMap) -> StructDef { + let mut def = StructDef { + name: name.to_string(), + fields: Vec::new(), + }; + // `rust_ident` is not injective: `fooBar` and `foo_bar` are one Rust + // field. Two of them in the same object would emit the field twice. + let mut used_fields = HashSet::new(); + for (key, node) in fields { + let ty = self.field_type(node, &pascal_case(key)); + let field = unique_ident(&rust_ident(key), &mut used_fields, "f"); + def.fields + .push((field, key.clone(), format!("Option<{ty}>"))); + } + def + } + + fn field_type(&mut self, node: &TypeNode, name_hint: &str) -> String { + match node { + TypeNode::Leaf(tag) => scalar_rust(tag).to_string(), + TypeNode::Array(items) => { + // The IR carries a single element shape; an empty array would + // still have to name a type. + let inner = items + .first() + .map(|n| self.field_type(n, name_hint)) + .unwrap_or_else(|| "String".to_string()); + format!("Vec<{inner}>") + } + TypeNode::Object(map) => { + let def = self.struct_def(name_hint, map); + self.intern(def, false) + } + } + } + + fn intern(&mut self, mut def: StructDef, top_level: bool) -> String { + if def.name.is_empty() { + def.name = "Item".to_string(); + } + let sig = def.signature(); + let base = def.name.clone(); + let mut name = base.clone(); + let mut n = 2; + loop { + if !top_level && self.reserved.contains(&name) { + name = format!("{base}{n}"); + n += 1; + continue; + } + match self.by_name.get(&name) { + Some(existing) if *existing == sig => return name, + Some(_) => { + name = format!("{base}{n}"); + n += 1; + } + None => break, + } + } + def.name = name.clone(); + self.by_name.insert(name.clone(), sig); + self.structs.push(def); + name + } +} + +/// The IR's scalar tags. Anything else, including `enum:A|B` and `unknown`, +/// deserializes as a string: the extractor cannot prove a closed variant set, +/// and a wrong enum would fail the whole response. +fn scalar_rust(tag: &str) -> &'static str { + match tag { + "number" => "i64", + "boolean" => "bool", + _ => "String", + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::{MexOperation, MexOperationKind}; + + fn leaf(t: &str) -> TypeNode { + TypeNode::Leaf(t.to_string()) + } + + fn obj(fields: &[(&str, TypeNode)]) -> TypeNode { + TypeNode::Object( + fields + .iter() + .map(|(k, v)| (k.to_string(), v.clone())) + .collect(), + ) + } + + fn ir(key: &str, op: MexOperation) -> MexIr { + MexIr { + wa_version: "2.3000.1".into(), + operations: BTreeMap::from([(key.to_string(), op)]), + } + } + + fn op(variables: &[(&str, TypeNode)], response: &[(&str, TypeNode)]) -> MexOperation { + MexOperation { + original_name: "WAWebFetchThingQuery".into(), + doc_id: "123".into(), + operation_kind: MexOperationKind::Query, + variables_shape: variables + .iter() + .map(|(k, v)| (k.to_string(), v.clone())) + .collect(), + response: response + .iter() + .map(|(k, v)| (k.to_string(), v.clone())) + .collect(), + } + } + + #[test] + fn emits_a_module_with_the_persisted_ids_and_typed_shapes() { + let code = generate(&ir( + "FetchThing", + op( + &[("thing_id", leaf("string"))], + &[( + "xwa2_thing", + obj(&[("count", leaf("number")), ("ok", leaf("boolean"))]), + )], + ), + )); + assert!(code.contains("pub mod fetch_thing {")); + assert!(code.contains("pub const NAME: &str = \"WAWebFetchThingQuery\";")); + assert!(code.contains("pub const DOC_ID: &str = \"123\";")); + assert!(code.contains("pub const OPERATION_KIND: &str = \"query\";")); + assert!(code.contains("pub thing_id: Option,")); + assert!(code.contains("pub count: Option,")); + assert!(code.contains("pub ok: Option,")); + assert!(code.contains("pub struct Xwa2Thing {")); + assert!(code.contains("pub xwa2_thing: Option,")); + // Nested structs are declared before the struct that names them. + let nested = code.find("pub struct Xwa2Thing").expect("nested struct"); + let response = code.find("pub struct Response").expect("response struct"); + assert!(nested < response); + } + + #[test] + fn a_plural_field_becomes_a_vec_of_its_element_struct() { + let code = generate(&ir( + "FetchThing", + op( + &[], + &[( + "items", + TypeNode::Array(vec![obj(&[("id", leaf("string"))])]), + )], + ), + )); + assert!(code.contains("pub struct Items {")); + assert!(code.contains("pub items: Option>,")); + } + + #[test] + fn json_keys_that_are_not_rust_idents_get_a_rename() { + let code = generate(&ir( + "FetchThing", + op( + &[], + &[("__typename", leaf("string")), ("type", leaf("string"))], + ), + )); + assert!(code.contains("#[serde(rename = \"__typename\")]")); + assert!(code.contains("pub typename: Option,")); + // A raw identifier already spells its JSON key, so it needs no rename. + assert!(code.contains("pub r#type: Option,")); + assert!(!code.contains("#[serde(rename = \"type\")]")); + } + + #[test] + fn same_named_structs_with_different_shapes_are_kept_apart() { + let code = generate(&ir( + "FetchThing", + op( + &[("node", obj(&[("a", leaf("string"))]))], + &[("node", obj(&[("b", leaf("number"))]))], + ), + )); + assert!(code.contains("pub struct Node {")); + assert!(code.contains("pub struct Node2 {")); + } + + #[test] + fn an_identical_shape_reused_under_the_same_name_is_emitted_once() { + let code = generate(&ir( + "FetchThing", + op( + &[("node", obj(&[("a", leaf("string"))]))], + &[("node", obj(&[("a", leaf("string"))]))], + ), + )); + assert_eq!(code.matches("pub struct Node {").count(), 1); + assert!(!code.contains("pub struct Node2")); + } + + #[test] + fn a_nested_object_cannot_take_the_top_level_struct_names() { + // `op::Variables` and `op::Response` are the generated API. A field + // named after either one must not push the real struct to `Response2`. + let code = generate(&ir( + "FetchThing", + op( + &[("response", obj(&[("a", leaf("string"))]))], + &[("variables", obj(&[("b", leaf("string"))]))], + ), + )); + assert!(code.contains("pub struct Variables {"), "{code}"); + assert!(code.contains("pub struct Response {"), "{code}"); + assert!(code.contains("pub struct Response2 {"), "{code}"); + assert!(code.contains("pub struct Variables2 {"), "{code}"); + } + + #[test] + fn two_keys_that_snake_case_alike_stay_two_fields() { + // `rust_ident` is not injective, and a struct cannot declare the same + // field twice. + let code = generate(&ir( + "FetchThing", + op( + &[], + &[("fooBar", leaf("string")), ("foo_bar", leaf("string"))], + ), + )); + assert_eq!(code.matches("pub foo_bar:").count(), 1, "{code}"); + assert_eq!(code.matches("pub foo_bar_2:").count(), 1, "{code}"); + // Both keys still deserialize from their own wire name. + assert!(code.contains("#[serde(rename = \"fooBar\")]"), "{code}"); + assert!(code.contains("#[serde(rename = \"foo_bar\")]"), "{code}"); + } + + #[test] + fn an_unmodelled_leaf_tag_falls_back_to_string() { + let code = generate(&ir( + "FetchThing", + op( + &[], + &[("state", leaf("enum:ON|OFF")), ("x", leaf("unknown"))], + ), + )); + assert!(code.contains("pub state: Option,")); + assert!(code.contains("pub x: Option,")); + } +} diff --git a/tools/whatspec-codegen/src/emit/mod.rs b/tools/whatspec-codegen/src/emit/mod.rs new file mode 100644 index 000000000..9a0f3ba5d --- /dev/null +++ b/tools/whatspec-codegen/src/emit/mod.rs @@ -0,0 +1,30 @@ +//! The emitters, one per committed artifact. +//! +//! Each returns the file's full text; nothing here touches the filesystem, so an +//! emitter is testable from a fixture and `--check` can compare without writing. + +pub mod abprops; +pub mod appstate; +pub mod mex; +pub mod proto; +pub mod tokens; +pub mod version; + +/// The two-line preamble every generated Rust file opens with. The version is +/// part of it so a partially refreshed tree is visible in a diff. +pub fn header(what: &str, wa_version: &str) -> String { + format!("//! Auto-generated {what} (WhatsApp {wa_version}). DO NOT EDIT.\n//!\n") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn header_stamps_the_version() { + assert_eq!( + header("tokens", "2.3000.1"), + "//! Auto-generated tokens (WhatsApp 2.3000.1). DO NOT EDIT.\n//!\n" + ); + } +} diff --git a/tools/whatspec-codegen/src/emit/proto.rs b/tools/whatspec-codegen/src/emit/proto.rs new file mode 100644 index 000000000..d58a288a6 --- /dev/null +++ b/tools/whatspec-codegen/src/emit/proto.rs @@ -0,0 +1,162 @@ +//! `waproto/src/whatsapp.proto`: the upstream schema plus the messages this +//! repository keeps after WA dropped them from the public bundle. +//! +//! Local *fields* belong in `waproto/build.rs`'s `LOCAL_FIELDS`, which splices +//! them into the descriptor. A whole message has no such hook, so it is declared +//! here and spliced into the `.proto` text instead. Either way the addition +//! survives a sync, and a sync that starts declaring the same name fails the +//! build rather than quietly taking over a type we already persist. + +use anyhow::{Result, bail}; + +/// A message this repository declares that the upstream bundle no longer does. +struct LocalBlock { + /// Spliced in after this top-level message's closing brace, so the block + /// lands beside the message it belongs to instead of at the end of the file. + after_message: &'static str, + /// Type names the block declares. Upstream declaring one of these means the + /// block is obsolete and must be deleted, not duplicated. + declares: &'static [&'static str], + text: &'static str, +} + +const LOCAL_BLOCKS: &[LocalBlock] = &[LocalBlock { + after_message: "LIDMigrationMappingSyncMessage", + declares: &["LIDMigrationMapping", "LIDMigrationMappingSyncPayload"], + text: "\ +// Retained locally: WA dropped these from the public JS bundle, but the wire +// still carries them as the protobuf-encoded `encodedMappingPayload` above. +message LIDMigrationMapping { + required uint64 pn = 1; + required uint64 assignedLid = 2; + optional uint64 latestLid = 3; +} + +message LIDMigrationMappingSyncPayload { + repeated LIDMigrationMapping pnToLidMappings = 1; + optional uint64 chatDbMigrationTimestamp = 2; +} +", +}]; + +pub fn generate(upstream: &str) -> Result { + let mut out = upstream.to_string(); + for block in LOCAL_BLOCKS { + for name in block.declares { + if declares_message(upstream, name) { + bail!( + "upstream now declares `message {name}`; drop the local block anchored at \ + `{}` in the proto emitter instead of shadowing it", + block.after_message + ); + } + } + let at = end_of_message(&out, block.after_message).ok_or_else(|| { + anyhow::anyhow!( + "anchor `message {}` is gone from the upstream proto; re-anchor the local block \ + declaring {:?}", + block.after_message, + block.declares + ) + })?; + out.insert_str(at, &format!("\n{}", block.text)); + } + Ok(out) +} + +/// Whether the file declares a top-level `message `. +fn declares_message(proto: &str, name: &str) -> bool { + proto + .lines() + .any(|l| l == format!("message {name} {{") || l == format!("message {name} {{}}")) +} + +/// Byte offset just past the closing brace line of a top-level message. +/// +/// Top-level declarations sit at column zero and nested ones are indented, so a +/// line that is exactly `}` closes the message the scan is inside. +fn end_of_message(proto: &str, name: &str) -> Option { + let open = format!("message {name} {{"); + let mut offset = 0usize; + let mut inside = false; + for line in proto.split_inclusive('\n') { + let trimmed = line.trim_end_matches(['\n', '\r']); + if inside && trimmed == "}" { + return Some(offset + line.len()); + } + if trimmed == open { + inside = true; + } + offset += line.len(); + } + None +} + +#[cfg(test)] +mod tests { + use super::*; + + const UPSTREAM: &str = "\ +syntax = \"proto2\"; +package whatsapp; + +message LIDMigrationMappingSyncMessage { + optional bytes encodedMappingPayload = 1; +} + +message LabyrinthWaCommand { + oneof commandInput { + CreateBackupInput createBackupInput = 1; + } +} +"; + + #[test] + fn splices_the_local_block_after_its_anchor() { + let out = generate(UPSTREAM).expect("proto"); + let anchor = out + .find("optional bytes encodedMappingPayload") + .expect("anchor"); + let local = out + .find("message LIDMigrationMapping {") + .expect("local block"); + let next = out + .find("message LabyrinthWaCommand") + .expect("next message"); + assert!(anchor < local && local < next, "{out}"); + assert!(out.contains("message LIDMigrationMappingSyncPayload {")); + // The upstream text is otherwise untouched. + assert!(out.starts_with("syntax = \"proto2\";\n")); + assert!(out.ends_with("}\n")); + } + + #[test] + fn a_lost_anchor_fails_instead_of_dropping_the_block() { + let err = generate("syntax = \"proto2\";\npackage whatsapp;\n").expect_err("must fail"); + assert!(err.to_string().contains("re-anchor"), "{err}"); + } + + #[test] + fn upstream_reclaiming_the_name_fails_instead_of_duplicating_it() { + let upstream = + format!("{UPSTREAM}\nmessage LIDMigrationMapping {{\n required uint64 pn = 1;\n}}\n"); + let err = generate(&upstream).expect_err("must fail"); + assert!(err.to_string().contains("drop the local block"), "{err}"); + } + + #[test] + fn a_nested_closing_brace_does_not_end_the_anchor_early() { + let upstream = "\ +message LIDMigrationMappingSyncMessage { + message Inner { + optional bytes a = 1; + } + optional bytes encodedMappingPayload = 1; +} +"; + let out = generate(upstream).expect("proto"); + let payload = out.find("encodedMappingPayload").expect("field"); + let local = out.find("message LIDMigrationMapping {").expect("local"); + assert!(payload < local, "{out}"); + } +} diff --git a/tools/whatspec-codegen/src/emit/tokens.rs b/tools/whatspec-codegen/src/emit/tokens.rs new file mode 100644 index 000000000..73d31da4e --- /dev/null +++ b/tools/whatspec-codegen/src/emit/tokens.rs @@ -0,0 +1,76 @@ +//! `wacore/binary/src/tokens.json`: the binary-protocol token dictionaries. +//! +//! The IR is already canonicalized to the wire-indexable form (index 0 of the +//! single-byte table is the reserved empty token), so this is a re-serialization +//! under the two keys `wacore-binary`'s build script reads. + +use anyhow::{Result, ensure}; +use serde::Serialize; + +use crate::ir::TokensIr; + +/// Serialized in declaration order, so the file reads single-byte table first. +/// `serde_json::json!` would key it by a sorted map and put the dictionaries on +/// top, which is a whole-file diff for no gain. +#[derive(Serialize)] +struct Tokens<'a> { + single_byte: &'a [String], + double_byte: &'a [Vec], +} + +pub fn generate(ir: &TokensIr) -> Result { + // The decoder indexes these tables directly by wire tag. A table that lost + // its reserved leading slot would shift every token by one and corrupt every + // frame, so refuse to write it rather than let the build succeed. + ensure!( + ir.single_byte.first().is_some_and(|t| t.is_empty()), + "single-byte token table does not start with the reserved empty token" + ); + ensure!( + !ir.double_byte.is_empty(), + "token IR carries no double-byte dictionaries" + ); + let doc = Tokens { + single_byte: &ir.single_byte, + double_byte: &ir.double_byte, + }; + Ok(serde_json::to_string_pretty(&doc)? + "\n") +} + +#[cfg(test)] +mod tests { + use super::*; + + fn ir(single: &[&str], double: &[&[&str]]) -> TokensIr { + TokensIr { + single_byte: single.iter().map(|s| s.to_string()).collect(), + double_byte: double + .iter() + .map(|d| d.iter().map(|s| s.to_string()).collect()) + .collect(), + } + } + + #[test] + fn emits_the_two_keys_the_build_script_reads() { + let out = + generate(&ir(&["", "xmlstreamstart"], &[&["read-self"], &["reject"]])).expect("tokens"); + let v: serde_json::Value = serde_json::from_str(&out).expect("json"); + assert_eq!(v["single_byte"][0], ""); + assert_eq!(v["single_byte"][1], "xmlstreamstart"); + assert_eq!(v["double_byte"][0][0], "read-self"); + assert_eq!(v["double_byte"][1][0], "reject"); + assert!(out.ends_with('\n')); + } + + #[test] + fn a_table_missing_the_reserved_slot_is_rejected() { + let err = generate(&ir(&["xmlstreamstart"], &[&["read-self"]])); + assert!(err.is_err(), "off-by-one table must not be written"); + } + + #[test] + fn a_table_with_no_dictionaries_is_rejected() { + assert!(generate(&ir(&[""], &[])).is_err()); + } +} diff --git a/tools/whatspec-codegen/src/emit/version.rs b/tools/whatspec-codegen/src/emit/version.rs new file mode 100644 index 000000000..eef3af5c4 --- /dev/null +++ b/tools/whatspec-codegen/src/emit/version.rs @@ -0,0 +1,75 @@ +//! `wacore/src/version/generated.rs`: the WhatsApp build every other +//! committed artifact was extracted from. +//! +//! Stamping it as code rather than as a comment is what keeps the registries and +//! the version a device announces from drifting apart: they are regenerated +//! together or not at all. + +use anyhow::{Context, Result, bail}; + +const HEADER: &str = "\ +//! The WhatsApp Web build the committed whatspec artifacts were extracted from. +//! +//! Regenerate with `cargo run -p whatspec-codegen`; never edit by hand. + +"; + +pub fn generate(wa_version: &str) -> Result { + let (primary, secondary, tertiary) = parse(wa_version)?; + let mut out = super::header("WhatsApp Web version stamp", wa_version); + out.push_str(HEADER); + out.push_str(&format!( + "/// The version string whatspec stamped on the IR: `{wa_version}`.\n\ + pub const WA_WEB_VERSION_STR: &str = \"{wa_version}\";\n\n\ + /// The same version as the `(primary, secondary, tertiary)` triple the\n\ + /// client payload carries.\n\ + pub const WA_WEB_VERSION: (u32, u32, u32) = ({primary}, {secondary}, {tertiary});\n" + )); + Ok(out) +} + +fn parse(wa_version: &str) -> Result<(u32, u32, u32)> { + let mut parts = wa_version.split('.'); + let mut next = |what: &'static str| -> Result { + parts + .next() + .with_context(|| format!("whatspec waVersion {wa_version:?} has no {what} component"))? + .parse::() + .with_context(|| format!("whatspec waVersion {wa_version:?} has a non-numeric {what}")) + }; + let triple = (next("primary")?, next("secondary")?, next("tertiary")?); + if parts.next().is_some() { + bail!("whatspec waVersion {wa_version:?} has more than three components"); + } + Ok(triple) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn emits_the_string_and_the_triple() { + let out = generate("2.3000.1044659339").expect("version"); + assert!(out.contains("(WhatsApp 2.3000.1044659339). DO NOT EDIT.")); + assert!(out.contains("pub const WA_WEB_VERSION_STR: &str = \"2.3000.1044659339\";")); + assert!(out.contains("pub const WA_WEB_VERSION: (u32, u32, u32) = (2, 3000, 1044659339);")); + } + + #[test] + fn a_version_that_is_not_a_numeric_triple_is_rejected() { + // The triple reaches the wire in the client payload, so a version the + // tool cannot parse must stop the run rather than emit a plausible zero. + for bad in ["2.3000", "2.3000.1.4", "2.3000.beta", ""] { + assert!(generate(bad).is_err(), "{bad:?} must be rejected"); + } + } + + #[test] + fn a_revision_at_the_top_of_the_range_still_parses() { + // Revisions are already past 2^30 and climb with every rollout. + let out = generate("2.3000.4294967295").expect("version"); + assert!(out.contains("(2, 3000, 4294967295)")); + assert!(generate("2.3000.4294967296").is_err()); + } +} diff --git a/tools/whatspec-codegen/src/ir.rs b/tools/whatspec-codegen/src/ir.rs new file mode 100644 index 000000000..753b0e0f2 --- /dev/null +++ b/tools/whatspec-codegen/src/ir.rs @@ -0,0 +1,217 @@ +//! The slice of the whatspec IR this repository consumes. +//! +//! Field names and the `untagged` variant order mirror `wa-ir` exactly. An +//! untagged enum resolves to its first matching variant, so reordering `Scalar` +//! or [`TypeNode`] silently retypes generated fields; keep them as declared. + +use std::collections::BTreeMap; + +use serde::Deserialize; + +/// The IR contract version this tool was written against. A whatspec bundle +/// stamping a different major reshapes the documents below, so refuse it rather +/// than deserialize a shape we no longer understand. +pub const SUPPORTED_SCHEMA_MAJOR: &str = "2"; + +/// Fields every domain document carries, used to prove the domains were all +/// extracted from one WhatsApp build. +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Envelope { + pub schema_version: String, + pub wa_version: String, +} + +/// `generated/manifest.json`, reduced to the stamp we check. +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Manifest { + pub schema_version: String, + pub wa_version: String, +} + +/// A JSON scalar literal. `untagged`, so it renders as the bare JSON value and +/// the surrounding `valueType` says which arm to expect. +#[derive(Debug, Clone, Deserialize)] +#[serde(untagged)] +pub enum Scalar { + Bool(bool), + Int(i64), + Float(f64), + Str(String), +} + +/// The declared value type of an A/B prop. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum AbPropType { + Bool, + Int, + String, + Float, +} + +/// One feature flag: name, the numeric code sent in the `` IQ, and its +/// default. A flag can appear in more than one registry, so `module` is part of +/// its identity. +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AbPropConfig { + pub module: String, + pub name: String, + pub code: u32, + pub value_type: AbPropType, + pub default: Scalar, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AbPropsIr { + pub wa_version: String, + pub configs: Vec, +} + +/// One element of an action's mutation index; `type` discriminates the shape. +#[derive(Debug, Clone, Deserialize)] +#[serde(tag = "type")] +pub enum IndexPart { + #[serde(rename = "literal")] + Literal { value: String }, + #[serde(rename = "jid")] + Jid { name: String }, + #[serde(rename = "boolString")] + BoolString { name: String }, + #[serde(rename = "jidOrZero")] + JidOrZero { name: String }, + #[serde(rename = "enum", rename_all = "camelCase")] + Enum { name: String, proto_enum: String }, + #[serde(rename = "string")] + StringPart { name: String }, + #[serde(rename = "unknown")] + Unknown { name: String }, +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AppstateAction { + pub module: String, + pub name: String, + pub collection: Option, + pub version: Option, + pub scope: String, + pub value_field: Option, + pub value_proto_type: Option, + pub value_enum_fields: Option>, + pub chat_jid_index: Option, + pub index_parts: Vec, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AppstateIr { + pub wa_version: String, + pub collections: Vec, + pub actions: BTreeMap, +} + +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum MexOperationKind { + Query, + Mutation, +} + +impl MexOperationKind { + pub fn as_str(self) -> &'static str { + match self { + Self::Query => "query", + Self::Mutation => "mutation", + } + } +} + +/// A node in a `variablesShape` / `response` type tree: an object, a +/// single-element array standing for a plural field, or a scalar type tag +/// (`"string"`, `"number"`, `"boolean"`, `"enum:A|B"`, `"unknown"`). +#[derive(Debug, Clone, Deserialize)] +#[serde(untagged)] +pub enum TypeNode { + Object(BTreeMap), + Array(Vec), + Leaf(String), +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MexOperation { + pub original_name: String, + pub doc_id: String, + pub operation_kind: MexOperationKind, + #[serde(default)] + pub variables_shape: BTreeMap, + #[serde(default)] + pub response: BTreeMap, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MexIr { + pub wa_version: String, + pub operations: BTreeMap, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TokensIr { + pub single_byte: Vec, + pub double_byte: Vec>, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn scalar_arms_follow_the_json_type() { + let parse = |s: &str| serde_json::from_str::(s).expect("scalar"); + assert!(matches!(parse("true"), Scalar::Bool(true))); + assert!(matches!(parse("7"), Scalar::Int(7))); + assert!(matches!(parse("1.5"), Scalar::Float(_))); + assert!(matches!(parse("\"x\""), Scalar::Str(_))); + // A whole-number JSON literal is an Int even when the flag is declared + // float; the emitter renders the arm, not the declared type. + assert!(matches!(parse("0"), Scalar::Int(0))); + } + + #[test] + fn type_node_prefers_object_then_array_then_leaf() { + let parse = |s: &str| serde_json::from_str::(s).expect("node"); + assert!(matches!(parse(r#"{"a":"string"}"#), TypeNode::Object(_))); + assert!(matches!(parse(r#"["string"]"#), TypeNode::Array(_))); + assert!(matches!(parse(r#""number""#), TypeNode::Leaf(_))); + } + + #[test] + fn index_part_reads_every_wire_tag() { + let parts: Vec = serde_json::from_str( + r#"[{"type":"literal","value":"a"}, + {"type":"jid","name":"chatJid"}, + {"type":"boolString","name":"fromMe"}, + {"type":"jidOrZero","name":"participant"}, + {"type":"enum","name":"k","protoEnum":"A.B"}, + {"type":"string","name":"id"}, + {"type":"unknown","name":"x"}]"#, + ) + .expect("index parts"); + assert_eq!(parts.len(), 7); + assert!(matches!(&parts[4], IndexPart::Enum { proto_enum, .. } if proto_enum == "A.B")); + } + + #[test] + fn an_unknown_index_part_tag_is_rejected() { + // A whatspec release that adds an index-part kind must fail loudly here + // rather than emit a registry missing an index slot. + let err = serde_json::from_str::(r#"{"type":"quantum","name":"x"}"#); + assert!(err.is_err(), "unknown index-part tag must not deserialize"); + } +} diff --git a/tools/whatspec-codegen/src/main.rs b/tools/whatspec-codegen/src/main.rs new file mode 100644 index 000000000..0f6e069ed --- /dev/null +++ b/tools/whatspec-codegen/src/main.rs @@ -0,0 +1,606 @@ +//! Regenerates the whatspec-derived artifacts committed in this repository. +//! +//! whatspec publishes a language-neutral IR (`generated/*/index.json`) and no +//! longer commits Rust, so refreshing a vendored file is no longer a copy. This +//! tool is the missing half: it reads that IR at a pinned commit and writes the +//! files `build` lists, in the shape `wacore` already exposes. +//! +//! ```text +//! cargo run -p whatspec-codegen # regenerate from the pinned commit +//! cargo run -p whatspec-codegen -- --check # fail if the tree has drifted +//! cargo run -p whatspec-codegen -- --from ../whatspec/generated +//! cargo run -p whatspec-codegen -- --update-lock --rev main +//! ``` +//! +//! Regeneration is all-or-nothing on purpose. Every artifact carries the same +//! `waVersion` stamp, and the version a device announces is generated from it, +//! so refreshing one domain alone is the drift this tool exists to remove. + +// A CLI's output is its interface; the workspace print lints are aimed at the +// library, where diagnostics belong in `log`. +#![allow(clippy::print_stdout, clippy::print_stderr)] + +mod emit; +mod ir; +mod naming; +mod source; + +use std::path::{Path, PathBuf}; +use std::process::Command; + +use anyhow::{Context, Result, bail, ensure}; + +use source::{Ir, Lock}; + +/// The one IR document that is not JSON, so the envelope loop cannot reach it. +const PROTO_IR: &str = "proto/WAProto.proto"; + +/// Its committed counterpart, whose descriptor `--check` also validates. +const PROTO_ARTIFACT: &str = "waproto/src/whatsapp.proto"; + +/// Where the IR comes from. +#[derive(Debug)] +enum Origin { + /// The commit the lock pins, fetched into the target directory. + Pinned, + /// A whatspec `generated/` directory the caller already has. + Local(PathBuf), +} + +#[derive(Debug)] +struct Options { + origin: Origin, + check: bool, + update_lock: bool, + /// Ref to resolve when updating the lock. + git_ref: String, + /// Skip the `protoc` step, for a machine that has no protoc. + skip_proto_desc: bool, +} + +const USAGE: &str = "\ +Usage: cargo run -p whatspec-codegen -- [options] + + --check Do not write; exit non-zero if any artifact differs. + --from Read a whatspec `generated/` directory instead of fetching. + --update-lock Re-pin the lock to --rev and rewrite it. + --rev Ref to pin when updating the lock (default: main). + --skip-proto-desc Do not run protoc after writing the .proto. + -h, --help This message. +"; + +/// One committed file: its path in the repo and its generated content. +struct Artifact { + /// Repo-relative, so the diagnostics name the file a reader can open. + path: &'static str, + content: String, + /// Whether the content is Rust and has to go through rustfmt. + rust: bool, +} + +fn main() -> Result<()> { + let opts = parse_args(std::env::args().skip(1))?; + let repo_root = repo_root(); + let lock_path = repo_root.join("tools/whatspec-codegen/whatspec.lock.json"); + let mut lock = Lock::read(&lock_path)?; + + if opts.update_lock { + lock.rev = source::resolve_rev(&lock.repo, &opts.git_ref)?; + println!("pinning {} at {}", lock.repo, lock.rev); + } + + let ir = match &opts.origin { + Origin::Local(dir) => source::read_generated_dir(dir)?, + Origin::Pinned => { + source::fetch_pinned(&lock.repo, &lock.rev, &repo_root.join("target/whatspec-ir"))? + } + }; + + let wa_version = stamped_version(&ir)?; + if !opts.update_lock { + source::verify(&ir, &lock)?; + ensure!( + lock.wa_version == wa_version, + "lock says WhatsApp {} but the IR stamps {wa_version}; run --update-lock", + lock.wa_version + ); + } + + // Before the lock is touched: the emitters reject a lost proto anchor, an + // invalid token table and an unrepresentable version, and a lock pinning a + // build that no committed artifact describes is worse than no new lock. + let artifacts = build(&ir, &wa_version)?; + if opts.check { + return check(&repo_root, &artifacts); + } + + // Before anything is written, for the same reason. `write` replaces the + // `.proto` but not the descriptor beside it, so discovering a missing protoc + // afterwards leaves a tree whose two halves describe different schemas and + // which does not build. + if !opts.skip_proto_desc { + require_protoc()?; + } + write(&repo_root, &artifacts)?; + if !opts.skip_proto_desc { + regenerate_proto_descriptor(&repo_root)?; + } + if opts.update_lock { + lock.wa_version = wa_version.clone(); + lock.files = ir.digests(); + lock.write(&lock_path)?; + println!("wrote {}", lock_path.display()); + } + println!( + "regenerated {} artifacts at WhatsApp {wa_version}", + artifacts.len() + ); + Ok(()) +} + +fn parse_args(args: impl Iterator) -> Result { + let mut opts = Options { + origin: Origin::Pinned, + check: false, + update_lock: false, + git_ref: "main".to_string(), + skip_proto_desc: false, + }; + let mut args = args.peekable(); + while let Some(arg) = args.next() { + match arg.as_str() { + "--check" => opts.check = true, + "--update-lock" => opts.update_lock = true, + "--skip-proto-desc" => opts.skip_proto_desc = true, + "--from" => { + let dir = args.next().context("--from needs a directory")?; + opts.origin = Origin::Local(PathBuf::from(dir)); + } + "--rev" => opts.git_ref = args.next().context("--rev needs a git ref")?, + "-h" | "--help" => { + println!("{USAGE}"); + std::process::exit(0); + } + other => bail!("unknown argument {other:?}\n\n{USAGE}"), + } + } + ensure!( + !(opts.check && opts.update_lock), + "--check and --update-lock contradict each other" + ); + // A lock says "commit X hashes to these digests". Resolving the rev against + // the remote while hashing an unrelated local tree writes a claim nobody + // ever checked, and it only surfaces on the next pinned run. + ensure!( + !(opts.update_lock && matches!(opts.origin, Origin::Local(_))), + "--from and --update-lock contradict each other: the lock would pin a remote rev and record local digests" + ); + Ok(opts) +} + +/// The workspace root, from this crate's manifest directory. +fn repo_root() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .and_then(Path::parent) + .expect("the crate lives at /tools/whatspec-codegen") + .to_path_buf() +} + +/// The one WhatsApp build every IR document must agree on. +/// +/// whatspec emits the domains from a single bundle set, so a disagreement means +/// the tree was assembled from two runs and the artifacts would be internally +/// inconsistent, which is the failure this tool replaces. +fn stamped_version(ir: &Ir) -> Result { + let manifest: ir::Manifest = + serde_json::from_str(&ir.text("manifest.json")?).context("parsing manifest.json")?; + let major = manifest + .schema_version + .split('.') + .next() + .unwrap_or_default(); + ensure!( + major == ir::SUPPORTED_SCHEMA_MAJOR, + "whatspec IR schemaVersion {} is not supported (this tool reads {}.x)", + manifest.schema_version, + ir::SUPPORTED_SCHEMA_MAJOR + ); + + for rel in source::IR_FILES { + if !rel.ends_with("index.json") { + continue; + } + let envelope: ir::Envelope = serde_json::from_str(&ir.text(rel)?) + .with_context(|| format!("parsing the envelope of {rel}"))?; + ensure!( + envelope.wa_version == manifest.wa_version, + "{rel} stamps WhatsApp {} but the manifest stamps {}", + envelope.wa_version, + manifest.wa_version + ); + ensure!( + envelope.schema_version == manifest.schema_version, + "{rel} stamps IR schema {} but the manifest stamps {}", + envelope.schema_version, + manifest.schema_version + ); + } + + // The proto is the one domain with no JSON envelope, so skipping it here is + // how a schema from a different build reaches `whatsapp.proto` while every + // JSON-derived registry agrees. It carries the same stamp as a comment. + let proto = ir.text(PROTO_IR)?; + let stamped = proto + .lines() + .find_map(|l| l.trim().strip_prefix("/// WhatsApp Version:")) + .map(str::trim) + .with_context(|| format!("{PROTO_IR} carries no `/// WhatsApp Version:` header"))?; + ensure!( + stamped == manifest.wa_version, + "{PROTO_IR} stamps WhatsApp {stamped} but the manifest stamps {}", + manifest.wa_version + ); + + Ok(manifest.wa_version) +} + +fn build(ir: &Ir, wa_version: &str) -> Result> { + let abprops: ir::AbPropsIr = + serde_json::from_str(&ir.text("abprops/index.json")?).context("parsing the abprops IR")?; + let appstate: ir::AppstateIr = serde_json::from_str(&ir.text("appstate/index.json")?) + .context("parsing the appstate IR")?; + let mex: ir::MexIr = + serde_json::from_str(&ir.text("mex/index.json")?).context("parsing the mex IR")?; + let tokens: ir::TokensIr = + serde_json::from_str(&ir.text("tokens/index.json")?).context("parsing the tokens IR")?; + + Ok(vec![ + Artifact { + path: "wacore/src/version/generated.rs", + content: emit::version::generate(wa_version)?, + rust: true, + }, + Artifact { + path: "wacore/src/iq/abprops.rs", + content: emit::abprops::generate(&abprops)?, + rust: true, + }, + Artifact { + path: "wacore/src/iq/mex_operations.rs", + content: emit::mex::generate(&mex), + rust: true, + }, + Artifact { + path: "wacore/appstate/src/schemas.rs", + content: emit::appstate::generate(&appstate)?, + rust: true, + }, + Artifact { + path: "wacore/binary/src/tokens.json", + content: emit::tokens::generate(&tokens)?, + rust: false, + }, + Artifact { + path: PROTO_ARTIFACT, + content: emit::proto::generate(&ir.text(PROTO_IR)?)?, + rust: false, + }, + ]) +} + +fn write(root: &Path, artifacts: &[Artifact]) -> Result<()> { + for a in artifacts { + let path = root.join(a.path); + let content = finalize(root, a)?; + // Leave the mtime alone when nothing changed: these files feed build + // scripts whose rerun-if-changed would otherwise rebuild the workspace. + if std::fs::read_to_string(&path).is_ok_and(|old| old == content) { + println!("unchanged {}", a.path); + continue; + } + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::write(&path, &content).with_context(|| format!("writing {}", path.display()))?; + println!("wrote {}", a.path); + } + Ok(()) +} + +fn check(root: &Path, artifacts: &[Artifact]) -> Result<()> { + let mut stale = Vec::new(); + for a in artifacts { + let path = root.join(a.path); + let content = finalize(root, a)?; + match std::fs::read_to_string(&path) { + Ok(on_disk) if on_disk == content => {} + Ok(_) => stale.push(a.path), + Err(e) => { + eprintln!("{}: {e}", a.path); + stale.push(a.path); + } + } + } + ensure!( + stale.is_empty(), + "these artifacts do not match the pinned IR: {}\nrun `cargo run -p whatspec-codegen`", + stale.join(", ") + ); + let proto = artifacts + .iter() + .find(|a| a.path == PROTO_ARTIFACT) + .with_context(|| format!("{PROTO_ARTIFACT} is not in the artifact set"))?; + check_proto_descriptor(root, &proto.content)?; + println!("all artifacts match the pinned IR"); + Ok(()) +} + +/// The descriptor beside the `.proto` describes the same schema. +/// +/// `--check` would otherwise pass on a tree regenerated with `--skip-proto-desc` +/// or with a hand-edited `.desc`, and the contradiction would surface much later +/// as a `waproto` build failure in a different job. Comparing the recorded +/// hashes catches it here and needs no protoc. +fn check_proto_descriptor(root: &Path, proto: &str) -> Result<()> { + let hashes = root.join("waproto/src/whatsapp.desc.sha256"); + let text = std::fs::read_to_string(&hashes) + .with_context(|| format!("reading {}", hashes.display()))?; + let recorded = |key: &str| -> Result { + text.lines() + .find_map(|l| l.strip_prefix(key).map(|h| h.trim().to_string())) + .with_context(|| format!("{} has no `{key}` line", hashes.display())) + }; + let desc = std::fs::read(root.join("waproto/src/whatsapp.desc")) + .context("reading waproto/src/whatsapp.desc")?; + for (what, want, got) in [ + ("proto", recorded("proto ")?, sha256_hex(proto.as_bytes())), + ("desc", recorded("desc ")?, sha256_hex(&desc)), + ] { + ensure!( + want == got, + "waproto/src/whatsapp.desc.sha256 records {what} {want} but the {} hashes to {got}\n\ + run `cargo run -p whatspec-codegen` (or scripts/regenerate-proto-desc.sh)", + if what == "proto" { + "generated schema" + } else { + "committed descriptor" + } + ); + } + Ok(()) +} + +fn sha256_hex(bytes: &[u8]) -> String { + use sha2::{Digest, Sha256}; + Sha256::digest(bytes) + .iter() + .fold(String::new(), |mut s, b| { + s.push_str(&format!("{b:02x}")); + s + }) +} + +/// The exact bytes an artifact should have on disk, rustfmt included. +fn finalize(root: &Path, a: &Artifact) -> Result { + if a.rust { + rustfmt(root, &a.content) + } else { + Ok(a.content.clone()) + } +} + +/// Format through the repository's pinned rustfmt. +/// +/// Via a scratch file rather than stdin so `--check` can format without touching +/// the tree, and run from the workspace root so `rust-toolchain.toml` selects the +/// same rustfmt CI runs. +fn rustfmt(root: &Path, source: &str) -> Result { + let dir = root.join("target/whatspec-codegen"); + std::fs::create_dir_all(&dir)?; + // Per-process, because CI's `--check` and a developer regenerating in the + // same checkout would otherwise overwrite each other's scratch between the + // write and the read-back, and the loser commits the winner's bytes. + let path = dir.join(format!("scratch-{}.rs", std::process::id())); + std::fs::write(&path, source)?; + let out = Command::new("rustfmt") + .current_dir(root) + .arg("--edition") + .arg("2024") + .arg(&path) + .output() + .context("running rustfmt (install it with `rustup component add rustfmt`)")?; + ensure!( + out.status.success(), + "rustfmt rejected generated source: {}", + String::from_utf8_lossy(&out.stderr).trim() + ); + let formatted = std::fs::read_to_string(&path).context("reading back the formatted source")?; + let _ = std::fs::remove_file(&path); + Ok(formatted) +} + +/// Rebuild `whatsapp.desc` from the `.proto` we just wrote. +/// +/// The descriptor is what `waproto`'s build script compiles, and it carries a +/// hash of the `.proto` beside it, so leaving it behind fails the next build +/// rather than shipping a stale schema. +/// Fail before writing when the descriptor step could not run afterwards. +fn require_protoc() -> Result<()> { + let found = Command::new("protoc") + .arg("--version") + .output() + .is_ok_and(|o| o.status.success()); + ensure!( + found, + "protoc is not on PATH, and the descriptor is regenerated from the schema this run \ + writes.\nInstall it, or pass --skip-proto-desc and run scripts/regenerate-proto-desc.sh \ + yourself." + ); + Ok(()) +} + +fn regenerate_proto_descriptor(root: &Path) -> Result<()> { + let script = root.join("scripts/regenerate-proto-desc.sh"); + let status = Command::new("bash") + .arg(&script) + .current_dir(root) + .status() + .with_context(|| format!("running {}", script.display()))?; + ensure!( + status.success(), + "{} failed; install protoc, or pass --skip-proto-desc and run it yourself", + script.display() + ); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn parse(args: &[&str]) -> Result { + parse_args(args.iter().map(|s| s.to_string())) + } + + #[test] + fn defaults_to_regenerating_from_the_pinned_commit() { + let o = parse(&[]).expect("defaults"); + assert!(matches!(o.origin, Origin::Pinned)); + assert!(!o.check && !o.update_lock && !o.skip_proto_desc); + assert_eq!(o.git_ref, "main"); + } + + #[test] + fn reads_the_flags_it_documents() { + let o = + parse(&["--check", "--from", "/tmp/generated", "--skip-proto-desc"]).expect("flags"); + assert!(o.check && o.skip_proto_desc); + assert!(matches!(&o.origin, Origin::Local(p) if p == Path::new("/tmp/generated"))); + let o = parse(&["--update-lock", "--rev", "abc"]).expect("flags"); + assert!(o.update_lock); + assert_eq!(o.git_ref, "abc"); + } + + #[test] + fn rejects_unknown_and_contradictory_arguments() { + assert!(parse(&["--wat"]).is_err()); + assert!(parse(&["--from"]).is_err(), "--from needs a value"); + assert!(parse(&["--rev"]).is_err(), "--rev needs a value"); + // --check proves the tree matches the lock; --update-lock rewrites the + // lock to match the tree. Together they prove nothing. + assert!(parse(&["--check", "--update-lock"]).is_err()); + let err = parse(&["--from", "/tmp/ir", "--update-lock"]) + .expect_err("--from cannot source an updated lock"); + assert!( + err.to_string().contains("--from and --update-lock"), + "{err}" + ); + } + + #[test] + fn the_committed_descriptor_hashes_match_the_generated_schema() { + // The real tree, so this fails if someone regenerates the `.proto` with + // --skip-proto-desc and commits without rerunning protoc. + let root = repo_root(); + let proto = std::fs::read_to_string(root.join(PROTO_ARTIFACT)).expect("the proto"); + check_proto_descriptor(&root, &proto).expect("descriptor agrees with the schema"); + + let err = check_proto_descriptor(&root, "syntax = \"proto2\";\n") + .expect_err("a different schema must not pass"); + assert!(format!("{err:#}").contains("records proto"), "{err:#}"); + } + + #[test] + fn repo_root_holds_the_workspace_manifest() { + assert!(repo_root().join("Cargo.toml").is_file()); + assert!(repo_root().join("wacore/src/iq/abprops.rs").is_file()); + } + + fn ir_from(files: &[(&str, String)]) -> Ir { + Ir { + files: files + .iter() + .map(|(k, v)| (k.to_string(), v.as_bytes().to_vec())) + .collect(), + } + } + + fn envelope(schema: &str, wa: &str) -> String { + format!(r#"{{"schemaVersion":"{schema}","waVersion":"{wa}"}}"#) + } + + /// The proto carries its stamp as a comment rather than a JSON envelope. + fn proto_stub(wa: &str) -> String { + format!("syntax = \"proto2\";\n\n/// WhatsApp Version: {wa}\n") + } + + fn ir_files(schema: &str, wa: &str) -> Vec<(&'static str, String)> { + source::IR_FILES + .iter() + .map(|f| { + let body = if *f == PROTO_IR { + proto_stub(wa) + } else { + envelope(schema, wa) + }; + (*f, body) + }) + .collect() + } + + #[test] + fn stamped_version_agrees_across_domains() { + assert_eq!( + stamped_version(&ir_from(&ir_files("2.0.0", "2.3000.7"))).expect("stamp"), + "2.3000.7" + ); + } + + #[test] + fn a_domain_from_another_build_stops_the_run() { + // The exact drift this tool replaces: abprops and mex vendored from two + // different WhatsApp releases. + let mut files = ir_files("2.0.0", "2.3000.7"); + let mex = files + .iter_mut() + .find(|(f, _)| *f == "mex/index.json") + .expect("mex"); + mex.1 = envelope("2.0.0", "2.3000.8"); + let err = stamped_version(&ir_from(&files)).expect_err("mixed builds"); + assert!(err.to_string().contains("mex/index.json"), "{err}"); + } + + #[test] + fn a_proto_from_another_build_stops_the_run() { + // The proto has no JSON envelope, so the loop above cannot see it. It is + // the one domain whose drift would otherwise reach whatsapp.proto with + // every other registry agreeing. + let mut files = ir_files("2.0.0", "2.3000.7"); + let proto = files + .iter_mut() + .find(|(f, _)| *f == PROTO_IR) + .expect("proto"); + proto.1 = proto_stub("2.3000.8"); + let err = stamped_version(&ir_from(&files)).expect_err("mixed builds"); + assert!(err.to_string().contains(PROTO_IR), "{err}"); + } + + #[test] + fn a_proto_with_no_version_header_stops_the_run() { + let mut files = ir_files("2.0.0", "2.3000.7"); + let proto = files + .iter_mut() + .find(|(f, _)| *f == PROTO_IR) + .expect("proto"); + proto.1 = "syntax = \"proto2\";\n".to_string(); + let err = stamped_version(&ir_from(&files)).expect_err("no stamp to compare"); + assert!(err.to_string().contains("carries no"), "{err}"); + } + + #[test] + fn an_unsupported_ir_schema_major_stops_the_run() { + let err = stamped_version(&ir_from(&ir_files("3.0.0", "2.3000.7"))).expect_err("schema 3"); + assert!(err.to_string().contains("not supported"), "{err}"); + } +} diff --git a/tools/whatspec-codegen/src/naming.rs b/tools/whatspec-codegen/src/naming.rs new file mode 100644 index 000000000..3f892fc67 --- /dev/null +++ b/tools/whatspec-codegen/src/naming.rs @@ -0,0 +1,253 @@ +//! Identifier casing and keyword escaping for the emitted Rust. +//! +//! These rules decide the public names of the generated registries, so they are +//! reproduced exactly as whatspec's reference emitter defines them: a bundle key +//! must keep mapping to the same `pub const` / `pub mod` across regenerations, +//! or a refresh silently renames API. + +use std::collections::HashSet; + +const RUST_KEYWORDS: &[&str] = &[ + "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", + "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", + "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", + "while", "async", "await", "dyn", "gen", "abstract", "become", "box", "do", "final", "macro", + "override", "priv", "try", "typeof", "unsized", "virtual", "yield", +]; + +/// Keywords a raw identifier cannot spell (`r#self` is a compile error), so they +/// are disambiguated with a suffix instead. +const RAW_INELIGIBLE: &[&str] = &["self", "Self", "crate", "super"]; + +/// Coerce an arbitrary string into a usable Rust identifier: non-empty, not +/// digit-led, keyword-safe. A no-op on the ordinary alphanumeric bundle names. +pub fn ensure_ident(s: &str) -> String { + let base = if s.is_empty() { + "_".to_string() + } else if s.starts_with(|c: char| c.is_ascii_digit()) { + format!("_{s}") + } else { + s.to_string() + }; + if RAW_INELIGIBLE.contains(&base.as_str()) { + format!("{base}_") + } else if RUST_KEYWORDS.contains(&base.as_str()) { + format!("r#{base}") + } else { + base + } +} + +/// Separate `fooBar` into `fooBar`. +fn split_lower_upper(s: &str, sep: char) -> String { + let chars: Vec = s.chars().collect(); + let mut out = String::with_capacity(s.len() + 8); + for (i, &c) in chars.iter().enumerate() { + if i > 0 && c.is_ascii_uppercase() { + let prev = chars[i - 1]; + if prev.is_ascii_lowercase() || prev.is_ascii_digit() { + out.push(sep); + } + } + out.push(c); + } + out +} + +/// Separate a run of capitals from the word that follows it: `HTTPServer` into +/// `HTTPServer`. The break goes before the last capital of the run, which +/// is the one that starts the next word. +fn split_acronym(s: &str, sep: char) -> String { + let chars: Vec = s.chars().collect(); + let mut out = String::with_capacity(s.len() + 8); + for (i, &c) in chars.iter().enumerate() { + if i > 0 + && i + 1 < chars.len() + && c.is_ascii_uppercase() + && chars[i - 1].is_ascii_uppercase() + && chars[i + 1].is_ascii_lowercase() + { + out.push(sep); + } + out.push(c); + } + out +} + +fn non_alnum_to(s: &str, sep: char) -> String { + s.chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { sep }) + .collect() +} + +/// `FooBar` / `foo-bar` into `foo_bar`. +pub fn snake_case(s: &str) -> String { + let s = split_lower_upper(s, '_'); + let s = split_acronym(&s, '_'); + let s = non_alnum_to(&s, '_'); + let mut collapsed = String::with_capacity(s.len()); + let mut last_underscore = false; + for c in s.chars() { + if c == '_' { + if !last_underscore { + collapsed.push(c); + } + last_underscore = true; + } else { + collapsed.push(c); + last_underscore = false; + } + } + collapsed.trim_matches('_').to_lowercase() +} + +/// `foo_bar` / `fooBar` into `FooBar`, coerced into a valid Rust type or +/// variant identifier. +pub fn pascal_case(s: &str) -> String { + let s = split_lower_upper(s, ' '); + let s = split_acronym(&s, ' '); + let s = non_alnum_to(&s, ' '); + let pascal: String = s + .split_whitespace() + .map(|w| { + let mut c = w.chars(); + match c.next() { + Some(first) => first.to_uppercase().collect::() + c.as_str(), + None => String::new(), + } + }) + .collect(); + ensure_ident(&pascal) +} + +/// `snake_case` coerced into a valid, keyword-safe Rust identifier. +pub fn rust_ident(s: &str) -> String { + ensure_ident(&snake_case(s)) +} + +/// Make `base` a unique, ident-safe name within `used`, falling back to +/// `fallback_prefix` when the bundle name is empty and appending a numeric +/// suffix on collision. +pub fn unique_ident(base: &str, used: &mut HashSet, fallback_prefix: &str) -> String { + let mut name = if base.is_empty() { + ensure_ident(fallback_prefix) + } else { + ensure_ident(base) + }; + if used.contains(&name) { + let mut n = 2; + while used.contains(&format!("{name}_{n}")) { + n += 1; + } + name = format!("{name}_{n}"); + } + used.insert(name.clone()); + name +} + +/// [`unique_ident`] for a name that has to stay UpperCamelCase. +/// +/// The `_2` suffix would make an enum variant trip `non_camel_case_types`, and +/// the generated file is compiled with warnings denied. +pub fn unique_type_ident(base: &str, used: &mut HashSet, fallback_prefix: &str) -> String { + let mut name = ensure_ident(if base.is_empty() { + fallback_prefix + } else { + base + }); + if used.contains(&name) { + let mut n = 2; + while used.contains(&format!("{name}{n}")) { + n += 1; + } + name = format!("{name}{n}"); + } + used.insert(name.clone()); + name +} + +/// A fully escaped Rust string literal. Bundle strings are ordinarily plain, but +/// this stays correct for one carrying a quote, a backslash or a control byte. +pub fn rust_lit(s: &str) -> String { + format!("{s:?}") +} + +/// A valid Rust `f64` literal. `{:?}` renders finite values as literals but +/// spells the others `NaN`/`inf`, which are not. +pub fn float_lit(f: f64) -> String { + if f.is_nan() { + "f64::NAN".to_string() + } else if f.is_infinite() { + if f > 0.0 { + "f64::INFINITY".to_string() + } else { + "f64::NEG_INFINITY".to_string() + } + } else { + format!("{f:?}") + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn casing_matches_the_reference_rules() { + assert_eq!(snake_case("FooBarBaz"), "foo_bar_baz"); + assert_eq!(snake_case("HTTPServer"), "http_server"); + assert_eq!(snake_case("w:g2"), "w_g2"); + assert_eq!( + snake_case("ACSServerProviderConfig"), + "acs_server_provider_config" + ); + assert_eq!( + snake_case("__leading__and__trailing__"), + "leading_and_trailing" + ); + assert_eq!(pascal_case("foo_bar"), "FooBar"); + assert_eq!(pascal_case("getGroupInfo"), "GetGroupInfo"); + assert_eq!( + pascal_case("xwa2_newsletter_admin_invite_accept"), + "Xwa2NewsletterAdminInviteAccept" + ); + // A digit run does not start a new word, so the capital after it does. + assert_eq!(snake_case("mlow2Codec"), "mlow2_codec"); + } + + #[test] + fn keyword_and_shape_escaping() { + assert_eq!(rust_ident("type"), "r#type"); + assert_eq!(rust_ident("name"), "name"); + // self/Self/crate/super cannot be raw identifiers. + assert_eq!(rust_ident("self"), "self_"); + assert_eq!(pascal_case("self"), "Self_"); + // `gen` became a keyword in edition 2024; a bundle field named `gen` + // would otherwise emit a struct that does not parse. + assert_eq!(rust_ident("gen"), "r#gen"); + assert_eq!(rust_ident("2fa"), "_2fa"); + assert_eq!(pascal_case("123"), "_123"); + assert_eq!(ensure_ident(""), "_"); + } + + #[test] + fn unique_ident_sanitizes_and_disambiguates() { + let mut used = HashSet::new(); + assert_eq!(unique_ident("match", &mut used, "m"), "r#match"); + assert_eq!(unique_ident("self", &mut used, "m"), "self_"); + assert_eq!(unique_ident("foo", &mut used, "m"), "foo"); + assert_eq!(unique_ident("foo", &mut used, "m"), "foo_2"); + assert_eq!(unique_ident("foo", &mut used, "m"), "foo_3"); + assert_eq!(unique_ident("", &mut used, "fallback"), "fallback"); + } + + #[test] + fn literals_stay_valid_for_awkward_bundle_strings() { + assert_eq!(rust_lit("plain"), "\"plain\""); + assert_eq!(rust_lit("a\"b\\c"), "\"a\\\"b\\\\c\""); + assert_eq!(float_lit(0.0), "0.0"); + assert_eq!(float_lit(f64::NAN), "f64::NAN"); + assert_eq!(float_lit(f64::INFINITY), "f64::INFINITY"); + assert_eq!(float_lit(f64::NEG_INFINITY), "f64::NEG_INFINITY"); + } +} diff --git a/tools/whatspec-codegen/src/source.rs b/tools/whatspec-codegen/src/source.rs new file mode 100644 index 000000000..37b699205 --- /dev/null +++ b/tools/whatspec-codegen/src/source.rs @@ -0,0 +1,380 @@ +//! Getting the whatspec IR, and proving it is the one the lock pins. +//! +//! Acquisition is `git`, not HTTP: the lock pins a commit, and fetching that +//! commit reuses whatever credentials, proxy and CA configuration the user's git +//! already has, so the tool works wherever `git clone` does. The per-file +//! digests are checked on top of that, because they are also what makes a local +//! checkout (`--from`) trustworthy. + +use std::collections::BTreeMap; +use std::path::Path; +use std::process::Command; + +use anyhow::{Context, Result, bail, ensure}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; + +/// The IR files this repository consumes. Nothing else is read, so a whatspec +/// domain we do not vendor cannot break a regeneration. +pub const IR_FILES: &[&str] = &[ + "manifest.json", + "abprops/index.json", + "appstate/index.json", + "mex/index.json", + "tokens/index.json", + "proto/WAProto.proto", +]; + +/// `tools/whatspec-codegen/whatspec.lock.json`: which whatspec commit the +/// committed artifacts came from, and what its files hashed to. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Lock { + pub repo: String, + /// Full commit sha. A branch name would not pin anything. + pub rev: String, + pub wa_version: String, + /// Path under `generated/` to its `sha256:` digest. + pub files: BTreeMap, +} + +impl Lock { + pub fn read(path: &Path) -> Result { + let text = std::fs::read_to_string(path) + .with_context(|| format!("reading the lock at {}", path.display()))?; + let lock: Lock = serde_json::from_str(&text) + .with_context(|| format!("parsing the lock at {}", path.display()))?; + ensure!( + lock.rev.len() == 40 && lock.rev.chars().all(|c| c.is_ascii_hexdigit()), + "lock rev {:?} is not a full commit sha; a branch or short sha pins nothing", + lock.rev + ); + Ok(lock) + } + + pub fn write(&self, path: &Path) -> Result<()> { + let text = serde_json::to_string_pretty(self)? + "\n"; + std::fs::write(path, text) + .with_context(|| format!("writing the lock at {}", path.display())) + } +} + +pub fn digest(bytes: &[u8]) -> String { + let mut out = String::from("sha256:"); + for byte in Sha256::digest(bytes) { + out.push_str(&format!("{byte:02x}")); + } + out +} + +/// The IR files, read and (unless `verify` is off) checked against the lock. +pub struct Ir { + pub files: BTreeMap>, +} + +impl Ir { + pub fn get(&self, rel: &str) -> Result<&[u8]> { + self.files + .get(rel) + .map(Vec::as_slice) + .with_context(|| format!("IR file {rel} was not read")) + } + + pub fn text(&self, rel: &str) -> Result { + String::from_utf8(self.get(rel)?.to_vec()) + .with_context(|| format!("IR file {rel} is not UTF-8")) + } + + pub fn digests(&self) -> BTreeMap { + self.files + .iter() + .map(|(k, v)| (k.clone(), digest(v))) + .collect() + } +} + +/// Read `IR_FILES` out of a whatspec `generated/` directory. +pub fn read_generated_dir(dir: &Path) -> Result { + ensure!( + dir.join("manifest.json").is_file(), + "{} does not look like a whatspec `generated/` directory (no manifest.json)", + dir.display() + ); + let mut files = BTreeMap::new(); + for rel in IR_FILES { + let path = dir.join(rel); + let bytes = + std::fs::read(&path).with_context(|| format!("reading IR file {}", path.display()))?; + files.insert((*rel).to_string(), bytes); + } + Ok(Ir { files }) +} + +/// Fetch the pinned commit into `cache` and read its `generated/` tree. +/// +/// The checkout is sparse: `generated/` is the only path this tool reads, and +/// the rest of whatspec is tens of megabytes of bundles. +pub fn fetch_pinned(repo: &str, rev: &str, cache: &Path) -> Result { + let dir = cache.join(rev); + let generated = dir.join("generated"); + // Completeness, not existence: an interrupted checkout leaves the directory + // behind, and treating that as a finished cache entry makes every later run + // skip the fetch and fail in `read_generated_dir` with no way out but + // deleting the cache by hand. + let complete = IR_FILES.iter().all(|rel| generated.join(rel).is_file()); + if !complete { + std::fs::create_dir_all(&dir) + .with_context(|| format!("creating the IR cache at {}", dir.display()))?; + git(&dir, &["init", "--quiet", "."])?; + // Idempotent across a retry of a half-finished cache entry. + let _ = git(&dir, &["remote", "remove", "origin"]); + git(&dir, &["remote", "add", "origin", repo])?; + git(&dir, &["sparse-checkout", "set", "--cone", "generated"])?; + git(&dir, &["fetch", "--quiet", "--depth", "1", "origin", rev]) + .with_context(|| format!("fetching whatspec {rev} from {repo}"))?; + git(&dir, &["checkout", "--quiet", "--force", "FETCH_HEAD"])?; + } + read_generated_dir(&generated) +} + +fn git(dir: &Path, args: &[&str]) -> Result { + let out = Command::new("git") + .arg("-C") + .arg(dir) + .args(args) + .output() + .with_context(|| format!("running `git {}`", args.join(" ")))?; + if !out.status.success() { + bail!( + "`git {}` failed in {}: {}", + args.join(" "), + dir.display(), + String::from_utf8_lossy(&out.stderr).trim() + ); + } + Ok(String::from_utf8_lossy(&out.stdout).trim().to_string()) +} + +/// Resolve a ref (branch, tag or sha) to a full commit sha, for `--update-lock`. +pub fn resolve_rev(repo: &str, git_ref: &str) -> Result { + if git_ref.len() == 40 && git_ref.chars().all(|c| c.is_ascii_hexdigit()) { + return Ok(git_ref.to_string()); + } + let out = Command::new("git") + .args(["ls-remote", repo, git_ref]) + .output() + .context("running `git ls-remote`")?; + ensure!( + out.status.success(), + "`git ls-remote {repo} {git_ref}` failed: {}", + String::from_utf8_lossy(&out.stderr).trim() + ); + let stdout = String::from_utf8_lossy(&out.stdout); + resolve_from_ls_remote(&stdout, repo, git_ref) +} + +/// Pick the one commit a `git ls-remote` listing pins the requested ref to. +/// +/// `ls-remote` matches the *tail* of a ref name, so asking for `main` also +/// prints `refs/heads/feature/main`. Taking the first line would then pin a +/// commit nobody asked for, and the lock records that as fact. Only a ref whose +/// name is exactly ``, `refs/heads/` or `refs/tags/` counts. +fn resolve_from_ls_remote(stdout: &str, repo: &str, git_ref: &str) -> Result { + let wanted = [ + git_ref.to_string(), + format!("refs/heads/{git_ref}"), + format!("refs/tags/{git_ref}"), + ]; + let mut exact: Vec<(&str, &str)> = Vec::new(); + for line in stdout.lines() { + let mut cols = line.split_whitespace(); + let (Some(sha), Some(name)) = (cols.next(), cols.next()) else { + continue; + }; + // An annotated tag prints twice; the `^{}` line carries the commit the + // tag points at, which is what a checkout would land on. + let bare = name.strip_suffix("^{}").unwrap_or(name); + if wanted.iter().any(|w| w == bare) { + exact.push((sha, name)); + } + } + ensure!( + !exact.is_empty(), + "{repo} has no ref named exactly {git_ref:?}" + ); + let names: Vec<&str> = exact + .iter() + .map(|(_, n)| *n) + .filter(|n| !n.ends_with("^{}")) + .collect(); + ensure!( + names.len() <= 1, + "{git_ref:?} is ambiguous in {repo}: it names {}", + names.join(", ") + ); + let sha = exact + .iter() + .find(|(_, n)| n.ends_with("^{}")) + .map_or(exact[0].0, |(sha, _)| *sha); + ensure!( + sha.len() == 40 && sha.chars().all(|c| c.is_ascii_hexdigit()), + "`git ls-remote {repo} {git_ref}` returned {sha:?}, which is not a commit sha" + ); + Ok(sha.to_string()) +} + +/// Every IR file matches the lock, and every domain stamps the same build. +pub fn verify(ir: &Ir, lock: &Lock) -> Result<()> { + let actual = ir.digests(); + for rel in IR_FILES { + let want = lock.files.get(*rel).with_context(|| { + format!("lock does not pin {rel}; regenerate the lock with --update-lock") + })?; + let got = actual + .get(*rel) + .with_context(|| format!("IR file {rel} was never read"))?; + ensure!( + want == got, + "IR file {rel} does not match the lock\n expected {want}\n got {got}" + ); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn lock_with(files: BTreeMap) -> Lock { + Lock { + repo: "https://example.invalid/whatspec".into(), + rev: "0".repeat(40), + wa_version: "2.3000.1".into(), + files, + } + } + + fn ir_with(files: &[(&str, &str)]) -> Ir { + Ir { + files: files + .iter() + .map(|(k, v)| (k.to_string(), v.as_bytes().to_vec())) + .collect(), + } + } + + /// Every IR file, holding `body`. + fn full_ir(body: &str) -> Vec<(&str, &str)> { + IR_FILES.iter().map(|f| (*f, body)).collect() + } + + /// A lock pinning every IR file to the digest of `body`. + fn full_lock(body: &str) -> Lock { + lock_with( + IR_FILES + .iter() + .map(|f| ((*f).to_string(), digest(body.as_bytes()))) + .collect(), + ) + } + + #[test] + fn digest_is_a_prefixed_sha256() { + assert_eq!( + digest(b""), + "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ); + } + + #[test] + fn verify_accepts_a_matching_tree() { + verify(&ir_with(&full_ir("x")), &full_lock("x")).expect("matching tree verifies"); + } + + #[test] + fn verify_rejects_a_tampered_file() { + let mut files = full_ir("x"); + files[1].1 = "tampered"; + let err = verify(&ir_with(&files), &full_lock("x")).expect_err("tampering must be caught"); + assert!(err.to_string().contains(IR_FILES[1]), "{err}"); + } + + #[test] + fn verify_rejects_a_lock_that_does_not_pin_every_file() { + let lock = lock_with(BTreeMap::from([(IR_FILES[0].to_string(), digest(b"x"))])); + let err = verify(&ir_with(&full_ir("x")), &lock).expect_err("incomplete lock"); + assert!(err.to_string().contains("--update-lock"), "{err}"); + } + + #[test] + fn a_half_written_cache_entry_is_not_reused() { + // An interrupted checkout leaves `generated/` behind. Reusing it would + // make every later run fail the same way, with no ordinary retry that + // repairs it. + let cache = std::env::temp_dir().join("whatspec-codegen-cache-test"); + let _ = std::fs::remove_dir_all(&cache); + let generated = cache.join("deadbeef").join("generated"); + std::fs::create_dir_all(generated.join("abprops")).expect("partial cache"); + std::fs::write(generated.join("manifest.json"), b"{}").expect("one file"); + + // No network: the reuse branch would have returned a read error for the + // missing files, so reaching git at all is what proves the entry was + // rejected. + let msg = match fetch_pinned("file:///nonexistent-whatspec", "deadbeef", &cache) { + Err(e) => format!("{e:#}"), + Ok(_) => panic!("an incomplete entry must be refetched"), + }; + assert!(!msg.contains("reading IR file"), "{msg}"); + + let _ = std::fs::remove_dir_all(&cache); + } + + #[test] + fn a_ref_resolves_only_against_an_exact_ref_name() { + let sha = "a".repeat(40); + let other = "b".repeat(40); + // `ls-remote` matches ref-name tails, so asking for `main` also prints + // `feature/main`. Pinning that would record a commit nobody asked for. + let only_tail = format!("{other}\trefs/heads/feature/main\n"); + let err = resolve_from_ls_remote(&only_tail, "r", "main").expect_err("tail is not a match"); + assert!(err.to_string().contains("no ref named exactly"), "{err}"); + + let both = format!("{sha}\trefs/heads/main\n{other}\trefs/heads/feature/main\n"); + assert_eq!( + resolve_from_ls_remote(&both, "r", "main").expect("exact"), + sha + ); + } + + #[test] + fn an_annotated_tag_resolves_to_the_commit_it_points_at() { + let tag = "c".repeat(40); + let commit = "d".repeat(40); + let out = format!("{tag}\trefs/tags/v1.0\n{commit}\trefs/tags/v1.0^{{}}\n"); + assert_eq!( + resolve_from_ls_remote(&out, "r", "v1.0").expect("peeled"), + commit + ); + } + + #[test] + fn a_ref_line_that_is_not_a_sha_is_rejected() { + let err = resolve_from_ls_remote("not-a-sha\trefs/heads/main\n", "r", "main") + .expect_err("a lock may only pin a commit"); + assert!(err.to_string().contains("not a commit sha"), "{err}"); + } + + #[test] + fn a_lock_pinning_a_branch_is_rejected() { + let dir = std::env::temp_dir().join("whatspec-codegen-lock-test"); + std::fs::create_dir_all(&dir).expect("temp dir"); + let path = dir.join("branch.json"); + std::fs::write( + &path, + r#"{"repo":"r","rev":"main","waVersion":"2.3000.1","files":{}}"#, + ) + .expect("write"); + let err = Lock::read(&path).expect_err("a branch pins nothing"); + assert!(err.to_string().contains("pins nothing"), "{err}"); + } +} diff --git a/tools/whatspec-codegen/tests/committed_artifacts.rs b/tools/whatspec-codegen/tests/committed_artifacts.rs new file mode 100644 index 000000000..047148b84 --- /dev/null +++ b/tools/whatspec-codegen/tests/committed_artifacts.rs @@ -0,0 +1,120 @@ +//! The committed artifacts all describe one WhatsApp build. +//! +//! This is the offline half of `--check`: it needs no whatspec checkout, so it +//! runs in the ordinary test matrix and catches the failure that actually +//! happened before this tool existed, which is a single domain being refreshed +//! on its own. `--check` covers the rest, byte for byte, against the pinned IR. + +use std::path::{Path, PathBuf}; + +fn repo_root() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .and_then(Path::parent) + .expect("the crate lives at /tools/whatspec-codegen") + .to_path_buf() +} + +fn read(rel: &str) -> String { + let path = repo_root().join(rel); + std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("reading {}: {e}", path.display())) +} + +/// The version out of `(WhatsApp )` in a generated file's first line. +fn stamped_in_header(text: &str) -> Option<&str> { + let line = text.lines().next()?; + let start = line.find("(WhatsApp ")? + "(WhatsApp ".len(); + let rest = &line[start..]; + Some(&rest[..rest.find(')')?]) +} + +/// The version the lock pins, read without a JSON dependency in the test. +fn locked_version() -> String { + let lock = read("tools/whatspec-codegen/whatspec.lock.json"); + let key = "\"waVersion\":"; + let after = lock.split(key).nth(1).expect("lock has a waVersion"); + after + .split('"') + .nth(1) + .expect("waVersion is a string") + .to_string() +} + +#[test] +fn every_generated_rust_file_stamps_the_locked_version() { + let want = locked_version(); + for rel in [ + "wacore/src/version/generated.rs", + "wacore/src/iq/abprops.rs", + "wacore/src/iq/mex_operations.rs", + "wacore/appstate/src/schemas.rs", + ] { + let text = read(rel); + let got = stamped_in_header(&text) + .unwrap_or_else(|| panic!("{rel} has no `(WhatsApp )` header")); + assert_eq!( + got, want, + "{rel} was generated from WhatsApp {got} but the lock pins {want}; \ + regenerate the whole set with `cargo run -p whatspec-codegen`" + ); + } +} + +#[test] +fn the_proto_and_the_version_const_agree_with_the_lock() { + let want = locked_version(); + let proto = read("waproto/src/whatsapp.proto"); + let stamped = proto + .lines() + .find_map(|l| l.strip_prefix("/// WhatsApp Version: ")) + .expect("the proto carries its version"); + assert_eq!( + stamped, want, + "waproto/src/whatsapp.proto is from another build" + ); + + let generated = read("wacore/src/version/generated.rs"); + assert!( + generated.contains(&format!("WA_WEB_VERSION_STR: &str = \"{want}\"")), + "the version const does not spell {want}" + ); + let triple: Vec<&str> = want.split('.').collect(); + assert!( + generated.contains(&format!( + "WA_WEB_VERSION: (u32, u32, u32) = ({}, {}, {})", + triple[0], triple[1], triple[2] + )), + "the version triple does not match {want}" + ); +} + +#[test] +fn a_header_from_another_build_is_detected() { + // The assertion above is only worth anything if the extraction actually + // reads the version rather than returning None and passing vacuously. + let good = "//! Auto-generated x (WhatsApp 2.3000.7). DO NOT EDIT.\n//!\n"; + assert_eq!(stamped_in_header(good), Some("2.3000.7")); + assert_eq!(stamped_in_header("//! hand written\n"), None); + assert_eq!(stamped_in_header(""), None); + assert_eq!( + stamped_in_header("//! (WhatsApp 2.3000.7 unterminated\n"), + None + ); +} + +#[test] +fn the_token_tables_stay_wire_indexable() { + // tokens.json carries no version stamp, so this is what the other tests are + // for it: index 0 of the single-byte table is the reserved empty token, and + // a regeneration that lost it would shift every token by one. + let tokens = read("wacore/binary/src/tokens.json"); + let single = tokens + .split("\"single_byte\": [") + .nth(1) + .expect("single_byte table"); + assert!( + single.trim_start().starts_with("\"\","), + "single_byte no longer starts with the reserved empty token" + ); + assert!(tokens.contains("\"double_byte\": [")); +} diff --git a/tools/whatspec-codegen/whatspec.lock.json b/tools/whatspec-codegen/whatspec.lock.json new file mode 100644 index 000000000..aa035b35d --- /dev/null +++ b/tools/whatspec-codegen/whatspec.lock.json @@ -0,0 +1,13 @@ +{ + "repo": "https://github.com/oxidezap/whatspec", + "rev": "622d256be5c796750641ac5216b978d261c18fb2", + "waVersion": "2.3000.1044659339", + "files": { + "abprops/index.json": "sha256:8e935cd88d28fa8e2c87dee73405a4611266f7bdd4c0f6f62c2764656fc29c0a", + "appstate/index.json": "sha256:3ab0c56c54d0ba6c0e2e5b319737b799258f881a158deada1dcf8c6233d84eb8", + "manifest.json": "sha256:cf8db5f2fb9b8e5b7ab2cc3e5d5fb74a7a0a21f76efe946f7add27a8f6d461a1", + "mex/index.json": "sha256:e381c86874d16ec39d817fd85592b6b5e4423a68831219d5b790341993fd0b1f", + "proto/WAProto.proto": "sha256:021d53059e7b35d8553c97c09567da8d6aba7278c7f2510242eab686bff3647a", + "tokens/index.json": "sha256:6d45399515cdc6ec55528aa56e36ecf566f06290039e3ed37a5561a272cb89f9" + } +} diff --git a/wacore/appstate/src/schemas.rs b/wacore/appstate/src/schemas.rs index fe27c2c57..c918d596c 100644 --- a/wacore/appstate/src/schemas.rs +++ b/wacore/appstate/src/schemas.rs @@ -1,4 +1,4 @@ -//! Auto-generated AppState (syncd) action schemas (WhatsApp 2.3000.1042742319). DO NOT EDIT. +//! Auto-generated AppState (syncd) action schemas (WhatsApp 2.3000.1044659339). DO NOT EDIT. //! //! Typed registry of syncd actions: collection, version, scope, value proto type, //! enum fields, and the mutation-index parts. `const`/`&'static`, no deps. @@ -580,23 +580,6 @@ pub const DETECTED_OUTCOME_STATUS: Schema = Schema { }], }; -/// `DeviceCapabilities` — module `WAWebDeviceCapabilitiesSync`. -pub const DEVICE_CAPABILITIES: Schema = Schema { - key: "DeviceCapabilities", - name: "device_capabilities", - module: "WAWebDeviceCapabilitiesSync", - collection: Collection::RegularLow, - version: 7, - scope: Scope::Account, - value_field: Some("deviceCapabilities"), - value_proto_type: Some("DeviceCapabilities"), - value_enum_fields: &[], - chat_jid_index: None, - index_parts: &[IndexPart::Literal { - value: "device_capabilities", - }], -}; - /// `DisableLinkPreviews` — module `WAWebDisableLinkPreviewsSync`. pub const DISABLE_LINK_PREVIEWS: Schema = Schema { key: "DisableLinkPreviews", @@ -751,6 +734,29 @@ pub const LABEL_REORDERING: Schema = Schema { }], }; +/// `LabelSublist` — module `WAWebLabelSublistSync`. +pub const LABEL_SUBLIST: Schema = Schema { + key: "LabelSublist", + name: "label_sublist", + module: "WAWebLabelSublistSync", + collection: Collection::Regular, + version: 1, + scope: Scope::ChatOrContact, + value_field: Some("labelSublistAction"), + value_proto_type: Some("SyncActionValue.LabelSublistAction"), + value_enum_fields: &[], + chat_jid_index: Some(2), + index_parts: &[ + IndexPart::Literal { + value: "label_sublist", + }, + IndexPart::StringPart { + name: "predefinedId", + }, + IndexPart::Jid { name: "chatJid" }, + ], +}; + /// `LidContact` — module `WAWebLidContactSync`. pub const LID_CONTACT: Schema = Schema { key: "LidContact", @@ -836,7 +842,10 @@ pub const MARKETING_MESSAGE: Schema = Schema { scope: Scope::Account, value_field: Some("marketingMessageAction"), value_proto_type: Some("SyncActionValue.MarketingMessageAction"), - value_enum_fields: &[], + value_enum_fields: &[( + "type", + "MarketingMessageAction.MarketingMessagePrototypeType", + )], chat_jid_index: None, index_parts: &[ IndexPart::Literal { @@ -1252,10 +1261,7 @@ pub const STATUS_PRIVACY: Schema = Schema { scope: Scope::Account, value_field: Some("statusPrivacy"), value_proto_type: Some("SyncActionValue.StatusPrivacyAction"), - value_enum_fields: &[ - ("mode", "StatusPrivacyAction.StatusDistributionMode"), - ("modes", "StatusPrivacyAction.StatusDistributionMode"), - ], + value_enum_fields: &[], chat_jid_index: None, index_parts: &[IndexPart::Literal { value: "status_privacy", @@ -1377,7 +1383,10 @@ pub const WASA_ROOT_SECRET: Schema = Schema { scope: Scope::Chat, value_field: Some("wasaRootSecretAction"), value_proto_type: Some("SyncActionValue.WASARootSecretAction"), - value_enum_fields: &[], + value_enum_fields: &[( + "secrets.status", + "WASARootSecretAction.RootSecretEntry.Status", + )], chat_jid_index: Some(1), index_parts: &[ IndexPart::Literal { @@ -1413,7 +1422,6 @@ pub const ALL: &[Schema] = &[ DELETE_CHAT, DELETE_MESSAGE_FOR_ME, DETECTED_OUTCOME_STATUS, - DEVICE_CAPABILITIES, DISABLE_LINK_PREVIEWS, EXTERNAL_WEB_BETA, FAVORITE_STICKER, @@ -1422,6 +1430,7 @@ pub const ALL: &[Schema] = &[ LABEL_EDIT, LABEL_JID, LABEL_REORDERING, + LABEL_SUBLIST, LID_CONTACT, LOCALE_SETTING, LOCK_CHAT, diff --git a/wacore/binary/src/tokens.json b/wacore/binary/src/tokens.json index 75d3bfb80..feea6ae00 100644 --- a/wacore/binary/src/tokens.json +++ b/wacore/binary/src/tokens.json @@ -1271,4 +1271,4 @@ "1961" ] ] -} \ No newline at end of file +} diff --git a/wacore/src/companion_reg.rs b/wacore/src/companion_reg.rs index 322d713a5..3c3f6c3db 100644 --- a/wacore/src/companion_reg.rs +++ b/wacore/src/companion_reg.rs @@ -111,7 +111,8 @@ pub const fn companion_web_client_type_for_platform( | P::AR_DEVICE | P::VR | P::CLOUD_API - | P::SMARTGLASSES => C::OtherWebClient, + | P::SMARTGLASSES + | P::WAIL => C::OtherWebClient, } } @@ -327,6 +328,7 @@ mod tests { P::TCL_TV, P::CLOUD_API, P::SMARTGLASSES, + P::WAIL, ] { assert_eq!( companion_web_client_type_for_platform(pt), diff --git a/wacore/src/iq/abprops.rs b/wacore/src/iq/abprops.rs index 5d7ffdca1..d646a0a03 100644 --- a/wacore/src/iq/abprops.rs +++ b/wacore/src/iq/abprops.rs @@ -1,4 +1,4 @@ -//! Auto-generated A/B-props registry (WhatsApp 2.3000.1042742319). DO NOT EDIT. +//! Auto-generated A/B-props registry (WhatsApp 2.3000.1044659339). DO NOT EDIT. //! //! One `pub mod` per WA Web registry, one `pub const` per flag (screaming-snake of //! its key) with the numeric `code` sent in the `` IQ, value type, and default; @@ -31,7 +31,7 @@ pub struct AbProp { pub default: AbDefault, } -/// `WAWebABPropsConfigs` — 2036 flags. +/// `WAWebABPropsConfigs` — 2193 flags. pub mod web { use super::{AbDefault, AbProp, AbPropType}; @@ -95,24 +95,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(33), }; - pub const ADMIN_REVOKE_RECEIVER: AbProp = AbProp { - name: "admin_revoke_receiver", - code: 1177, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const ADV_ACCEPT_HOSTED_DEVICES: AbProp = AbProp { name: "adv_accept_hosted_devices", code: 6939, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const ADV_V2_M4_M5: AbProp = AbProp { - name: "adv_v2_m4_m5", - code: 753, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const ADVANCED_CHAT_PRIVACY_CONTENT_UPDATE_JULY_25: AbProp = AbProp { name: "advanced_chat_privacy_content_update_july_25", code: 18025, @@ -149,6 +137,30 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AI_3P_AGENT_MEDIA_SUPPORT_MODE: AbProp = AbProp { + name: "ai_3p_agent_media_support_mode", + code: 34393, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const AI_3P_BOT_PRODUCT_CHAT_RENDERING_ENABLED: AbProp = AbProp { + name: "ai_3p_bot_product_chat_rendering_enabled", + code: 34186, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_3P_BOT_PRODUCT_NUX_NOTICE_ID: AbProp = AbProp { + name: "ai_3p_bot_product_nux_notice_id", + code: 34541, + value_type: AbPropType::Str, + default: AbDefault::Str("20260806"), + }; + pub const AI_ACCOUNT_LINKING_ENABLED: AbProp = AbProp { + name: "ai_account_linking_enabled", + code: 13856, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AI_ALL_LANGUAGES_ENABLED: AbProp = AbProp { name: "ai_all_languages_enabled", code: 16091, @@ -233,6 +245,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AI_CHAT_THREADS_EXPORT_BY_THREADS_ENABLED: AbProp = AbProp { + name: "ai_chat_threads_export_by_threads_enabled", + code: 34081, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AI_CHAT_THREADS_FUZZY_SEARCH_ENABLED: AbProp = AbProp { name: "ai_chat_threads_fuzzy_search_enabled", code: 27199, @@ -485,6 +503,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AI_GROUP_TEE_REQUIRE_ADDITIONAL_MEMBER_ENABLED: AbProp = AbProp { + name: "ai_group_tee_require_additional_member_enabled", + code: 33050, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AI_GROUPS_OPEN_ENABLED: AbProp = AbProp { name: "ai_groups_open_enabled", code: 22165, @@ -773,6 +797,18 @@ pub mod web { value_type: AbPropType::Str, default: AbDefault::Str("rephrase,professional,funny,supportive"), }; + pub const AI_RICH_RESPONSE_FORWARD_MEDIA_RECEIVING_ENABLED: AbProp = AbProp { + name: "ai_rich_response_forward_media_receiving_enabled", + code: 21363, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_RICH_RESPONSE_FORWARD_MEDIA_SENDING_ENABLED: AbProp = AbProp { + name: "ai_rich_response_forward_media_sending_enabled", + code: 20747, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AI_RICH_RESPONSE_FORWARD_RECEIVING_ENABLED: AbProp = AbProp { name: "ai_rich_response_forward_receiving_enabled", code: 16682, @@ -947,12 +983,30 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AI_STANDARD_BOT_PROFILE_ENABLED: AbProp = AbProp { + name: "ai_standard_bot_profile_enabled", + code: 32961, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_SUBSCRIPTION_ENABLED: AbProp = AbProp { + name: "ai_subscription_enabled", + code: 25927, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AI_SUBSCRIPTION_IMAGINE_INTENT_ENABLED: AbProp = AbProp { name: "ai_subscription_imagine_intent_enabled", code: 28585, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AI_SUBSCRIPTION_IMAGINE_INTENT_METERING_ENABLED: AbProp = AbProp { + name: "ai_subscription_imagine_intent_metering_enabled", + code: 33229, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AI_SUBSCRIPTION_METERING_ENABLED: AbProp = AbProp { name: "ai_subscription_metering_enabled", code: 30960, @@ -989,6 +1043,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AI_UNIFIED_RESPONSE_MUTATION_ENABLED: AbProp = AbProp { + name: "ai_unified_response_mutation_enabled", + code: 17805, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const AI_UNIFIED_RESPONSE_QPL_LOGGING: AbProp = AbProp { name: "ai_unified_response_qpl_logging", code: 24484, @@ -1055,6 +1115,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AI_WEB_ASK_META_AI_MEDIA_FORWARD_ENABLED: AbProp = AbProp { + name: "ai_web_ask_meta_ai_media_forward_enabled", + code: 34257, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AI_WEB_FORWARD_FLOW_ENABLED: AbProp = AbProp { name: "ai_web_forward_flow_enabled", code: 19676, @@ -1085,12 +1151,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const ALBUM_V2_ITEM_WITH_CAPTION_IN_ALBUM_RECEIVER_ENABLED: AbProp = AbProp { - name: "album_v2_item_with_caption_in_album_receiver_enabled", - code: 11943, - value_type: AbPropType::Bool, - default: AbDefault::Bool(true), - }; pub const ALBUM_V2_MIN_ITEMS_TO_SEND_ALBUM_WITH_CAPTION: AbProp = AbProp { name: "album_v2_min_items_to_send_album_with_caption", code: 12538, @@ -1121,6 +1181,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ANDROID_INBOX_MENTIONS_REPLIES_FILTER: AbProp = AbProp { + name: "android_inbox_mentions_replies_filter", + code: 33633, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ANIMATED_EMOJI_FINAL_SET_ENABLED: AbProp = AbProp { name: "animated_emoji_final_set_enabled", code: 9757, @@ -1181,6 +1247,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ATTACH_INVITEE_USER_PN_IN_OFFER: AbProp = AbProp { + name: "attach_invitee_user_pn_in_offer", + code: 34040, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ATTACH_TRANSPORT_RTX: AbProp = AbProp { name: "attach_transport_rtx", code: 16201, @@ -1217,12 +1289,36 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AURA_FOCUS_LISTS_DEFAULT_LIST_ENABLED: AbProp = AbProp { + name: "aura_focus_lists_default_list_enabled", + code: 34252, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AURA_FOCUS_LISTS_ENABLED: AbProp = AbProp { name: "aura_focus_lists_enabled", code: 32723, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const AURA_FOCUS_LISTS_EXCLUSION_ENABLED: AbProp = AbProp { + name: "aura_focus_lists_exclusion_enabled", + code: 33928, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AURA_FOCUS_LISTS_SCHEDULE_ENABLED: AbProp = AbProp { + name: "aura_focus_lists_schedule_enabled", + code: 33413, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AURA_GROUP_REACTIONS_BLOCKING_ENABLED: AbProp = AbProp { + name: "aura_group_reactions_blocking_enabled", + code: 33522, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AURA_KILL_SWITCH: AbProp = AbProp { name: "aura_kill_switch", code: 28345, @@ -1325,6 +1421,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(5), }; + pub const AURA_STICKERS_QP_BANNER_UPSELL_SHEET_ENABLED: AbProp = AbProp { + name: "aura_stickers_qp_banner_upsell_sheet_enabled", + code: 33209, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const AURA_SUBSCRIPTION_SIMULATION_ENABLED: AbProp = AbProp { name: "aura_subscription_simulation_enabled", code: 26086, @@ -1349,6 +1451,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const BACKFILL_CHECK_PRIMARY_IDENTITY_KEY: AbProp = AbProp { + name: "backfill_check_primary_identity_key", + code: 33448, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const BACKFILL_SUPPORTS_COEX_COMPANION: AbProp = AbProp { name: "backfill_supports_coex_companion", code: 27975, @@ -1535,6 +1643,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const BIZ_AI_FAB_ENABLED: AbProp = AbProp { + name: "biz_ai_fab_enabled", + code: 33531, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BIZ_AI_HANDOFF_TIMING_SYNC_ENABLED: AbProp = AbProp { + name: "biz_ai_handoff_timing_sync_enabled", + code: 33602, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const BIZ_AI_IN_THREAD_UNMUTE_V2: AbProp = AbProp { name: "biz_ai_in_thread_unmute_v2", code: 15523, @@ -1553,6 +1673,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const BIZ_AI_PRIORITY_LIST_ITEM_EXPIRE_DAYS: AbProp = AbProp { + name: "biz_ai_priority_list_item_expire_days", + code: 16472, + value_type: AbPropType::Int, + default: AbDefault::Int(14), + }; pub const BIZ_AI_RESPONDING_LIST_ENABLED: AbProp = AbProp { name: "biz_ai_responding_list_enabled", code: 26670, @@ -1583,6 +1709,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; + pub const BIZ_AI_WEB_AI_HUB_CHAT_NAV_ENABLED: AbProp = AbProp { + name: "biz_ai_web_ai_hub_chat_nav_enabled", + code: 34204, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const BIZ_AI_WEB_AI_HUB_TAP_CTA_SHOW_ALERT: AbProp = AbProp { name: "biz_ai_web_ai_hub_tap_cta_show_alert", code: 17093, @@ -1595,6 +1727,24 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const BIZ_AI_WEB_GDRIVE_ENABLED: AbProp = AbProp { + name: "biz_ai_web_gdrive_enabled", + code: 32906, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BIZ_AI_WEB_HUB_CHAT_ENABLED: AbProp = AbProp { + name: "biz_ai_web_hub_chat_enabled", + code: 34203, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BIZ_AI_WEB_INTEGRATION_HUB_ENABLED: AbProp = AbProp { + name: "biz_ai_web_integration_hub_enabled", + code: 33956, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const BIZ_AI_WEB_ONBOARDING_HANDOFF: AbProp = AbProp { name: "biz_ai_web_onboarding_handoff", code: 29298, @@ -1607,6 +1757,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const BIZ_AI_WEB_SMART_COMPOSER_ENABLED: AbProp = AbProp { + name: "biz_ai_web_smart_composer_enabled", + code: 34003, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const BIZ_VPV_DIMENSIONS_LOGGING_ENABLED: AbProp = AbProp { name: "biz_vpv_dimensions_logging_enabled", code: 30266, @@ -1751,12 +1907,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const BOT_3P_ENABLED: AbProp = AbProp { - name: "bot_3p_enabled", - code: 5587, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const BOT_3P_STATUS: AbProp = AbProp { name: "bot_3p_status", code: 5985, @@ -1769,6 +1919,54 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const BR_CONSUMER_DELETE_PAYMENT_INFO_WEB_ENABLED: AbProp = AbProp { + name: "br_consumer_delete_payment_info_web_enabled", + code: 34062, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BR_CONSUMER_PAYMENTS_HOME_WEB_ENABLED: AbProp = AbProp { + name: "br_consumer_payments_home_web_enabled", + code: 32968, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BR_CONSUMER_PIX_ACTIONS_WEB_ENABLED: AbProp = AbProp { + name: "br_consumer_pix_actions_web_enabled", + code: 33028, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BR_CONSUMER_PIX_CONTACT_INFO_WEB_ENABLED: AbProp = AbProp { + name: "br_consumer_pix_contact_info_web_enabled", + code: 34555, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BR_CONSUMER_PIX_GROUPS_WEB_ENABLED: AbProp = AbProp { + name: "br_consumer_pix_groups_web_enabled", + code: 34235, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BR_CONSUMER_PIX_SYNC_RECEIVE_ENABLED: AbProp = AbProp { + name: "br_consumer_pix_sync_receive_enabled", + code: 33219, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BR_CONSUMER_PIX_SYNC_RECEIVE_WEB_ENABLED: AbProp = AbProp { + name: "br_consumer_pix_sync_receive_web_enabled", + code: 33244, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BR_CONSUMER_TRANSACTIONS_DATE_FILTER_WEB_ENABLED: AbProp = AbProp { + name: "br_consumer_transactions_date_filter_web_enabled", + code: 34454, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const BR_ENABLE_PAYMENT_LOGOS_ON_BUBBLE: AbProp = AbProp { name: "br_enable_payment_logos_on_bubble", code: 8160, @@ -1943,12 +2141,6 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; - pub const CALL_INFO_USE_TYPED_JID: AbProp = AbProp { - name: "call_info_use_typed_jid", - code: 29027, - value_type: AbPropType::Int, - default: AbDefault::Int(0), - }; pub const CALL_OFFER_FAILED_SOFT_LANDING_SCREEN_VERSION: AbProp = AbProp { name: "call_offer_failed_soft_landing_screen_version", code: 10559, @@ -1985,11 +2177,29 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const CALLING_E2E_KEYGEN_VIA_SELF_LID: AbProp = AbProp { - name: "calling_e2e_keygen_via_self_lid", - code: 26411, + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_BATTERY_THRESHOLD_PCT: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_battery_threshold_pct", + code: 33552, value_type: AbPropType::Int, - default: AbDefault::Int(0), + default: AbDefault::Int(15), + }; + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_ENABLED: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_enabled", + code: 32896, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_INCLUDE_LOW_DATA_USAGE: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_include_low_data_usage", + code: 33235, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_POOR_NETWORK_TIME_MS: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_poor_network_time_ms", + code: 33548, + value_type: AbPropType::Int, + default: AbDefault::Int(5800), }; pub const CALLING_LID_VERSION: AbProp = AbProp { name: "calling_lid_version", @@ -2075,6 +2285,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CAP_CONTEXT_INFO_MAX_ARRAY_LENGTH: AbProp = AbProp { + name: "cap_context_info_max_array_length", + code: 33504, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const CAROUSEL_MESSAGE_CLIENT_ENABLED: AbProp = AbProp { name: "carousel_message_client_enabled", code: 4668, @@ -2207,12 +2423,24 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CHANNEL_STATUS_CONSUMPTION_MUSIC_ENABLED: AbProp = AbProp { + name: "channel_status_consumption_music_enabled", + code: 26774, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CHANNEL_STATUS_CREATION: AbProp = AbProp { name: "channel_status_creation", code: 23994, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CHANNEL_STATUS_CREATION_PROFILE_RING_ENABLED: AbProp = AbProp { + name: "channel_status_creation_profile_ring_enabled", + code: 33840, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CHANNEL_STATUS_DEEPLINK_ENABLED: AbProp = AbProp { name: "channel_status_deeplink_enabled", code: 28500, @@ -2309,6 +2537,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CHANNELS_ADMIN_PROFILES_BANNER_ENABLED: AbProp = AbProp { + name: "channels_admin_profiles_banner_enabled", + code: 33896, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CHANNELS_ADMIN_PROFILES_FORWARDING_TO_CHATS_ENABLED: AbProp = AbProp { name: "channels_admin_profiles_forwarding_to_chats_enabled", code: 23170, @@ -2333,6 +2567,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CHANNELS_ADMIN_PROFILES_SETTINGS_ENABLED: AbProp = AbProp { + name: "channels_admin_profiles_settings_enabled", + code: 24347, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CHANNELS_ADMIN_PROFILES_UPDATE_ENABLED: AbProp = AbProp { + name: "channels_admin_profiles_update_enabled", + code: 23168, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CHANNELS_ADMIN_REPLY_ENABLED: AbProp = AbProp { name: "channels_admin_reply_enabled", code: 7211, @@ -2736,12 +2982,6 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(30), }; - pub const CHANNELS_QUESTION_FOLLOWER_ENABLED: AbProp = AbProp { - name: "channels_question_follower_enabled", - code: 17425, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const CHANNELS_QUESTION_FOLLOWER_M2_ENABLED: AbProp = AbProp { name: "channels_question_follower_m2_enabled", code: 26911, @@ -2868,6 +3108,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CHANNELS_RECOMMENDATION_UNIT_REMOVAL_V1_ENABLED: AbProp = AbProp { + name: "channels_recommendation_unit_removal_v1_enabled", + code: 33761, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CHANNELS_RECOMMENDED_V3_UI_LIMIT: AbProp = AbProp { name: "channels_recommended_v3_ui_limit", code: 8167, @@ -2892,6 +3138,18 @@ pub mod web { value_type: AbPropType::Str, default: AbDefault::Str(""), }; + pub const CHANNELS_SCHEDULING_UPDATES_ENABLED: AbProp = AbProp { + name: "channels_scheduling_updates_enabled", + code: 33897, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CHANNELS_SCHEDULING_UPDATES_MESSAGE_TYPES: AbProp = AbProp { + name: "channels_scheduling_updates_message_types", + code: 33898, + value_type: AbPropType::Str, + default: AbDefault::Str("1"), + }; pub const CHANNELS_SEND_ALBUM_ENABLED: AbProp = AbProp { name: "channels_send_album_enabled", code: 5643, @@ -2916,6 +3174,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CHANNELS_SGI_SENDER_SELF_DISCLOSURE_ENABLED: AbProp = AbProp { + name: "channels_sgi_sender_self_disclosure_enabled", + code: 32990, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CHANNELS_SGI_UI_LABEL_ENABLED: AbProp = AbProp { + name: "channels_sgi_ui_label_enabled", + code: 33109, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CHANNELS_SHARE_LINK_LOGGING_ENABLED: AbProp = AbProp { name: "channels_share_link_logging_enabled", code: 5491, @@ -3102,6 +3372,30 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const COMPANION_CONTACT_REFRESH: AbProp = AbProp { + name: "companion_contact_refresh", + code: 33093, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const COMPANION_CONTACT_REFRESH_DEBOUNCE_MS: AbProp = AbProp { + name: "companion_contact_refresh_debounce_ms", + code: 33497, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const COMPANION_CONTACT_REFRESH_RECEIVER: AbProp = AbProp { + name: "companion_contact_refresh_receiver", + code: 33635, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const COMPANION_INITIATED_COMPANION_CONTACT_REFRESH: AbProp = AbProp { + name: "companion_initiated_companion_contact_refresh", + code: 33123, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CONSUMER_GRAPHQL_ENABLE_DOUBLE_LOG_FOR_SURVEY: AbProp = AbProp { name: "consumer_graphql_enable_double_log_for_survey", code: 28129, @@ -3120,6 +3414,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(1320), }; + pub const CONTEXT_MENU_CONTENT_FIX: AbProp = AbProp { + name: "context_menu_content_fix", + code: 34337, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const COUNTRY_CLIENT_GATING_ENABLED: AbProp = AbProp { name: "country_client_gating_enabled", code: 1105, @@ -3150,6 +3450,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CTWA_1PD_WEB_NBF_SIGNALS_ENABLED: AbProp = AbProp { + name: "ctwa_1pd_web_nbf_signals_enabled", + code: 33508, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CTWA_3PD_AGGREGATED_CALL_LOGGING_ALLOWED: AbProp = AbProp { name: "ctwa_3pd_aggregated_call_logging_allowed", code: 32379, @@ -3162,6 +3468,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CTWA_3PD_CONVERSION_ON_AE_DETECTION: AbProp = AbProp { + name: "ctwa_3pd_conversion_on_ae_detection", + code: 34045, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CTWA_3PD_DATA_SHARING_ADDITIONAL_LOGGING: AbProp = AbProp { name: "ctwa_3pd_data_sharing_additional_logging", code: 29333, @@ -3174,6 +3486,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; + pub const CTWA_3PD_DATA_SHARING_DISCLOSURE_ON_LISTS_HOME: AbProp = AbProp { + name: "ctwa_3pd_data_sharing_disclosure_on_lists_home", + code: 31224, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const CTWA_3PD_DATA_SHARING_ON_THREAD_ENTRY: AbProp = AbProp { name: "ctwa_3pd_data_sharing_on_thread_entry", code: 13485, @@ -3192,6 +3510,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const CTWA_3PD_POST_DC_DEPTH_LIMIT: AbProp = AbProp { + name: "ctwa_3pd_post_dc_depth_limit", + code: 24061, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; pub const CTWA_AD_ACCOUNT_NONCE_PUSH_WAIT_TIMEOUT_WEB: AbProp = AbProp { name: "ctwa_ad_account_nonce_push_wait_timeout_web", code: 8664, @@ -3393,12 +3717,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const CTWA_SMB_DETECTED_OUTCOME_LABELS_ENABLED: AbProp = AbProp { - name: "ctwa_smb_detected_outcome_labels_enabled", - code: 15307, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const CTWA_SMB_DETECTED_OUTCOME_LABELS_MERGER_ENABLED: AbProp = AbProp { name: "ctwa_smb_detected_outcome_labels_merger_enabled", code: 15308, @@ -3526,6 +3844,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const DEDUPE_LID_PN_IDENTITY_KEY_STORES: AbProp = AbProp { + name: "dedupe_lid_pn_identity_key_stores", + code: 33083, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const DEFAULT_AUDIO_LIMIT_MB: AbProp = AbProp { name: "default_audio_limit_mb", code: 3657, @@ -3610,6 +3934,12 @@ pub mod web { value_type: AbPropType::Str, default: AbDefault::Str(""), }; + pub const DEVICE_CAPABILITIES_V2_SYNC_ENABLED: AbProp = AbProp { + name: "device_capabilities_v2_sync_enabled", + code: 33380, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const DEVICE_SWITCHING_ENABLED: AbProp = AbProp { name: "device_switching_enabled", code: 3205, @@ -3898,6 +4228,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ENABLE_CALLUSER_VIDEO_DEEPLINK: AbProp = AbProp { + name: "enable_calluser_video_deeplink", + code: 32881, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ENABLE_CHANNEL_VIDEO_SERVER_THUMBNAIL: AbProp = AbProp { name: "enable_channel_video_server_thumbnail", code: 11192, @@ -3922,12 +4258,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const ENABLE_COMMUNITY_SUSPEND_AND_APPEALS: AbProp = AbProp { - name: "enable_community_suspend_and_appeals", - code: 10539, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const ENABLE_COPY_PASTE_P2P: AbProp = AbProp { name: "enable_copy_paste_p2p", code: 27642, @@ -3964,6 +4294,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; + pub const ENABLE_EVENTS_V2_INVITE_MESSAGE_UPDATE: AbProp = AbProp { + name: "enable_events_v2_invite_message_update", + code: 32555, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ENABLE_EVENTS_V2_INVITE_MESSAGE_WITH_DATETIME: AbProp = AbProp { name: "enable_events_v2_invite_message_with_datetime", code: 32612, @@ -3988,6 +4324,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ENABLE_FSA_SAVE_AS: AbProp = AbProp { + name: "enable_fsa_save_as", + code: 33783, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ENABLE_FUTUREPROOF_GALAXY_FLOW_MESSAGE_FOR_BUSINESS_NUMBERS: AbProp = AbProp { name: "enable_futureproof_galaxy_flow_message_for_business_numbers", code: 22311, @@ -4018,6 +4360,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(true), }; + pub const ENABLE_HYBRID_OPEN_WITH_SHARED_BUFFER: AbProp = AbProp { + name: "enable_hybrid_open_with_shared_buffer", + code: 34175, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ENABLE_HYBRID_VIDEO_TRANSCODING: AbProp = AbProp { name: "enable_hybrid_video_transcoding", code: 19895, @@ -4042,6 +4390,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ENABLE_JOIN_ONGOING_CALL_REFACTOR: AbProp = AbProp { + name: "enable_join_ongoing_call_refactor", + code: 34093, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ENABLE_LAZY_LOADING_OF_CALL_VIEW_ELEMENTS: AbProp = AbProp { name: "enable_lazy_loading_of_call_view_elements", code: 5053, @@ -4126,6 +4480,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ENABLE_POLL_RESULTS_CONTACT_INFO_ENTRY_POINT: AbProp = AbProp { + name: "enable_poll_results_contact_info_entry_point", + code: 33818, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ENABLE_POLL_SETTINGS_LABEL_IMPROVED_LAYOUT: AbProp = AbProp { name: "enable_poll_settings_label_improved_layout", code: 32778, @@ -4342,6 +4702,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ENABLE_WEB_VOIP_AUDIO_DRIVER_LIFETIME_FIX: AbProp = AbProp { + name: "enable_web_voip_audio_driver_lifetime_fix", + code: 33581, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const ENABLE_WEB_VOIP_DYNAMIC_FPS_THROTTLE: AbProp = AbProp { name: "enable_web_voip_dynamic_fps_throttle", code: 25394, @@ -4372,6 +4738,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(true), }; + pub const ENABLE_WEB_VOIP_VIDEO_CAPTURE_DOM_ATTACH: AbProp = AbProp { + name: "enable_web_voip_video_capture_dom_attach", + code: 33953, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const ENABLE_WEB_VOIP_VIDEO_RESOLUTION_CAP: AbProp = AbProp { name: "enable_web_voip_video_resolution_cap", code: 25899, @@ -4396,6 +4768,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ENABLE_WEB_VOIP_WEBTRANSPORT_FALLBACK: AbProp = AbProp { + name: "enable_web_voip_webtransport_fallback", + code: 33539, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const ENABLE_WEB_VOIP_WORKER_POOL_RECLAIM_ON_REJOIN: AbProp = AbProp { + name: "enable_web_voip_worker_pool_reclaim_on_rejoin", + code: 33597, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const ENABLE_WEBCODEC_REQUIRE_KEYFRAME: AbProp = AbProp { name: "enable_webcodec_require_keyframe", code: 29510, @@ -4444,6 +4828,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const ENABLE_WINDOWS_XDR_WNS_PKEY: AbProp = AbProp { + name: "enable_windows_xdr_wns_pkey", + code: 32324, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const ENHANCED_MENTION_LIMIT: AbProp = AbProp { name: "enhanced_mention_limit", code: 25951, @@ -4480,24 +4870,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(100), }; - pub const EVENTS_CREATE: AbProp = AbProp { - name: "events_create", - code: 5562, - value_type: AbPropType::Bool, - default: AbDefault::Bool(true), - }; pub const EVENTS_CREATE_CAG_ENABLED: AbProp = AbProp { name: "events_create_cag_enabled", code: 9932, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const EVENTS_EDIT_RECEIVE: AbProp = AbProp { - name: "events_edit_receive", - code: 7358, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const EVENTS_M3_COVER_IMAGE_RECEIVE: AbProp = AbProp { name: "events_m3_cover_image_receive", code: 7511, @@ -4618,12 +4996,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const FLATTENED_REACTIONS_COLLECTION: AbProp = AbProp { - name: "flattened_reactions_collection", - code: 4390, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const FLOWS_TERMINATION_MESSAGE_V2_SENDING_ENABLED: AbProp = AbProp { name: "flows_termination_message_v2_sending_enabled", code: 9157, @@ -4640,13 +5012,13 @@ pub mod web { name: "flows_wa_web_agm_cta", code: 24215, value_type: AbPropType::Bool, - default: AbDefault::Bool(false), + default: AbDefault::Bool(true), }; pub const FLOWS_WA_WEB_RESPONSES_DOWNLOAD: AbProp = AbProp { name: "flows_wa_web_responses_download", code: 24216, value_type: AbPropType::Bool, - default: AbDefault::Bool(false), + default: AbDefault::Bool(true), }; pub const FMX_CTWA_KILL_SWITCH: AbProp = AbProp { name: "fmx_ctwa_kill_switch", @@ -4654,7 +5026,13 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const FORWARDED_MESSAGE_USER_JOURNEY_LOGGING_ENABLED: AbProp = AbProp { + pub const FMX_PERSISTENT_COUNTRY_TRUST_SIGNAL_ENABLED: AbProp = AbProp { + name: "fmx_persistent_country_trust_signal_enabled", + code: 33926, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const FORWARDED_MESSAGE_USER_JOURNEY_LOGGING_ENABLED: AbProp = AbProp { name: "forwarded_message_user_journey_logging_enabled", code: 16055, value_type: AbPropType::Bool, @@ -4684,12 +5062,24 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const FUNCTIONAL_EMOJI_TEXT_ENABLED: AbProp = AbProp { + name: "functional_emoji_text_enabled", + code: 34047, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const FUTUREPROOF_ASSOCIATED_CHILD_ENABLED: AbProp = AbProp { name: "futureproof_associated_child_enabled", code: 11976, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const GC_DEVICE_SWITCH_SHOW_ENTRY_POINT: AbProp = AbProp { + name: "gc_device_switch_show_entry_point", + code: 33281, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const GC_DEVICE_SWITCHING_KILLSWITCH: AbProp = AbProp { name: "gc_device_switching_killswitch", code: 26182, @@ -4768,12 +5158,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const GROUP_CATCH_UP: AbProp = AbProp { - name: "group_catch_up", - code: 559, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const GROUP_CREATE_ADD_USING_LID_JIDS: AbProp = AbProp { name: "group_create_add_using_lid_jids", code: 16192, @@ -4930,18 +5314,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const GROUP_JOIN_REQUEST_CAN_SEND_OPTIONAL_MESSAGE: AbProp = AbProp { - name: "group_join_request_can_send_optional_message", - code: 3384, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; - pub const GROUP_JOIN_REQUEST_CAN_VIEW_OPTIONAL_MESSAGE: AbProp = AbProp { - name: "group_join_request_can_view_optional_message", - code: 3383, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const GROUP_JOIN_REQUEST_M2_BANNER_ON_CONVERSATION: AbProp = AbProp { name: "group_join_request_m2_banner_on_conversation", code: 2449, @@ -4990,6 +5362,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const GROUP_SETTINGS_IA_PROTOTYPE: AbProp = AbProp { + name: "group_settings_ia_prototype", + code: 34025, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; pub const GROUP_SIZE_BYPASSING_SAMPLING: AbProp = AbProp { name: "group_size_bypassing_sampling", code: 1861, @@ -5206,6 +5584,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const IM_A2UI_REQUIRE_BOT_ATTRIBUTION: AbProp = AbProp { + name: "im_a2ui_require_bot_attribution", + code: 34324, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const IM_BLOKS_WIDGET_ENABLE: AbProp = AbProp { name: "im_bloks_widget_enable", code: 25071, @@ -5398,6 +5782,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const IOS_REACTION_PICKER_WDS_HEADER_ENABLED: AbProp = AbProp { + name: "ios_reaction_picker_wds_header_enabled", + code: 33885, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const IS_AI_MODE_SELECTOR_VISIBLE: AbProp = AbProp { name: "is_ai_mode_selector_visible", code: 24489, @@ -5542,6 +5932,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const LID_MIGRATION_DAILY_GROUP_COMPOSITION_ENABLED: AbProp = AbProp { + name: "lid_migration_daily_group_composition_enabled", + code: 34155, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const LID_MIGRATION_FOR_BIZ_PROFILE_ENABLED: AbProp = AbProp { name: "lid_migration_for_biz_profile_enabled", code: 12000, @@ -5572,24 +5968,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const LID_ONE_ON_ONE_MIGRATION_LOG_OUT_ON_MISMATCH: AbProp = AbProp { - name: "lid_one_on_one_migration_log_out_on_mismatch", - code: 11050, - value_type: AbPropType::Bool, - default: AbDefault::Bool(true), - }; pub const LID_ONE_ON_ONE_MIGRATION_PEER_SYNC_TIMEOUT_IN_SECONDS: AbProp = AbProp { name: "lid_one_on_one_migration_peer_sync_timeout_in_seconds", code: 13936, value_type: AbPropType::Int, default: AbDefault::Int(300), }; - pub const LID_ONE_TO_ONE_MIGRATION_EVENT_RESPONSE_FORCE_PN_JID: AbProp = AbProp { - name: "lid_one_to_one_migration_event_response_force_pn_jid", - code: 15791, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const LID_PN_USERNAME_MAPPING_LOGGING_ENABLED: AbProp = AbProp { name: "lid_pn_username_mapping_logging_enabled", code: 31266, @@ -6095,6 +6479,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const MM_TEMPLATE_MESSAGE_TELEMETRY_STRICT_FIRST_MM_ENABLED: AbProp = AbProp { + name: "mm_template_message_telemetry_strict_first_mm_enabled", + code: 33160, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const MM_USER_CONTROLS_ENTRY_POINTS_UPDATE_M1_ICON: AbProp = AbProp { name: "mm_user_controls_entry_points_update_m1_icon", code: 20388, @@ -6257,12 +6647,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const NEWSLETTER_STATUS_RECEIVER_ENABLED: AbProp = AbProp { - name: "newsletter_status_receiver_enabled", - code: 26217, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const NEWSLETTER_TOS_NOTICE_ID: AbProp = AbProp { name: "newsletter_tos_notice_id", code: 3810, @@ -6819,11 +7203,35 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PAYMENTS_UPR_ARGENTINA_ENABLED: AbProp = AbProp { + name: "payments_upr_argentina_enabled", + code: 33887, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PAYMENTS_UPR_BUBBLE_COUNTRIES: AbProp = AbProp { name: "payments_upr_bubble_countries", code: 29342, value_type: AbPropType::Str, - default: AbDefault::Str("MX"), + default: AbDefault::Str("MX, ID, HK, TW, AE, EG, TR"), + }; + pub const PAYMENTS_UPR_CANADA_ENABLED: AbProp = AbProp { + name: "payments_upr_canada_enabled", + code: 33888, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_UPR_COLOMBIA_ENABLED: AbProp = AbProp { + name: "payments_upr_colombia_enabled", + code: 33889, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_UPR_COTE_DIVOIRE_ENABLED: AbProp = AbProp { + name: "payments_upr_cote_divoire_enabled", + code: 33894, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), }; pub const PAYMENTS_UPR_CUSTOM_PAYMENT_METHODS_SYNC_COUNTRIES: AbProp = AbProp { name: "payments_upr_custom_payment_methods_sync_countries", @@ -6837,6 +7245,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PAYMENTS_UPR_ETHIOPIA_ENABLED: AbProp = AbProp { + name: "payments_upr_ethiopia_enabled", + code: 33892, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_UPR_GHANA_ENABLED: AbProp = AbProp { + name: "payments_upr_ghana_enabled", + code: 33891, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PAYMENTS_UPR_HONGKONG_ENABLED: AbProp = AbProp { name: "payments_upr_hongkong_enabled", code: 31868, @@ -6867,18 +7287,42 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PAYMENTS_UPR_PERU_ENABLED: AbProp = AbProp { + name: "payments_upr_peru_enabled", + code: 33890, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_UPR_SAUDI_ARABIA_ENABLED: AbProp = AbProp { + name: "payments_upr_saudi_arabia_enabled", + code: 33886, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PAYMENTS_UPR_SEND_KEY_FROM_WEB: AbProp = AbProp { name: "payments_upr_send_key_from_web", code: 32826, value_type: AbPropType::Str, default: AbDefault::Str(""), }; + pub const PAYMENTS_UPR_SOUTH_AFRICA_ENABLED: AbProp = AbProp { + name: "payments_upr_south_africa_enabled", + code: 33922, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PAYMENTS_UPR_TAIWAN_ENABLED: AbProp = AbProp { name: "payments_upr_taiwan_enabled", code: 31869, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PAYMENTS_UPR_TANZANIA_ENABLED: AbProp = AbProp { + name: "payments_upr_tanzania_enabled", + code: 33893, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PAYMENTS_UPR_TURKEY_ENABLED: AbProp = AbProp { name: "payments_upr_turkey_enabled", code: 31848, @@ -6915,6 +7359,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PINNED_MESSAGE_BANNER_NOTCH_ANIMATION_ENABLED: AbProp = AbProp { + name: "pinned_message_banner_notch_animation_enabled", + code: 34369, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PINNED_MESSAGES_INFINITE_RECEIVER_ENABLED: AbProp = AbProp { name: "pinned_messages_infinite_receiver_enabled", code: 31886, @@ -6981,6 +7431,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PIX_PAYMENT_REQUEST_WEB_ENABLED: AbProp = AbProp { + name: "pix_payment_request_web_enabled", + code: 34199, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PLACEHOLDER_MESSAGE_KEY_HASH_LOGGING: AbProp = AbProp { name: "placeholder_message_key_hash_logging", code: 2639, @@ -7125,6 +7581,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PQ_1ON1_MESSAGE_ENABLED: AbProp = AbProp { + name: "pq_1on1_message_enabled", + code: 24160, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PQ_KEYS_UPLOAD: AbProp = AbProp { + name: "pq_keys_upload", + code: 21198, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PREMIUM_BLUE_ENABLED: AbProp = AbProp { name: "premium_blue_enabled", code: 5318, @@ -7143,6 +7611,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const PRIMARY_INITIATED_COMPANION_CONTACT_REFRESH: AbProp = AbProp { + name: "primary_initiated_companion_contact_refresh", + code: 33013, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const PRIVACY_SCREEN_ENABLED: AbProp = AbProp { name: "privacy_screen_enabled", code: 26820, @@ -7293,12 +7767,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const QUICK_PROMOTION_BANNER_CLIENT_ENABLED: AbProp = AbProp { - name: "quick_promotion_banner_client_enabled", - code: 3712, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const QUOTED_MESSAGE_USER_JOURNEY_LOGGING_ENABLED: AbProp = AbProp { name: "quoted_message_user_journey_logging_enabled", code: 15694, @@ -7323,12 +7791,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const REACTIONS_CHAT_PREVIEW: AbProp = AbProp { - name: "reactions_chat_preview", - code: 1605, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const REACTIONS_RECEIVER_ENABLED: AbProp = AbProp { name: "reactions_receiver_enabled", code: 13542, @@ -7401,6 +7863,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const REVEAL_USERNAME_NON_LINKING_REJECTION_REASON_ENABLED: AbProp = AbProp { + name: "reveal_username_non_linking_rejection_reason_enabled", + code: 32910, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const RICH_FORMAT_LOGGING_ENABLED: AbProp = AbProp { + name: "rich_format_logging_enabled", + code: 29428, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const RICH_ORDER_STATUS_WA_WEB: AbProp = AbProp { name: "rich_order_status_wa_web", code: 16534, @@ -7503,6 +7977,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const RUST_ACCEL_WACALL_FOUNDATION_ENABLED: AbProp = AbProp { + name: "rust_accel_wacall_foundation_enabled", + code: 33446, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SAGA_COPY: AbProp = AbProp { name: "saga_copy", code: 7044, @@ -7659,12 +8139,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const SEND_INVALID_PROTOBUF_NACK_FAILURE_REASON: AbProp = AbProp { - name: "send_invalid_protobuf_nack_failure_reason", - code: 9174, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const SERVER_DRIVEN_COPY_M2: AbProp = AbProp { name: "server_driven_copy_m2", code: 30492, @@ -7731,12 +8205,24 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(600), }; + pub const SHOW_FISHFOODING_TOGGLE_IN_BUG_REPORTING_FORM: AbProp = AbProp { + name: "show_fishfooding_toggle_in_bug_reporting_form", + code: 33156, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SHOW_INTEGRITY_SCREENSHARING_FRICTION_UI: AbProp = AbProp { name: "show_integrity_screensharing_friction_ui", code: 16411, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const SHOW_USERNAME_NON_LINKING_REJECTION_REASON_ENABLED: AbProp = AbProp { + name: "show_username_non_linking_rejection_reason_enabled", + code: 32920, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SILENT_GROUP_USERNAME_ACTIVITIES_ENABLED: AbProp = AbProp { name: "silent_group_username_activities_enabled", code: 24269, @@ -7821,6 +8307,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const SMB_BB_IN_THREAD_INSIGHT_METRICS_ENABLED: AbProp = AbProp { + name: "smb_bb_in_thread_insight_metrics_enabled", + code: 31676, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SMB_BB_PRO_BUSINESS_VERIFICATION: AbProp = AbProp { + name: "smb_bb_pro_business_verification", + code: 34341, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SMB_BB_WEB_AUDIENCE_EXPRESSION_SYNC_READ: AbProp = AbProp { name: "smb_bb_web_audience_expression_sync_read", code: 26894, @@ -7863,6 +8361,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const SMB_BUSINESS_BROADCAST_PRO_WEB_SCHEDULED_SENDS_ENABLED: AbProp = AbProp { + name: "smb_business_broadcast_pro_web_scheduled_sends_enabled", + code: 33169, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SMB_BUSINESS_BROADCAST_SEND_WEB: AbProp = AbProp { name: "smb_business_broadcast_send_web", code: 21508, @@ -7911,6 +8415,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const SMB_CONTACT_MANAGER_SUBLIST_ENABLED: AbProp = AbProp { + name: "smb_contact_manager_sublist_enabled", + code: 33708, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SMB_CORE_BIZ_PROFILE_PREVIEW: AbProp = AbProp { name: "smb_core_biz_profile_preview", code: 26441, @@ -8075,12 +8585,6 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(5000), }; - pub const SMB_NOTES_V1_ENABLED: AbProp = AbProp { - name: "smb_notes_v1_enabled", - code: 7710, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const SMB_PAYMENT_LINKS_CTA_BUTTON_KILL_SWITCH: AbProp = AbProp { name: "smb_payment_links_cta_button_kill_switch", code: 14967, @@ -8237,6 +8741,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const SMB_WEB_CUSTOMER_MANAGER_HEADER_MENU_ENABLED: AbProp = AbProp { + name: "smb_web_customer_manager_header_menu_enabled", + code: 33086, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SMB_WEB_ENABLE_FB_LINKING: AbProp = AbProp { name: "smb_web_enable_fb_linking", code: 30112, @@ -8321,12 +8831,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const SMOOTHIE_PERFORMANCE_CSS_DOM: AbProp = AbProp { - name: "smoothie_performance_css_dom", - code: 18995, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const SMOOTHIE_PERFORMANCE_MSG_SEND: AbProp = AbProp { name: "smoothie_performance_msg_send", code: 17942, @@ -8375,6 +8879,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const STATUS_CHAIN_FROM_CL_MODE: AbProp = AbProp { + name: "status_chain_from_cl_mode", + code: 27343, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const STATUS_CHAIN_FROM_MY_INTERACTION_LIMIT: AbProp = AbProp { + name: "status_chain_from_my_interaction_limit", + code: 27011, + value_type: AbPropType::Int, + default: AbDefault::Int(3), + }; pub const STATUS_E2EE_RECV_OVER_STATUS_STANZA: AbProp = AbProp { name: "status_e2ee_recv_over_status_stanza", code: 27622, @@ -8459,6 +8975,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(30), }; + pub const STATUS_VIEWER_ACTION_PSA_LINK_CLICK_LOGGING_ENABLED: AbProp = AbProp { + name: "status_viewer_action_psa_link_click_logging_enabled", + code: 34489, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const STATUS_WEB_RANKING: AbProp = AbProp { name: "status_web_ranking", code: 31666, @@ -8495,6 +9017,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const SUPPORT_EMAIL_CONTACT_FORM_LOGGED_IN_ENABLED: AbProp = AbProp { + name: "support_email_contact_form_logged_in_enabled", + code: 33263, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const SUPPORT_LIDS: AbProp = AbProp { name: "support_lids", code: 14317, @@ -8631,6 +9159,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(4), }; + pub const TEAMLINK_ENABLED: AbProp = AbProp { + name: "teamlink_enabled", + code: 33978, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const TEXT_STATUS_TTL_SECONDS_ALLOWLIST: AbProp = AbProp { name: "text_status_ttl_seconds_allowlist", code: 6153, @@ -8763,6 +9297,30 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const UNKNOWN_USER_PERSISTENCE_LOGGING_ENABLED: AbProp = AbProp { + name: "unknown_user_persistence_logging_enabled", + code: 34465, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const UNKNOWN_USER_TARGET_RID_LOGGING: AbProp = AbProp { + name: "unknown_user_target_rid_logging", + code: 34232, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const UNKNOWN_USER_WAM_EMIT_COOLDOWN_SECS: AbProp = AbProp { + name: "unknown_user_wam_emit_cooldown_secs", + code: 34551, + value_type: AbPropType::Int, + default: AbDefault::Int(30), + }; + pub const UNKNOWN_USER_WAM_MAX_EVENTS_PER_WINDOW: AbProp = AbProp { + name: "unknown_user_wam_max_events_per_window", + code: 32946, + value_type: AbPropType::Int, + default: AbDefault::Int(10), + }; pub const UPDATED_HARMFUL_DOCUMENT_DIALOG: AbProp = AbProp { name: "updated_harmful_document_dialog", code: 15022, @@ -8781,6 +9339,30 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const UPDATES_TAB_CHANNELS_HEADER_EXPLORE_ENTRY_POINT_VISIBILITY: AbProp = AbProp { + name: "updates_tab_channels_header_explore_entry_point_visibility", + code: 33934, + value_type: AbPropType::Int, + default: AbDefault::Int(1), + }; + pub const UPDATES_TAB_CHANNELS_SECTION_HEADER_VISIBILITY: AbProp = AbProp { + name: "updates_tab_channels_section_header_visibility", + code: 33935, + value_type: AbPropType::Int, + default: AbDefault::Int(1), + }; + pub const UPDATES_TAB_CHANNELS_SHOW_RECOMMENDATION_UNIT_ENABLED: AbProp = AbProp { + name: "updates_tab_channels_show_recommendation_unit_enabled", + code: 33937, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const UPDATES_TAB_CHANNELS_SHOW_UNFOLLOWED_SEARCH_RESULTS_ENABLED: AbProp = AbProp { + name: "updates_tab_channels_show_unfollowed_search_results_enabled", + code: 33936, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const UPLOAD_DOCUMENT_THUMB_MMS_ENABLED: AbProp = AbProp { name: "upload_document_thumb_mms_enabled", code: 247, @@ -8889,12 +9471,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const USERNAME_CREATION: AbProp = AbProp { - name: "username_creation", - code: 4745, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const USERNAME_CREATION_RESERVATION_PP_DISCLOSURE_ENABLED: AbProp = AbProp { name: "username_creation_reservation_pp_disclosure_enabled", code: 32098, @@ -8931,6 +9507,24 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const USERNAME_KEY_ENTRY_UI_V2: AbProp = AbProp { + name: "username_key_entry_ui_v2", + code: 34226, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const USERNAME_KEY_MAX_LENGTH: AbProp = AbProp { + name: "username_key_max_length", + code: 34348, + value_type: AbPropType::Int, + default: AbDefault::Int(6), + }; + pub const USERNAME_KEY_MIN_LENGTH: AbProp = AbProp { + name: "username_key_min_length", + code: 34347, + value_type: AbPropType::Int, + default: AbDefault::Int(4), + }; pub const USERNAME_KEY_REDESIGN_ENABLED: AbProp = AbProp { name: "username_key_redesign_enabled", code: 29026, @@ -8985,12 +9579,24 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; + pub const USERNAME_PREVENT_PN_POPULATE_NEW_CONTACT_CREATION: AbProp = AbProp { + name: "username_prevent_pn_populate_new_contact_creation", + code: 16495, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const USERNAME_SEARCH: AbProp = AbProp { name: "username_search", code: 15956, value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const USERNAME_SEARCH_WITHOUT_ATSIGN_ENABLED: AbProp = AbProp { + name: "username_search_without_atsign_enabled", + code: 32948, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const USERNAME_SECURITY_CODE_GENERATION: AbProp = AbProp { name: "username_security_code_generation", code: 7468, @@ -9003,6 +9609,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const USERNAME_UNKNOWN_USER_LOGGING_ENABLED: AbProp = AbProp { + name: "username_unknown_user_logging_enabled", + code: 32978, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const UTILITY_ORDER_STATUS_LOGGING_ENABLED: AbProp = AbProp { name: "utility_order_status_logging_enabled", code: 19059, @@ -9105,6 +9717,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const VOICE_CALL_STRING_TEST: AbProp = AbProp { + name: "voice_call_string_test", + code: 27841, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const VOICE_CHAT_COMPANION_EXPERIENCE_VERSION: AbProp = AbProp { name: "voice_chat_companion_experience_version", code: 17052, @@ -9165,6 +9783,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_BIZ_GAP_ENFORCEMENT_RULES_SYNC_TO_META_ENABLED_AC_LINKED_USER: AbProp = AbProp { + name: "wa_biz_gap_enforcement_rules_sync_to_meta_enabled_ac_linked_user", + code: 34290, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_BIZ_PAYMENT_TEMPLATE_CLICK_SIGNALS: AbProp = AbProp { + name: "wa_biz_payment_template_click_signals", + code: 33170, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_CAPPING_LOCAL_DATA_LOGIC_UPDATE: AbProp = AbProp { name: "wa_capping_local_data_logic_update", code: 21348, @@ -9177,6 +9807,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_COEX_BIZ_AI_CAPPING_ELIGIBLE: AbProp = AbProp { + name: "wa_coex_biz_ai_capping_eligible", + code: 34276, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_CONSUMER_ENTRY_POINT_ENABLED: AbProp = AbProp { name: "wa_consumer_entry_point_enabled", code: 24380, @@ -9333,6 +9969,36 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_NATIVE_ADS_WEB_CREATION_DUMMY: AbProp = AbProp { + name: "wa_native_ads_web_creation_dummy", + code: 33640, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_NATIVE_ADS_WEB_CREATION_ROLLOUT: AbProp = AbProp { + name: "wa_native_ads_web_creation_rollout", + code: 33639, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_NATIVE_ADS_WEB_CREATION_ROLLOUT_NO_EXPOSURE: AbProp = AbProp { + name: "wa_native_ads_web_creation_rollout_no_exposure", + code: 33752, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_NATIVE_ADS_XPLAT_DRAFT_ADS_MS1A_DUMMY_ENABLED: AbProp = AbProp { + name: "wa_native_ads_xplat_draft_ads_ms1a_dummy_enabled", + code: 33374, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_NATIVE_ADS_XPLAT_DRAFT_ADS_MS1A_ENABLED: AbProp = AbProp { + name: "wa_native_ads_xplat_draft_ads_ms1a_enabled", + code: 33372, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_NCT_TOKEN_HISTORY_SYNC_ENABLED: AbProp = AbProp { name: "wa_nct_token_history_sync_enabled", code: 25189, @@ -9381,6 +10047,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_SETTINGS_READ_RECEIPTS_COPY_V2: AbProp = AbProp { + name: "wa_settings_read_receipts_copy_v2", + code: 33610, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_SMB_BIZ_PROFILE_GOOGLE_INTEGRATION_ENABLED: AbProp = AbProp { name: "wa_smb_biz_profile_google_integration_enabled", code: 29007, @@ -9399,6 +10071,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_STATUS_CHAIN_NEW_AT_END: AbProp = AbProp { + name: "wa_status_chain_new_at_end", + code: 24110, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_STATUS_CHAIN_UNSEEN_MIN_POG: AbProp = AbProp { + name: "wa_status_chain_unseen_min_pog", + code: 24500, + value_type: AbPropType::Int, + default: AbDefault::Int(3), + }; pub const WA_WEB_ADAPTIVE_LAYOUT_ENABLED: AbProp = AbProp { name: "wa_web_adaptive_layout_enabled", code: 30140, @@ -9441,6 +10125,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; + pub const WA_WEB_BACKGROUND_NOTIFICATIONS: AbProp = AbProp { + name: "wa_web_background_notifications", + code: 33844, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_BASE_VIDEO_COMET_VIDEO_PLAYER_ENABLED: AbProp = AbProp { name: "wa_web_base_video_comet_video_player_enabled", code: 25660, @@ -9519,12 +10209,42 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_WEB_BUTTONS_RESPONSE_PROP_REMOVAL_KILLSWITCH: AbProp = AbProp { + name: "wa_web_buttons_response_prop_removal_killswitch", + code: 33817, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_WEB_CALLING_CALLS_TAB_EMPTY_STATE_UPDATE_ENABLED: AbProp = AbProp { + name: "wa_web_calling_calls_tab_empty_state_update_enabled", + code: 33154, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_WEB_CALLING_CHAT_EMPTY_STATE_UPDATE_ENABLED: AbProp = AbProp { + name: "wa_web_calling_chat_empty_state_update_enabled", + code: 33153, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_CALLING_DEEP_LINK_ERROR: AbProp = AbProp { name: "wa_web_calling_deep_link_error", code: 10051, value_type: AbPropType::Bool, default: AbDefault::Bool(true), }; + pub const WA_WEB_CALLING_SIDENAV_CALLS_TAB_NUX_ENABLED: AbProp = AbProp { + name: "wa_web_calling_sidenav_calls_tab_nux_enabled", + code: 33008, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_WEB_CALLING_WHATS_NEW_MODAL_UPDATE_ENABLED: AbProp = AbProp { + name: "wa_web_calling_whats_new_modal_update_enabled", + code: 33155, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_CANONICAL_REG_RELOAD_ENABLED: AbProp = AbProp { name: "wa_web_canonical_reg_reload_enabled", code: 29472, @@ -9543,6 +10263,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(2000), }; + pub const WA_WEB_CHAINING_FROM_MY_STATUS: AbProp = AbProp { + name: "wa_web_chaining_from_my_status", + code: 33019, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_CHANGE_LIST_WDS_SUBMENU: AbProp = AbProp { name: "wa_web_change_list_wds_submenu", code: 27123, @@ -9585,6 +10311,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_WEB_CHAT_THEMES_STOCK_WALLPAPER_SYNC_ENCODE: AbProp = AbProp { + name: "wa_web_chat_themes_stock_wallpaper_sync_encode", + code: 34349, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_CHATLIST_RENDER_CHAT_OPEN: AbProp = AbProp { name: "wa_web_chatlist_render_chat_open", code: 27947, @@ -9615,6 +10347,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(3), }; + pub const WA_WEB_CONTACT_AND_CHAT_FUZZY_SEARCH_ASYNC_ENABLED: AbProp = AbProp { + name: "wa_web_contact_and_chat_fuzzy_search_async_enabled", + code: 33433, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_CONTACT_AND_CHAT_FUZZY_SEARCH_DISTANCE_THRESHOLD: AbProp = AbProp { name: "wa_web_contact_and_chat_fuzzy_search_distance_threshold", code: 26731, @@ -9676,7 +10414,13 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const WA_WEB_DISABLE_PREFETCH_LOADABLES: AbProp = AbProp { + pub const WA_WEB_DEFENSE_MODE_QUARANTINE_EXTRA_PN_CHECK: AbProp = AbProp { + name: "wa_web_defense_mode_quarantine_extra_pn_check", + code: 33541, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_WEB_DISABLE_PREFETCH_LOADABLES: AbProp = AbProp { name: "wa_web_disable_prefetch_loadables", code: 21917, value_type: AbPropType::Bool, @@ -9898,6 +10642,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_WEB_INLINE_MESSAGE_EDIT: AbProp = AbProp { + name: "wa_web_inline_message_edit", + code: 33334, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_INVITE_LINK_PAGE_ENHANCEMENTS: AbProp = AbProp { name: "wa_web_invite_link_page_enhancements", code: 31210, @@ -9952,6 +10702,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_WEB_MEDIA_LOADER_BUTTON_UIX_IMPROVEMENT: AbProp = AbProp { + name: "wa_web_media_loader_button_uix_improvement", + code: 33245, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_MEDIA_UPLOAD_RETRY_RETRIES_COUNT: AbProp = AbProp { name: "wa_web_media_upload_retry_retries_count", code: 27782, @@ -10126,6 +10882,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_WEB_STATUS_CHAIN_FROM_CHATLIST: AbProp = AbProp { + name: "wa_web_status_chain_from_chatlist", + code: 33399, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_WEB_STATUS_CHAIN_NEW_AT_END: AbProp = AbProp { + name: "wa_web_status_chain_new_at_end", + code: 33400, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_STATUS_COMET_VIDEO_PLAYER_ENABLED: AbProp = AbProp { name: "wa_web_status_comet_video_player_enabled", code: 24791, @@ -10240,6 +11008,12 @@ pub mod web { value_type: AbPropType::Str, default: AbDefault::Str(""), }; + pub const WA_WEB_WIN_HYBRID_PLUS_ENABLED: AbProp = AbProp { + name: "wa_web_win_hybrid_plus_enabled", + code: 33753, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WA_WEB_XB_BUBBLE_ENABLED: AbProp = AbProp { name: "wa_web_xb_bubble_enabled", code: 32818, @@ -10318,6 +11092,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WA_WIN_WEBTP_PDF_VIEWER_PRELOAD_ENABLED: AbProp = AbProp { + name: "wa_win_webtp_pdf_viewer_preload_enabled", + code: 33347, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const WABAI_CONSENT_COOLDOWN: AbProp = AbProp { name: "wabai_consent_cooldown", code: 5746, @@ -10612,12 +11392,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const WDS_WEB_ACTION_TILE_REFRESH: AbProp = AbProp { - name: "wds_web_action_tile_refresh", - code: 28564, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const WDS_WEB_BADGE: AbProp = AbProp { name: "wds_web_badge", code: 27856, @@ -10876,6 +11650,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_BATCHED_STATUS_SENDING_ENABLED: AbProp = AbProp { + name: "web_batched_status_sending_enabled", + code: 34366, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_BATCHED_STATUS_SPLIT_TO_PARTS: AbProp = AbProp { + name: "web_batched_status_split_to_parts", + code: 34539, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; pub const WEB_BB_GENAI_COMPOSER_MIN_WORDS: AbProp = AbProp { name: "web_bb_genai_composer_min_words", code: 32054, @@ -11038,12 +11824,24 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_CALLING_PAUSE_BG_DURING_CALL_MODE: AbProp = AbProp { + name: "web_calling_pause_bg_during_call_mode", + code: 34144, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; pub const WEB_CALLING_PERF_OPTIMIZATIONS_BITMASK: AbProp = AbProp { name: "web_calling_perf_optimizations_bitmask", code: 22186, value_type: AbPropType::Int, default: AbDefault::Int(1), }; + pub const WEB_CALLING_SMOOTH_CALL_LINK_LOBBY: AbProp = AbProp { + name: "web_calling_smooth_call_link_lobby", + code: 33131, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; pub const WEB_CALLING_SPEAKER_STRIP_RESIZE_ENABLED: AbProp = AbProp { name: "web_calling_speaker_strip_resize_enabled", code: 30928, @@ -11092,6 +11890,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_CHATLIST_FTS_LISTENER_CLEANUP: AbProp = AbProp { + name: "web_chatlist_fts_listener_cleanup", + code: 33181, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_CHATPSA_FORWARDING: AbProp = AbProp { name: "web_chatpsa_forwarding", code: 23695, @@ -11182,6 +11986,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_DETACHED_DOM_UNMOUNT_CLEANUP: AbProp = AbProp { + name: "web_detached_dom_unmount_cleanup", + code: 33393, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_DEXIE_HOOKS_SUPPORT_ENABLED: AbProp = AbProp { name: "web_dexie_hooks_support_enabled", code: 12831, @@ -11224,6 +12034,18 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(5), }; + pub const WEB_E2E_STATUS_LIKES_SENDING_ENABLED: AbProp = AbProp { + name: "web_e2e_status_likes_sending_enabled", + code: 34296, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_EMAIL_INVITES_GROUP_INFO: AbProp = AbProp { + name: "web_email_invites_group_info", + code: 33556, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_ENABLE_BIZ_CATALOG_VIEW_PS_LOGGING: AbProp = AbProp { name: "web_enable_biz_catalog_view_ps_logging", code: 2056, @@ -11320,6 +12142,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_GUEST_CALLING_WAITING_ROOM_ADMIN_XP_ENABLED: AbProp = AbProp { + name: "web_guest_calling_waiting_room_admin_xp_enabled", + code: 33384, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_GUEST_CALLING_WAITING_ROOM_APPROVAL_NOTE_ENABLED: AbProp = AbProp { + name: "web_guest_calling_waiting_room_approval_note_enabled", + code: 33385, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_HISTORY_SYNC_ALLOW_DUPLICATE_IN_BULK_ERROR: AbProp = AbProp { name: "web_history_sync_allow_duplicate_in_bulk_error", code: 10842, @@ -11404,6 +12238,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_LINK_PREVIEW_DEBOUNCE_PERIOD_MS: AbProp = AbProp { + name: "web_link_preview_debounce_period_ms", + code: 33339, + value_type: AbPropType::Int, + default: AbDefault::Int(700), + }; pub const WEB_LINK_PREVIEW_SYNC_ENABLED: AbProp = AbProp { name: "web_link_preview_sync_enabled", code: 2156, @@ -11422,6 +12262,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_LOOM_STUCK_TRACE_TIMEOUT_MS: AbProp = AbProp { + name: "web_loom_stuck_trace_timeout_ms", + code: 34304, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; pub const WEB_LOW_END_DEVICE_LEVEL: AbProp = AbProp { name: "web_low_end_device_level", code: 18747, @@ -11470,6 +12316,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_MEMLAB_FIXES: AbProp = AbProp { + name: "web_memlab_fixes", + code: 33563, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_MEMLAB_FIXES_2: AbProp = AbProp { + name: "web_memlab_fixes_2", + code: 34305, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_MEMORY_REDUCTION: AbProp = AbProp { name: "web_memory_reduction", code: 30394, @@ -11488,6 +12346,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_MESSAGE_DROP_BULK_DB_OPERATION_FALLBACK_ENABLED: AbProp = AbProp { + name: "web_message_drop_bulk_db_operation_fallback_enabled", + code: 7865, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_MESSAGE_LIST_A11Y_REDESIGN: AbProp = AbProp { name: "web_message_list_a11y_redesign", code: 2016, @@ -11662,6 +12526,12 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; + pub const WEB_PAYMENT_NOTIFICATIONS_ACK_KICK_FIX_ENABLED: AbProp = AbProp { + name: "web_payment_notifications_ack_kick_fix_enabled", + code: 7546, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_PDF_THUMBNAIL_SIZE_IN_BYTES: AbProp = AbProp { name: "web_pdf_thumbnail_size_in_bytes", code: 16834, @@ -11824,6 +12694,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_SELF_ADV_DAILY_USE_LID: AbProp = AbProp { + name: "web_self_adv_daily_use_lid", + code: 34414, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_SEND_HID_FAILED_DECRYPT_IN_RECEIPTS_ENABLED: AbProp = AbProp { name: "web_send_hid_failed_decrypt_in_receipts_enabled", code: 31113, @@ -11872,6 +12748,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_STATUS_BATCH_SIZE: AbProp = AbProp { + name: "web_status_batch_size", + code: 34540, + value_type: AbPropType::Int, + default: AbDefault::Int(500), + }; pub const WEB_STATUS_CROSSPOSTING_ENABLED: AbProp = AbProp { name: "web_status_crossposting_enabled", code: 21501, @@ -11884,12 +12766,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const WEB_STATUS_PSA: AbProp = AbProp { - name: "web_status_psa", - code: 873, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const WEB_STATUS_RANKING: AbProp = AbProp { name: "web_status_ranking", code: 31683, @@ -11902,6 +12778,18 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_STATUS_RECV_VIA_SMAX: AbProp = AbProp { + name: "web_status_recv_via_smax", + code: 34258, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_STATUS_SEND_VIA_SMAX: AbProp = AbProp { + name: "web_status_send_via_smax", + code: 34259, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_STICKER_SUGGESTIONS_ENABLE: AbProp = AbProp { name: "web_sticker_suggestions_enable", code: 4726, @@ -11980,12 +12868,6 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; - pub const WEB_VIEW_MODE_USAGE_ENABLED: AbProp = AbProp { - name: "web_view_mode_usage_enabled", - code: 10856, - value_type: AbPropType::Bool, - default: AbDefault::Bool(false), - }; pub const WEB_VOIP_ADAPTIVE_SCTP_PREWARM: AbProp = AbProp { name: "web_voip_adaptive_sctp_prewarm", code: 32804, @@ -12034,12 +12916,36 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_VOIP_OUTGOING_CALL_SETUP_LATENCY_MODE: AbProp = AbProp { + name: "web_voip_outgoing_call_setup_latency_mode", + code: 33122, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const WEB_VOIP_RUNTIME_STACK_SELECTION_ENABLED: AbProp = AbProp { + name: "web_voip_runtime_stack_selection_enabled", + code: 33151, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_VOIP_SCTP_WORKER_SAFARI_EXP: AbProp = AbProp { name: "web_voip_sctp_worker_safari_exp", code: 27695, value_type: AbPropType::Int, default: AbDefault::Int(1), }; + pub const WEB_VOIP_SKIP_OFFLINE_WAIT_ON_CALL_INTENT: AbProp = AbProp { + name: "web_voip_skip_offline_wait_on_call_intent", + code: 33310, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_VOIP_USE_CONTENT_ADDRESSED_WASM: AbProp = AbProp { + name: "web_voip_use_content_addressed_wasm", + code: 33389, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WEB_VOIP_VIDEO_CAPTURE_IMPL: AbProp = AbProp { name: "web_voip_video_capture_impl", code: 21350, @@ -12094,6 +13000,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WEB_WHATS_NEW_AUTO_MODAL_CONTENT_VERSION: AbProp = AbProp { + name: "web_whats_new_auto_modal_content_version", + code: 33475, + value_type: AbPropType::Int, + default: AbDefault::Int(2), + }; pub const WEB_WHATS_NEW_AUTO_MODAL_SHORT_COOLDOWN: AbProp = AbProp { name: "web_whats_new_auto_modal_short_cooldown", code: 29622, @@ -12202,6 +13114,30 @@ pub mod web { value_type: AbPropType::Int, default: AbDefault::Int(0), }; + pub const WIN_HYBRID_VSR_BUTTON_ENABLED: AbProp = AbProp { + name: "win_hybrid_vsr_button_enabled", + code: 34272, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_HYBRID_VSR_BUTTON_ENABLED_2: AbProp = AbProp { + name: "win_hybrid_vsr_button_enabled_2", + code: 34279, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_HYBRID_VSR_ENABLED: AbProp = AbProp { + name: "win_hybrid_vsr_enabled", + code: 34271, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_HYBRID_VSR_ENABLED_2: AbProp = AbProp { + name: "win_hybrid_vsr_enabled_2", + code: 34280, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WIN_NETWORK_STATE_WATCHDOG_INTERVAL: AbProp = AbProp { name: "win_network_state_watchdog_interval", code: 7737, @@ -12250,6 +13186,12 @@ pub mod web { value_type: AbPropType::Bool, default: AbDefault::Bool(false), }; + pub const WMI_JM_TO_TS_SERVICED: AbProp = AbProp { + name: "wmi_jm_to_ts_serviced", + code: 34410, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; pub const WMI_TASK_SCHEDULER_SECOND_STEP: AbProp = AbProp { name: "wmi_task_scheduler_second_step", code: 30276, @@ -12275,7 +13217,7 @@ pub mod web { default: AbDefault::Bool(false), }; - /// All 2036 flags in this registry, sorted by name. + /// All 2193 flags in this registry, sorted by name. pub const ALL: &[AbProp] = &[ A2UI_SUPPORTED_ELEMENTS, ACP_REMOVAL, @@ -12287,15 +13229,17 @@ pub mod web { ADD_TO_CALL_IN_CHAT_THREAD, ADDON_INFRA_ENABLE_PERF_LOGGING, ADMIN_ONLY_MENTION_EVERYONE_GROUP_SIZE, - ADMIN_REVOKE_RECEIVER, ADV_ACCEPT_HOSTED_DEVICES, - ADV_V2_M4_M5, ADVANCED_CHAT_PRIVACY_CONTENT_UPDATE_JULY_25, AFTER_READ_FALLBACK_DURATION, AFTER_READ_RECEIVER_ENABLED, AFTER_READ_SENDING_ENABLED, AI_3P_AGENT_CHAT_ENABLED, AI_3P_AGENT_LINK_ENABLED, + AI_3P_AGENT_MEDIA_SUPPORT_MODE, + AI_3P_BOT_PRODUCT_CHAT_RENDERING_ENABLED, + AI_3P_BOT_PRODUCT_NUX_NOTICE_ID, + AI_ACCOUNT_LINKING_ENABLED, AI_ALL_LANGUAGES_ENABLED, AI_ASSET_REPLACEMENT_ENABLED, AI_BIZAI_2WAY_INTEGRATION_ENABLED, @@ -12310,6 +13254,7 @@ pub mod web { AI_CHAT_META_AI_HOME_WEB_ENABLED, AI_CHAT_META_AI_NULL_STATE_WEB_ENABLED, AI_CHAT_THREAD_CAPABILITY_ENABLED, + AI_CHAT_THREADS_EXPORT_BY_THREADS_ENABLED, AI_CHAT_THREADS_FUZZY_SEARCH_ENABLED, AI_CHAT_THREADS_HISTORICAL_MESSAGES_MIGRATION_ENABLED, AI_CHAT_THREADS_HISTORY_ICON_VARIANT, @@ -12352,6 +13297,7 @@ pub mod web { AI_GROUP_PARTICIPATION_SEND_ENABLED, AI_GROUP_SEND_MENTIONED_PUSHNAME_ENABLED, AI_GROUP_TEE_HISTORY_SHARE_ENABLED, + AI_GROUP_TEE_REQUIRE_ADDITIONAL_MEMBER_ENABLED, AI_GROUPS_OPEN_ENABLED, AI_HATCH_COMMANDS_ENABLED, AI_HATCH_DOCUMENT_UPLOAD_SIZE_LIMIT_MB, @@ -12400,6 +13346,8 @@ pub mod web { AI_REWRITE_STACK_UNDO_ENABLED, AI_REWRITE_SUPPORTED_LANGUAGES, AI_REWRITE_TONE_MODIFIERS, + AI_RICH_RESPONSE_FORWARD_MEDIA_RECEIVING_ENABLED, + AI_RICH_RESPONSE_FORWARD_MEDIA_SENDING_ENABLED, AI_RICH_RESPONSE_FORWARD_RECEIVING_ENABLED, AI_RICH_RESPONSE_FORWARD_SENDING_ENABLED, AI_RICH_RESPONSE_FORWARDING_VERIFICATION_ENABLED_V1, @@ -12429,13 +13377,17 @@ pub mod web { AI_SEARCH_NULL_STATE_UPDATE_INTERVAL, AI_SESSION_TRANSPARENCY_META_AI_ENABLED, AI_SIMPLIFIED_PROFILE_PAGE_ENABLED, + AI_STANDARD_BOT_PROFILE_ENABLED, + AI_SUBSCRIPTION_ENABLED, AI_SUBSCRIPTION_IMAGINE_INTENT_ENABLED, + AI_SUBSCRIPTION_IMAGINE_INTENT_METERING_ENABLED, AI_SUBSCRIPTION_METERING_ENABLED, AI_TAB_UNREAD_BADGE_RECENCY_WINDOW_HOURS, AI_UGC_HIDE_ENABLED, AI_UGC_NOT_AN_EXPERT_ENABLED, AI_UNIFIED_RESPONSE_FORWARDING_SENDER_WEB_TIMESTAMP, AI_UNIFIED_RESPONSE_IMAGINE_RECEIVER_WEB_ENABLED, + AI_UNIFIED_RESPONSE_MUTATION_ENABLED, AI_UNIFIED_RESPONSE_QPL_LOGGING, AI_UNIFIED_RESPONSE_RECEIVER_WEB_ENABLED, AI_UNIFIED_RESPONSE_RECEIVER_WEB_ENABLED_V2, @@ -12447,17 +13399,18 @@ pub mod web { AI_VOICE_ENTRY_POINT_LOGGING_ENABLED, AI_VOICE_MULTIMODAL_COMPOSER_ENABLED, AI_WEB_ASK_META_AI_ENABLED, + AI_WEB_ASK_META_AI_MEDIA_FORWARD_ENABLED, AI_WEB_FORWARD_FLOW_ENABLED, AI_WEB_META_AI_IMAGE_INPUT_ENABLED, AI_WEB_META_AI_PDF_DOCUMENT_INPUT_ENABLED, AIGC_VERSION, ALBUM_V2_FORWARD_AS_ALBUM_ENABLED, - ALBUM_V2_ITEM_WITH_CAPTION_IN_ALBUM_RECEIVER_ENABLED, ALBUM_V2_MIN_ITEMS_TO_SEND_ALBUM_WITH_CAPTION, ALBUM_V2_MIN_ITEMS_TO_SEND_AS_ALBUM_ENABLED, ALBUM_V2_RECEIVING_ENABLED, ALBUM_V2_SENDER_ENABLED, ALLOW_BACKFILL_WITH_V0_TO_V1_PRIMARY_VERSION_TRANSITION, + ANDROID_INBOX_MENTIONS_REPLIES_FILTER, ANIMATED_EMOJI_FINAL_SET_ENABLED, ANIMATED_EMOJI_SET_1_ENABLED, ANIMATED_EMOJI_USE_LAZY_PARSING, @@ -12468,13 +13421,18 @@ pub mod web { ANYONE_CAN_LINK_TO_GROUPS, APP_EXIT_REASON_VERSION, APPOINTMENT_BOOKING_BLOKS_ENABLED, + ATTACH_INVITEE_USER_PN_IN_OFFER, ATTACH_TRANSPORT_RTX, AUDIO_LEVEL_SPEAKING_THRESHOLD, AURA_APP_THEMES_BENEFIT_ACTIVE, AURA_APP_THEMES_ENABLED, AURA_ENABLED, AURA_FOCUS_LISTS_BENEFIT_ACTIVE, + AURA_FOCUS_LISTS_DEFAULT_LIST_ENABLED, AURA_FOCUS_LISTS_ENABLED, + AURA_FOCUS_LISTS_EXCLUSION_ENABLED, + AURA_FOCUS_LISTS_SCHEDULE_ENABLED, + AURA_GROUP_REACTIONS_BLOCKING_ENABLED, AURA_KILL_SWITCH, AURA_MEDIA_OFFLOAD_BENEFIT_ACTIVE, AURA_MEDIA_OFFLOAD_ENABLED, @@ -12492,10 +13450,12 @@ pub mod web { AURA_STICKERS_ENABLED, AURA_STICKERS_OVERLAY_ANIMATION_ENABLED, AURA_STICKERS_PREVIEW_MAX_ANIMATION_COUNT, + AURA_STICKERS_QP_BANNER_UPSELL_SHEET_ENABLED, AURA_SUBSCRIPTION_SIMULATION_ENABLED, AUTH_AGENT_SOFT_OFFBOARDING_ENABLED, AUTH_AGENTS_CONSUMER_EXP_ENABLED, AUTH_AGENTS_CONSUMER_OFFBOARDING_EXP_ENABLED, + BACKFILL_CHECK_PRIMARY_IDENTITY_KEY, BACKFILL_SUPPORTS_COEX_COMPANION, BANNED_SHOPS_UX_ENABLED, BB_CHAT_LIST_BANNER_1, @@ -12527,18 +13487,26 @@ pub mod web { BIZ_AI_CONSUMER_TOS_NOTICE_IQ_WEB, BIZ_AI_CONSUMER_TOS_UPDATE_WEB, BIZ_AI_FAB_CONFIRM_MODAL_ENABLED, + BIZ_AI_FAB_ENABLED, + BIZ_AI_HANDOFF_TIMING_SYNC_ENABLED, BIZ_AI_IN_THREAD_UNMUTE_V2, BIZ_AI_LARGE_SCREENS_GATE_FETCH_ENABLED, BIZ_AI_PRIORITY_LIST_ENABLED, + BIZ_AI_PRIORITY_LIST_ITEM_EXPIRE_DAYS, BIZ_AI_RESPONDING_LIST_ENABLED, BIZ_AI_SMB_AGENTS_AUTOMATIC_REPLY_ENABLED, BIZ_AI_TOOLS_SETTINGS, BIZ_AI_TOOLS_SYNC, BIZ_AI_TOS_VARIANT, + BIZ_AI_WEB_AI_HUB_CHAT_NAV_ENABLED, BIZ_AI_WEB_AI_HUB_TAP_CTA_SHOW_ALERT, BIZ_AI_WEB_BULK_THREAD_CONTROL_ENABLED, + BIZ_AI_WEB_GDRIVE_ENABLED, + BIZ_AI_WEB_HUB_CHAT_ENABLED, + BIZ_AI_WEB_INTEGRATION_HUB_ENABLED, BIZ_AI_WEB_ONBOARDING_HANDOFF, BIZ_AI_WEB_ONBOARDING_HANDOFF_KILLSWITCH, + BIZ_AI_WEB_SMART_COMPOSER_ENABLED, BIZ_VPV_DIMENSIONS_LOGGING_ENABLED, BIZ_VPV_IMPRESSION_LOGGING_ENABLED, BLOCKLIST_SYSTEM_MSG_ON_FULL_REFETCH, @@ -12563,9 +13531,16 @@ pub mod web { BONSAI_UPDATE_INTERVAL, BONSAI_WORD_STREAMING_ENABLED, BOOKING_CONFIRMATION_ENABLED_WA_WEB, - BOT_3P_ENABLED, BOT_3P_STATUS, BOT_PROFILE_SYNC_MIGRATION_ENABLED, + BR_CONSUMER_DELETE_PAYMENT_INFO_WEB_ENABLED, + BR_CONSUMER_PAYMENTS_HOME_WEB_ENABLED, + BR_CONSUMER_PIX_ACTIONS_WEB_ENABLED, + BR_CONSUMER_PIX_CONTACT_INFO_WEB_ENABLED, + BR_CONSUMER_PIX_GROUPS_WEB_ENABLED, + BR_CONSUMER_PIX_SYNC_RECEIVE_ENABLED, + BR_CONSUMER_PIX_SYNC_RECEIVE_WEB_ENABLED, + BR_CONSUMER_TRANSACTIONS_DATE_FILTER_WEB_ENABLED, BR_ENABLE_PAYMENT_LOGOS_ON_BUBBLE, BR_PAYMENTS_HOME_DURATION_RULE_FOR_PUX_BANNER, BR_PAYMENTS_PAYMENT_DETECTION_ENHANCEMENT, @@ -12595,14 +13570,16 @@ pub mod web { CALL_INFO_OPTIMIZATIONS_AHGC_CALL_LINK, CALL_INFO_OPTIMIZATIONS_LGC, CALL_INFO_OPTIMIZATIONS_VERSION, - CALL_INFO_USE_TYPED_JID, CALL_OFFER_FAILED_SOFT_LANDING_SCREEN_VERSION, CALL_SCREEN_SHARE_DUAL_STREAM_APP_UPDATE_DIALOG_ENABLED, CALLEE_ACCEPT_TIMEOUT_MS, CALLING_32P_VERSION, CALLING_AUDIO_SHARE_VERSION, CALLING_AV_SYNC_WEBRTC, - CALLING_E2E_KEYGEN_VIA_SELF_LID, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_BATTERY_THRESHOLD_PCT, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_ENABLED, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_INCLUDE_LOW_DATA_USAGE, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_POOR_NETWORK_TIME_MS, CALLING_LID_VERSION, CALLING_RUST_MIGRATION_BITMAP, CALLING_RUST_MIGRATION_INCOMING_ACK_STANZA_BITMAP, @@ -12617,6 +13594,7 @@ pub mod web { CAMERA_HEALTH_CHECK_DELAY, CAMERA_HEALTH_CHECK_PERIOD, CANONICAL_ENT_COMPANION_SERVER_CACHED_NONCE_ENABLED, + CAP_CONTEXT_INFO_MAX_ARRAY_LENGTH, CAROUSEL_MESSAGE_CLIENT_ENABLED, CATALOG_CATEGORIES_ENABLED, CCI_COMPLIANCE_CTWA, @@ -12639,7 +13617,9 @@ pub mod web { CHANNEL_REACTIONS_SENDER_LIST_ENABLED, CHANNEL_REACTIONS_SETTINGS_ENABLED, CHANNEL_STATUS_CONSUMPTION, + CHANNEL_STATUS_CONSUMPTION_MUSIC_ENABLED, CHANNEL_STATUS_CREATION, + CHANNEL_STATUS_CREATION_PROFILE_RING_ENABLED, CHANNEL_STATUS_DEEPLINK_ENABLED, CHANNEL_STATUS_FILL_GAP_PAGE_SIZE, CHANNEL_STATUS_FORWARDING_ENABLED, @@ -12656,10 +13636,13 @@ pub mod web { CHANNELS_ADMIN_INSIGHTS_GIZMOS_ENABLED, CHANNELS_ADMIN_NOTIFICATIONS_ENABLED, CHANNELS_ADMIN_NOTIFICATIONS_FORWARDS_ENABLED, + CHANNELS_ADMIN_PROFILES_BANNER_ENABLED, CHANNELS_ADMIN_PROFILES_FORWARDING_TO_CHATS_ENABLED, CHANNELS_ADMIN_PROFILES_LIST_ENABLED, CHANNELS_ADMIN_PROFILES_RECEIVER_ENABLED, CHANNELS_ADMIN_PROFILES_SENDER_ENABLED, + CHANNELS_ADMIN_PROFILES_SETTINGS_ENABLED, + CHANNELS_ADMIN_PROFILES_UPDATE_ENABLED, CHANNELS_ADMIN_REPLY_ENABLED, CHANNELS_ADMIN_REPLY_RECEIVER_ENABLED, CHANNELS_ALBUM_RECEIVER_ENABLED, @@ -12727,7 +13710,6 @@ pub mod web { CHANNELS_QUESTION_ADMIN_ENABLED, CHANNELS_QUESTION_ADMIN_M2_ENABLED, CHANNELS_QUESTION_FETCH_RESPONSES_PAGE_SIZE, - CHANNELS_QUESTION_FOLLOWER_ENABLED, CHANNELS_QUESTION_FOLLOWER_M2_ENABLED, CHANNELS_QUESTION_FORWARD_MESSAGE_TYPES_CHAT_M1_ENABLED, CHANNELS_QUESTION_FORWARD_MESSAGE_TYPES_CHAT_M2_ENABLED, @@ -12749,14 +13731,19 @@ pub mod web { CHANNELS_QUIZ_RECEIVING_ENABLED, CHANNELS_QUIZ_SENDING_ENABLED, CHANNELS_REACTIONS_BOTTOMSHEET_TAP_TO_REACT_ENABLED, + CHANNELS_RECOMMENDATION_UNIT_REMOVAL_V1_ENABLED, CHANNELS_RECOMMENDED_V3_UI_LIMIT, CHANNELS_REPLY_FORWARD_MESSAGE_TYPES_CHAT_M1_ENABLED, CHANNELS_REPLY_FORWARD_MESSAGE_TYPES_CHAT_M2_ENABLED, CHANNELS_REPLY_FORWARD_MESSAGE_TYPES_STATUS_M2_ENABLED, + CHANNELS_SCHEDULING_UPDATES_ENABLED, + CHANNELS_SCHEDULING_UPDATES_MESSAGE_TYPES, CHANNELS_SEND_ALBUM_ENABLED, CHANNELS_SEND_VIEW_RECEIPT_ENABLED, CHANNELS_SGI_RECEIVER_ENABLED, CHANNELS_SGI_SENDER_ENABLED, + CHANNELS_SGI_SENDER_SELF_DISCLOSURE_ENABLED, + CHANNELS_SGI_UI_LABEL_ENABLED, CHANNELS_SHARE_LINK_LOGGING_ENABLED, CHANNELS_STATUS_CONSUMPTION_ENTRYPOINTS, CHANNELS_STATUS_UPDATES_CONSUMPTION_ENABLED, @@ -12788,21 +13775,30 @@ pub mod web { COMMUNITY_ANNOUNCEMENT_GROUP_SIZE_LIMIT, COMMUNITY_GENERAL_CHAT_UI_ENABLED, COMMUNITY_GENERAL_CHAT_CREATE_ENABLED, + COMPANION_CONTACT_REFRESH, + COMPANION_CONTACT_REFRESH_DEBOUNCE_MS, + COMPANION_CONTACT_REFRESH_RECEIVER, + COMPANION_INITIATED_COMPANION_CONTACT_REFRESH, CONSUMER_GRAPHQL_ENABLE_DOUBLE_LOG_FOR_SURVEY, CONSUMER_GRAPHQL_WEB_TO_FETCH_QP_SURFACE_IDS, CONSUMER_WEB_QP_GRAPHQL_TO_FETCH_QP_FREQUENCY_MINS, + CONTEXT_MENU_CONTENT_FIX, COUNTRY_CLIENT_GATING_ENABLED, COUPON_COPY_BUTTON_URL, CREATE_GROUP_AND_ADD_MEMBER_OVERFLOW, CROSS_DEVICE_MESSAGE_EDITING, CTWA_1PD_LONGEST_CALL_ENABLED, + CTWA_1PD_WEB_NBF_SIGNALS_ENABLED, CTWA_3PD_AGGREGATED_CALL_LOGGING_ALLOWED, CTWA_3PD_AGGREGATED_CONVERSION_ENABLED, + CTWA_3PD_CONVERSION_ON_AE_DETECTION, CTWA_3PD_DATA_SHARING_ADDITIONAL_LOGGING, CTWA_3PD_DATA_SHARING_COOLDOWN_MAX_TIMES_SHOWN_FOR_OPTED_OUT, + CTWA_3PD_DATA_SHARING_DISCLOSURE_ON_LISTS_HOME, CTWA_3PD_DATA_SHARING_ON_THREAD_ENTRY, CTWA_3PD_DATA_SHARING_TITLE_CHANGE, CTWA_3PD_OPT_OUT_COUNTER_OPTIMIZATION_ENABLED, + CTWA_3PD_POST_DC_DEPTH_LIMIT, CTWA_AD_ACCOUNT_NONCE_PUSH_WAIT_TIMEOUT_WEB, CTWA_AD_ACCOUNT_NONCE_RETRIES_MAX_WEB, CTWA_AD_ACCOUNT_TOKEN_STORAGE_KILL_SWITCH_WEB, @@ -12836,7 +13832,6 @@ pub mod web { CTWA_SMB_DATA_SHARING_CONSENT, CTWA_SMB_DATA_SHARING_OPT_IN_COOL_OFF_PERIOD, CTWA_SMB_DATA_SHARING_SETTINGS_KILLSWITCH, - CTWA_SMB_DETECTED_OUTCOME_LABELS_ENABLED, CTWA_SMB_DETECTED_OUTCOME_LABELS_MERGER_ENABLED, CTWA_SMB_DETECTED_OUTCOME_LISTS_ENABLED, CTWA_SMB_LABEL_CHAT_HEADER_ENABLED_WEB, @@ -12858,6 +13853,7 @@ pub mod web { DATA_PRIVACY_PHASE_2_NON_E2EE_ENABLED, DATA_SHARING_TRANSPARENCY_INDICATOR_DURATION, DAU_FIX_DELAY_PRESENCE_ON_FOCUS, + DEDUPE_LID_PN_IDENTITY_KEY_STORES, DEFAULT_AUDIO_LIMIT_MB, DEFAULT_ENDPOINT_THREAD_POLL_TIMEOUT, DEFAULT_MEDIA_LIMIT_MB, @@ -12872,6 +13868,7 @@ pub mod web { DEV_PROP_FLOAT, DEV_PROP_INT, DEV_PROP_STRING, + DEVICE_CAPABILITIES_V2_SYNC_ENABLED, DEVICE_SWITCHING_ENABLED, DIALER_PAD_FOR_NEW_CHATS, DIRECT_CONNECTION_BUSINESS_NUMBERS, @@ -12920,30 +13917,34 @@ pub mod web { ENABLE_CALL_TRANSFER_NOTIFICATION, ENABLE_CALLING_PHONE_NUMBER_PRIVACY, ENABLE_CALLING_USERNAME, + ENABLE_CALLUSER_VIDEO_DEEPLINK, ENABLE_CHANNEL_VIDEO_SERVER_THUMBNAIL, ENABLE_CHAT_LIST_STICKER_EMOJIS, ENABLE_CHAT_PSA_AUTO_PLAY_VIDEOS, ENABLE_CLEAR_FORMATTED_PREVIEW, - ENABLE_COMMUNITY_SUSPEND_AND_APPEALS, ENABLE_COPY_PASTE_P2P, ENABLE_CTWA_ML_ENTRY_POINT_CONFIG, ENABLE_DAYS_SINCE_RECEIVE_LOGGING, ENABLE_EARLY_AUDIO_DRIVER_START, ENABLE_EVENTS_V2_ADD_TO_CALENDAR, ENABLE_EVENTS_V2_ENTRY_POINTS_CREATION, + ENABLE_EVENTS_V2_INVITE_MESSAGE_UPDATE, ENABLE_EVENTS_V2_INVITE_MESSAGE_WITH_DATETIME, ENABLE_EVENTS_V2_ON_COMPANION, ENABLE_FMX_LOGGING, ENABLE_FORCE_VOIP_LOGGING, + ENABLE_FSA_SAVE_AS, ENABLE_FUTUREPROOF_GALAXY_FLOW_MESSAGE_FOR_BUSINESS_NUMBERS, ENABLE_GRID_LAYOUT_TILE_UNIFICATION, ENABLE_GROUP_CREATE_OR_ADD_RATE_LIMITING_ERROR_UX, ENABLE_HYBRID_CALL_LINKS_CREATION, ENABLE_HYBRID_CALL_LINKS_JOIN, + ENABLE_HYBRID_OPEN_WITH_SHARED_BUFFER, ENABLE_HYBRID_VIDEO_TRANSCODING, ENABLE_HYBRID_VIDEO_TRANSCODING_FOR_VALID_MP4, ENABLE_INIT_BWE_FOR_GROUP_CALL, ENABLE_JOIN_GROUP_CONTEXT_NON_AUTO_EXPOSE, + ENABLE_JOIN_ONGOING_CALL_REFACTOR, ENABLE_LAZY_LOADING_OF_CALL_VIEW_ELEMENTS, ENABLE_LID_CALL_LINK, ENABLE_LOGGING_QBM_INCOMING_MESSAGE, @@ -12958,6 +13959,7 @@ pub mod web { ENABLE_ORBIT_SSO_BRIDGE, ENABLE_ORDER_DETAILS_FOR_PAYMENT_KEY, ENABLE_PEER_SNAPSHOT_RECOVERY, + ENABLE_POLL_RESULTS_CONTACT_INFO_ENTRY_POINT, ENABLE_POLL_SETTINGS_LABEL_IMPROVED_LAYOUT, ENABLE_PRE_WARM_AUDIO_COMPONENT, ENABLE_PRIVACY_TOKEN_WITH_TIMESTAMP, @@ -12994,15 +13996,19 @@ pub mod web { ENABLE_WEB_GROUP_CALLING, ENABLE_WEB_LOG_DOWNLOAD, ENABLE_WEB_VOIP_ANR_OPTIMIZATIONS, + ENABLE_WEB_VOIP_AUDIO_DRIVER_LIFETIME_FIX, ENABLE_WEB_VOIP_DYNAMIC_FPS_THROTTLE, ENABLE_WEB_VOIP_EAGER_MIC_ACQUIRE, ENABLE_WEB_VOIP_P2P, ENABLE_WEB_VOIP_PLATFORM_AV_SYNC, ENABLE_WEB_VOIP_PROXY_AND_SCTP_WORKERS, + ENABLE_WEB_VOIP_VIDEO_CAPTURE_DOM_ATTACH, ENABLE_WEB_VOIP_VIDEO_RESOLUTION_CAP, ENABLE_WEB_VOIP_VIRTUAL_AUDIO_CAPTURE_DRIVER, ENABLE_WEB_VOIP_VIRTUAL_VIDEO_CAPTURE_DRIVER, ENABLE_WEB_VOIP_WEBTRANSPORT, + ENABLE_WEB_VOIP_WEBTRANSPORT_FALLBACK, + ENABLE_WEB_VOIP_WORKER_POOL_RECLAIM_ON_REJOIN, ENABLE_WEBCODEC_REQUIRE_KEYFRAME, ENABLE_WEBCODEC_VIDEO_ENCODE, ENABLE_WEBRTC_VIDEO_JB, @@ -13011,15 +14017,14 @@ pub mod web { ENABLE_WINDOWS_JUMPLIST_HYBRID, ENABLE_WINDOWS_MOCKS_CAPTURE_DRIVERS, ENABLE_WINDOWS_XDR_CHAT_HANDOFF, + ENABLE_WINDOWS_XDR_WNS_PKEY, ENHANCED_MENTION_LIMIT, ENHANCED_MENTION_SUGGESTIONS_MIN_MENTION_CHAR_COUNT, ENHANCED_MENTION_SUGGESTIONS_NON_GROUP_MEMBERS_ENABLED, EPHEMERAL_SYNC_RESPONSE, EVENT_DESCRIPTION_LENGTH_LIMIT, EVENT_NAME_LENGTH_LIMIT, - EVENTS_CREATE, EVENTS_CREATE_CAG_ENABLED, - EVENTS_EDIT_RECEIVE, EVENTS_M3_COVER_IMAGE_RECEIVE, EVENTS_M3_COVER_IMAGE_SEND, EVENTS_V2_ENABLE_NOTIFICATIONS, @@ -13040,18 +14045,20 @@ pub mod web { FAVORITES_LIMIT, FEATURE_KEY_STORE_INFRA_ENABLED, FETCH_QP_VIA_GRAPHQL_WEB_ENABLED, - FLATTENED_REACTIONS_COLLECTION, FLOWS_TERMINATION_MESSAGE_V2_SENDING_ENABLED, FLOWS_WA_WEB, FLOWS_WA_WEB_AGM_CTA, FLOWS_WA_WEB_RESPONSES_DOWNLOAD, FMX_CTWA_KILL_SWITCH, + FMX_PERSISTENT_COUNTRY_TRUST_SIGNAL_ENABLED, FORWARDED_MESSAGE_USER_JOURNEY_LOGGING_ENABLED, FOUR_REACTIONS_IN_BUBBLE_ENABLED, FT_VALIDATION_FAILURE_DROP_PLACEHOLDER, FULLSCREEN_ANIMATION_FOR_KEYWORD, FUNCTIONAL_CHATLIST_ENABLED, + FUNCTIONAL_EMOJI_TEXT_ENABLED, FUTUREPROOF_ASSOCIATED_CHILD_ENABLED, + GC_DEVICE_SWITCH_SHOW_ENTRY_POINT, GC_DEVICE_SWITCHING_KILLSWITCH, GENAI_EARLY_AUDIO_PRE_BUF_SIZE, GIF_MAX_PLAY_DURATION, @@ -13065,7 +14072,6 @@ pub mod web { GROUP_CALL_MAX_PARTICIPANTS, GROUP_CALLING_WAVE_RECEIVING_ENABLED, GROUP_CALLING_WAVE_SENDING_ENABLED, - GROUP_CATCH_UP, GROUP_CREATE_ADD_USING_LID_JIDS, GROUP_DESCRIPTION_LENGTH, GROUP_FROM_GROUP, @@ -13092,8 +14098,6 @@ pub mod web { GROUP_HISTORY_SETTINGS_QUERY, GROUP_HISTORY_SETTINGS_TOGGLE_UI, GROUP_HISTORY_SUPPORT_HISTORY_SYNC_RECEIVER_PRE_CHAT, - GROUP_JOIN_REQUEST_CAN_SEND_OPTIONAL_MESSAGE, - GROUP_JOIN_REQUEST_CAN_VIEW_OPTIONAL_MESSAGE, GROUP_JOIN_REQUEST_M2_BANNER_ON_CONVERSATION, GROUP_MAX_SUBJECT, GROUP_MEMBER_UPDATES_HIDE_IN_THREAD_ENABLED, @@ -13102,6 +14106,7 @@ pub mod web { GROUP_MEMBER_UPDATES_USERNAMES_DB_ENABLED, GROUP_MEMBER_UPDATES_USERNAMES_ENABLED, GROUP_MEMBER_UPDATES_USERNAMES_UI_ENABLED, + GROUP_SETTINGS_IA_PROTOTYPE, GROUP_SIZE_BYPASSING_SAMPLING, GROUP_SIZE_LIMIT, GROUP_STATUS_RECEIVER_ENABLED, @@ -13138,6 +14143,7 @@ pub mod web { HYBRID_NUX_BETA_50_ENABLED, IGNORE_JOINABLE_TERMINATE_ON_EXPIRED_OFFER, IGNORE_ONE_TO_ONE_TERMINATE_IN_GROUP_CALL, + IM_A2UI_REQUIRE_BOT_ATTRIBUTION, IM_BLOKS_WIDGET_ENABLE, IM_NFM_MULTI_STEP_FORM_KILLSWITCH, IMP_SEND_SIGNAL_POST_CONNECT_DELAY, @@ -13170,6 +14176,7 @@ pub mod web { INTERACTIVE_RESPONSE_MESSAGE_NATIVE_FLOW_KILLSWITCH, INTERNAL_GROUP_INDICATOR, INVITE_DEACTIVATED_USER_WEB, + IOS_REACTION_PICKER_WDS_HEADER_ENABLED, IS_AI_MODE_SELECTOR_VISIBLE, IS_EXPAND_FMX_ACCOUNT_AGE_BOLDED_NON_AUTO_EXPOSE, IS_EXPAND_FMX_ACCOUNT_AGE_UI_ENABLED, @@ -13194,14 +14201,13 @@ pub mod web { LAZY_SYSTEM_MESSAGE_INSERTION_ENABLED, LID_GROUP_CREATION_ADDRESSING_MODE_OVERRIDE, LID_GROUP_MIGRATION_NON_MEMBER_IQ, + LID_MIGRATION_DAILY_GROUP_COMPOSITION_ENABLED, LID_MIGRATION_FOR_BIZ_PROFILE_ENABLED, LID_MIGRATION_FOR_VNAME_ENABLED, LID_MIGRATION_NOTIFICATIONS_ENABLED, LID_ONE_ON_ONE_MIGRATION_COMPATIBLE, LID_ONE_ON_ONE_MIGRATION_ENABLED, - LID_ONE_ON_ONE_MIGRATION_LOG_OUT_ON_MISMATCH, LID_ONE_ON_ONE_MIGRATION_PEER_SYNC_TIMEOUT_IN_SECONDS, - LID_ONE_TO_ONE_MIGRATION_EVENT_RESPONSE_FORCE_PN_JID, LID_PN_USERNAME_MAPPING_LOGGING_ENABLED, LID_STATUS_NON_SOAKED_CLIENT_SUPPORT_ENABLED, LID_STATUS_SEND_ENABLED, @@ -13286,6 +14292,7 @@ pub mod web { MM_SIGNAL_SHARING_VERIFICATION_SYSTEM_LID_ENABLED, MM_TAP_TARGET_BLOKS_CLIENT_HYDRATION_ENABLED, MM_TEMPLATE_MESSAGE_TELEMETRY_IS_FIRST_MM_ENABLED, + MM_TEMPLATE_MESSAGE_TELEMETRY_STRICT_FIRST_MM_ENABLED, MM_USER_CONTROLS_ENTRY_POINTS_UPDATE_M1_ICON, MM_USER_CONTROLS_ENTRY_POINTS_UPDATE_M1_MENU, MM_USER_CONTROLS_EXCEPTION_NUMBER_PREFIXES, @@ -13313,7 +14320,6 @@ pub mod web { NEWSLETTER_NUX_NOTICE_ID, NEWSLETTER_RCAT_FIELD_GENERATING_ENABLED, NEWSLETTER_STATUS_CREATION_ENABLED, - NEWSLETTER_STATUS_RECEIVER_ENABLED, NEWSLETTER_TOS_NOTICE_ID, NEWSLETTER_TOS_NOTICE_ID_SMB_WEB, NEWSLETTERS_VIDEO_PLAYBACK_WABBA_LOGGING_ENABLED, @@ -13405,22 +14411,33 @@ pub mod web { PAYMENTS_BR_PIX_WEB_ATTACHMENT_TRAY, PAYMENTS_LINK_TO_LITE_CONSUMER_ENABLED, PAYMENTS_MERCHANT_GLOBAL_ORDERS_VALUE_PROPS_BANNER_ENABLED, + PAYMENTS_UPR_ARGENTINA_ENABLED, PAYMENTS_UPR_BUBBLE_COUNTRIES, + PAYMENTS_UPR_CANADA_ENABLED, + PAYMENTS_UPR_COLOMBIA_ENABLED, + PAYMENTS_UPR_COTE_DIVOIRE_ENABLED, PAYMENTS_UPR_CUSTOM_PAYMENT_METHODS_SYNC_COUNTRIES, PAYMENTS_UPR_EGYPT_ENABLED, + PAYMENTS_UPR_ETHIOPIA_ENABLED, + PAYMENTS_UPR_GHANA_ENABLED, PAYMENTS_UPR_HONGKONG_ENABLED, PAYMENTS_UPR_ID_ENABLED, PAYMENTS_UPR_MEXICO_WALLET_ENABLED, PAYMENTS_UPR_MULTIPLE_KEY_COPY_ENABLED, PAYMENTS_UPR_MX_ENABLED, + PAYMENTS_UPR_PERU_ENABLED, + PAYMENTS_UPR_SAUDI_ARABIA_ENABLED, PAYMENTS_UPR_SEND_KEY_FROM_WEB, + PAYMENTS_UPR_SOUTH_AFRICA_ENABLED, PAYMENTS_UPR_TAIWAN_ENABLED, + PAYMENTS_UPR_TANZANIA_ENABLED, PAYMENTS_UPR_TURKEY_ENABLED, PAYMENTS_UPR_UAE_ENABLED, PEER_MESSAGE_LID_MIGRATION_OUTGOING, PENDING_GROUP_REQUESTS_PERSISTENT_BANNER, PER_CUSTOMER_DATA_SHARING_CONTROLS_ELIGIBLE, PHONE_NUMBER_SHARING_FLOW, + PINNED_MESSAGE_BANNER_NOTCH_ANIMATION_ENABLED, PINNED_MESSAGES_INFINITE_RECEIVER_ENABLED, PINNED_MESSAGES_INFINITE_SENDER_ENABLED, PINNED_MESSAGES_M0, @@ -13432,6 +14449,7 @@ pub mod web { PINNED_MESSAGES_SENDER_SHORT_EXPIRY_DURATIONS_ENABLED, PIX_ONBOARDING_NEW_CONTENT_ENABLED, PIX_PAYMENT_REQUEST_UPDATE_STATUS_ENABLED, + PIX_PAYMENT_REQUEST_WEB_ENABLED, PLACEHOLDER_MESSAGE_KEY_HASH_LOGGING, PLACEHOLDER_MESSAGE_RESEND, PLACEHOLDER_MESSAGE_RESEND_MAXIMUM_DAYS_LIMIT, @@ -13456,9 +14474,12 @@ pub mod web { POLL_RESULT_SNAPSHOT_POLLTYPE_ENVELOPE_ENABLED, POLL_TC_RECEIVING_ENABLED, POLL_TC_SENDING_ENABLED, + PQ_1ON1_MESSAGE_ENABLED, + PQ_KEYS_UPLOAD, PREMIUM_BLUE_ENABLED, PREMIUM_BROADCAST_SMB_CAPPING_ENABLED, PREMIUM_MSG_BB_CAMPAIGN_SYNC_ENABLED, + PRIMARY_INITIATED_COMPANION_CONTACT_REFRESH, PRIVACY_SCREEN_ENABLED, PRIVACY_SETTINGS_ABOUT_LID_MIGRATION_ENABLE, PRIVACY_SETTINGS_GROUP_ADD_LID_MIGRATION_ENABLE, @@ -13484,12 +14505,10 @@ pub mod web { PUSHNAME_BLOCKLIST_STARTING_WITH_AT, QP_BANNER_STICKER_ANIMATION_ENABLED, QP_CAMPAIGN_CLIENT_ENABLED, - QUICK_PROMOTION_BANNER_CLIENT_ENABLED, QUOTED_MESSAGE_USER_JOURNEY_LOGGING_ENABLED, RASTERIZE_TEXT_STATUS_PIXEL_WIDTH, REACTION_USER_JOURNEY_LOGGING_ENABLED, REACTIONS_ALIGNMENT_FOR_TRANSPARENT_MESSAGES_ENABLED, - REACTIONS_CHAT_PREVIEW, REACTIONS_RECEIVER_ENABLED, RECEIPT_MODE_BITMASK_ENABLED, RECOMMENDED_CHANNELS_BACKGROUND_REFRESH, @@ -13502,6 +14521,8 @@ pub mod web { REPORT_TO_ADMIN_ENABLED, REPORT_TO_ADMIN_KILL_SWITCH, REUSE_CACHED_CERTS_FOR_DATA_CHANNEL, + REVEAL_USERNAME_NON_LINKING_REJECTION_REASON_ENABLED, + RICH_FORMAT_LOGGING_ENABLED, RICH_ORDER_STATUS_WA_WEB, RNR_DAYS_COOLDOWN, RNR_MIN_DAYS_USER_ACTIVE, @@ -13519,6 +14540,7 @@ pub mod web { RT_SWAPPED_FALLBACK_VALIDATION, RT_SYNC_REPORTING_TAG, RT_WEB_DELAY_PROCESSING, + RUST_ACCEL_WACALL_FOUNDATION_ENABLED, SAGA_COPY, SAGA_ENABLED, SAGA_MESSAGE_FEEDBACK_USING_CANONICAL_ENT, @@ -13545,7 +14567,6 @@ pub mod web { SELLER_ORDERS_MANAGEMENT_REVAMP, SEND_CAG_MEMBER_REVOKES_AS_GDM, SEND_EXTENDED_NACK_ENABLED, - SEND_INVALID_PROTOBUF_NACK_FAILURE_REASON, SERVER_DRIVEN_COPY_M2, SERVICE_IMPROVEMENT_OPT_OUT_FLAG, SETTINGS_SYNC_ENABLED, @@ -13557,7 +14578,9 @@ pub mod web { SHORTCAKE_COMPANION_PROLOGUE_PASSKEYS_ENABLED, SHORTCAKE_COMPANION_PROLOGUE_PASSKEYS_HANDOFF_ENABLED, SHORTCAKE_COMPANION_PROLOGUE_PASSKEYS_REQUEST_OPTIONS_TTL_SECONDS, + SHOW_FISHFOODING_TOGGLE_IN_BUG_REPORTING_FORM, SHOW_INTEGRITY_SCREENSHARING_FRICTION_UI, + SHOW_USERNAME_NON_LINKING_REJECTION_REASON_ENABLED, SILENT_GROUP_USERNAME_ACTIVITIES_ENABLED, SIMILAR_CHANNELS_IN_CHANNEL_DETAILS_ENABLED, SIMILAR_CHANNELS_IN_THREAD_ON_FOLLOW_ENABLED, @@ -13572,6 +14595,8 @@ pub mod web { SMB_AGENT_THREAD_CONTROL_NOTIFICATION_ENABLED, SMB_AI_AGENTS_WEB_CHAT_ASSIGNMENT_INTEROP_ENABLED, SMB_AUTH_AGENTS_FEATURE_CONTROL_ENABLED, + SMB_BB_IN_THREAD_INSIGHT_METRICS_ENABLED, + SMB_BB_PRO_BUSINESS_VERIFICATION, SMB_BB_WEB_AUDIENCE_EXPRESSION_SYNC_READ, SMB_BILLING_ENABLED, SMB_BIZ_AI_LISTS_PILLS, @@ -13579,6 +14604,7 @@ pub mod web { SMB_BUSINESS_BROADCAST_IMPORT_CONTACT, SMB_BUSINESS_BROADCAST_MULTI_AUDIENCE_SEND_WEB, SMB_BUSINESS_BROADCAST_PRO_ENABLED, + SMB_BUSINESS_BROADCAST_PRO_WEB_SCHEDULED_SENDS_ENABLED, SMB_BUSINESS_BROADCAST_SEND_WEB, SMB_BUSINESS_BROADCAST_SEND_WEB_NO_EXP, SMB_BUSINESS_BROADCAST_SEND_WEB_SMBA, @@ -13587,6 +14613,7 @@ pub mod web { SMB_CATALOG_GRAPHQL_VERIFY_POSTCODE, SMB_CATKIT_QUERY_VERSION, SMB_COLLECTIONS_ENABLED, + SMB_CONTACT_MANAGER_SUBLIST_ENABLED, SMB_CORE_BIZ_PROFILE_PREVIEW, SMB_CORE_BIZ_PROFILE_UX_REFRESHED, SMB_CORE_BIZ_PROFILE_UX_REFRESHED_V2, @@ -13614,7 +14641,6 @@ pub mod web { SMB_MULTI_DEVICE_AGENTS_LOGGING_V2_ENABLED, SMB_MULTI_DEVICE_MESSAGE_ATTRIBUTION_ENABLED, SMB_NOTES_CONTENT_MAX_LIMIT, - SMB_NOTES_V1_ENABLED, SMB_PAYMENT_LINKS_CTA_BUTTON_KILL_SWITCH, SMB_PAYMENT_LINKS_CTA_PSP_LIST, SMB_PAYMENT_LINKS_CTA_VARIANT, @@ -13641,6 +14667,7 @@ pub mod web { SMB_WEB_CUSTOMER_MANAGER_DATE_RANGE_FILTER_ENABLED, SMB_WEB_CUSTOMER_MANAGER_DOB_FILTER_ENABLED, SMB_WEB_CUSTOMER_MANAGER_EXPORT_ENABLED, + SMB_WEB_CUSTOMER_MANAGER_HEADER_MENU_ENABLED, SMB_WEB_ENABLE_FB_LINKING, SMB_WEB_SHOW_QUICK_REPLY_OPTION_IN_COMPOSER, SMBA_BB_GENAI_COMPOSER_MIN_WORDS, @@ -13655,7 +14682,6 @@ pub mod web { SMBI_PREMIUM_BROADCAST_MAX_RECIPIENT_LIMIT, SMBW_BUSINESS_BROADCAST_DUPLICATE_ENABLED, SMBW_BUSINESS_BROADCAST_SMART_COLUMN_DETECTION_ENABLED, - SMOOTHIE_PERFORMANCE_CSS_DOM, SMOOTHIE_PERFORMANCE_MSG_SEND, SMOOTHIE_PERFORMANCE_RESIZE_FOLLOWUP, SNAPL_NEWSLETTER_LOGGING_ENCRYPTED_RID_ENABLED, @@ -13664,6 +14690,8 @@ pub mod web { SOCCER_BALL_REACTION_FULL_ANIMATION_ENABLED, SOCCER_REACTION_IN_TRAY_ENABLED, STATUS_ALLOW_FORWARDING_TO_STATUS_ON_WEB, + STATUS_CHAIN_FROM_CL_MODE, + STATUS_CHAIN_FROM_MY_INTERACTION_LIMIT, STATUS_E2EE_RECV_OVER_STATUS_STANZA, STATUS_E2EE_SEND_OVER_STATUS_STANZA, STATUS_FUTURE_PROOFING, @@ -13678,12 +14706,14 @@ pub mod web { STATUS_REACTION_EMOJIS, STATUS_SAVE_TO_CAMERA_ROLL_ENABLED, STATUS_VIDEO_MAX_DURATION, + STATUS_VIEWER_ACTION_PSA_LINK_CLICK_LOGGING_ENABLED, STATUS_WEB_RANKING, STICKER_STORE_TESTING_ENABLED, STICKERS_EMOJI_TAGGING_ENABLED, STICKY_CHAT_PROFILE_PICTURE_ENABLED, SUGGESTED_AUDIENCES_WA_WEB, SUPPORT_CONTACT_FORM_USING_GRAPHQL, + SUPPORT_EMAIL_CONTACT_FORM_LOGGED_IN_ENABLED, SUPPORT_LIDS, SUPPORT_MESSAGE_FEEDBACK_ENABLED, SUPPORTS_KEEP_IN_CHAT_IN_CAG, @@ -13706,6 +14736,7 @@ pub mod web { TCTOKEN_DURATION_SENDER, TCTOKEN_NUM_BUCKETS, TCTOKEN_NUM_BUCKETS_SENDER, + TEAMLINK_ENABLED, TEXT_STATUS_TTL_SECONDS_ALLOWLIST, TEXT_USER_JOURNEY_LOGGING_WAM_ENABLED, TIMEOUT_MEX_CALL_EXPAND_FMX_TRUST_SIGNALS, @@ -13728,9 +14759,17 @@ pub mod web { UNIFIED_RESPONSE_MARKDOWN_LINKS_ENABLED, UNIFIED_SESSION_LOG_CALL_EVENT, UNIFY_END_CALL_EVENTS, + UNKNOWN_USER_PERSISTENCE_LOGGING_ENABLED, + UNKNOWN_USER_TARGET_RID_LOGGING, + UNKNOWN_USER_WAM_EMIT_COOLDOWN_SECS, + UNKNOWN_USER_WAM_MAX_EVENTS_PER_WINDOW, UPDATED_HARMFUL_DOCUMENT_DIALOG, UPDATES_PRIVACY_NOTICE_ROLLOUT_DATE, UPDATES_QUICK_PROMOTION_BANNER_ENABLED, + UPDATES_TAB_CHANNELS_HEADER_EXPLORE_ENTRY_POINT_VISIBILITY, + UPDATES_TAB_CHANNELS_SECTION_HEADER_VISIBILITY, + UPDATES_TAB_CHANNELS_SHOW_RECOMMENDATION_UNIT_ENABLED, + UPDATES_TAB_CHANNELS_SHOW_UNFOLLOWED_SEARCH_RESULTS_ENABLED, UPLOAD_DOCUMENT_THUMB_MMS_ENABLED, USE_CACHED_APP_SETTINGS_FROM_GLOBAL_CTX, USE_CUSTOM_SOCCER_BALL_FOR_REACTION_ENABLED, @@ -13749,13 +14788,15 @@ pub mod web { USERNAME_CONTACT_SYNCD_SUPPORT_ENABLE, USERNAME_CONTACT_UI_VCARD, USERNAME_CONTACT_USYNC_LID_BASED, - USERNAME_CREATION, USERNAME_CREATION_RESERVATION_PP_DISCLOSURE_ENABLED, USERNAME_ENABLED_ON_COMPANION, USERNAME_ENGAGEMENT_NETWORK_IMPACT_LOGGING, USERNAME_EXPOSED_LOGGING_ENABLED, USERNAME_GLOBAL_SEARCH_ENABLED, USERNAME_GROUP_MUTATION_ENABLED, + USERNAME_KEY_ENTRY_UI_V2, + USERNAME_KEY_MAX_LENGTH, + USERNAME_KEY_MIN_LENGTH, USERNAME_KEY_REDESIGN_ENABLED, USERNAME_KEY_UPSELL_MAX_CHARACTERS, USERNAME_KEY_UPSELL_MAX_NUMBERS, @@ -13765,9 +14806,12 @@ pub mod web { USERNAME_MEX_ACCOUNT_SYNC_ENABLED, USERNAME_MIN_LENGTH, USERNAME_NUMERIC_CODE_V4, + USERNAME_PREVENT_PN_POPULATE_NEW_CONTACT_CREATION, USERNAME_SEARCH, + USERNAME_SEARCH_WITHOUT_ATSIGN_ENABLED, USERNAME_SECURITY_CODE_GENERATION, USERNAME_SUGGESTIONS_ENABLED, + USERNAME_UNKNOWN_USER_LOGGING_ENABLED, UTILITY_ORDER_STATUS_LOGGING_ENABLED, UTILITY_ORDER_VIEW_MBS_ENABLED, UTILITY_PAYMENT_REMINDER_M1_ENABLED, @@ -13785,6 +14829,7 @@ pub mod web { VIEW_REPLIES_WITH_THREADID_ENABLED, VISIBLE_MESSAGE_DROP_PLACEHOLDER_ENABLED_INTERNAL_ONLY, VOICE_AI_CONVERSATION_STARTER_LATENCY_TRACKING, + VOICE_CALL_STRING_TEST, VOICE_CHAT_COMPANION_EXPERIENCE_VERSION, VOICEMAIL_NUDGE_DURATION_MS, VOIP_CALL_COORDINATOR_VERSION, @@ -13795,8 +14840,11 @@ pub mod web { WA_ASTERIA_META_AI_SETTINGS_TAB_ENTRYPOINT_ENABLED, WA_ASTERIA_ROLLOUT_ENABLED, WA_AUTH_AGENT_OFFBOARDING_ENABLED, + WA_BIZ_GAP_ENFORCEMENT_RULES_SYNC_TO_META_ENABLED_AC_LINKED_USER, + WA_BIZ_PAYMENT_TEMPLATE_CLICK_SIGNALS, WA_CAPPING_LOCAL_DATA_LOGIC_UPDATE, WA_CATALOG_GRAPHQL_USE_LID_ENABLED, + WA_COEX_BIZ_AI_CAPPING_ELIGIBLE, WA_CONSUMER_ENTRY_POINT_ENABLED, WA_CONSUMER_NOVA_ELIGIBILITY_SUBSCRIPTION_STATUS_CHECK_ENABLED, WA_CONSUMER_NOVA_ENTRY_POINT_SETTINGS_ENABLED, @@ -13823,6 +14871,11 @@ pub mod web { WA_META_ONE_LAUNCH_FREE_TRIAL_ENABLED, WA_META_ONE_ROLLOUT_ENABLED, WA_META_ONE_SUBSCRIPTION_NOTIFICATIONS_ENABLED, + WA_NATIVE_ADS_WEB_CREATION_DUMMY, + WA_NATIVE_ADS_WEB_CREATION_ROLLOUT, + WA_NATIVE_ADS_WEB_CREATION_ROLLOUT_NO_EXPOSURE, + WA_NATIVE_ADS_XPLAT_DRAFT_ADS_MS1A_DUMMY_ENABLED, + WA_NATIVE_ADS_XPLAT_DRAFT_ADS_MS1A_ENABLED, WA_NCT_TOKEN_HISTORY_SYNC_ENABLED, WA_NCT_TOKEN_SALT_CREATION_ENABLED, WA_NCT_TOKEN_SEND_ENABLED, @@ -13831,9 +14884,12 @@ pub mod web { WA_PAYMENTS_SMB_ENABLED, WA_PAYMENTS_SMB_LABELS_CONVENTION_ENABLED, WA_QP_EXPOSURE_LOG_VIA_GRAPHQL_ENABLED, + WA_SETTINGS_READ_RECEIPTS_COPY_V2, WA_SMB_BIZ_PROFILE_GOOGLE_INTEGRATION_ENABLED, WA_SMB_FORWARD_BB_WEB_ENABLED, WA_SMB_WEB_LISTS_QUICK_REPLIES_ENABLED, + WA_STATUS_CHAIN_NEW_AT_END, + WA_STATUS_CHAIN_UNSEEN_MIN_POG, WA_WEB_ADAPTIVE_LAYOUT_ENABLED, WA_WEB_AGM_SIGNUP_ENABLED, WA_WEB_ANR_PUSHNAME_CHECK_ENABLED, @@ -13841,6 +14897,7 @@ pub mod web { WA_WEB_ANYONE_CAN_LINK_M2_FLOOD_LIMIT, WA_WEB_APP_LOCK_UPSELL, WA_WEB_ATTACH_ICON_VARIANT, + WA_WEB_BACKGROUND_NOTIFICATIONS, WA_WEB_BASE_VIDEO_COMET_VIDEO_PLAYER_ENABLED, WA_WEB_BIZ_BROADCAST_COLLECTION_BASED_CAMPAIGNS_ENABLED, WA_WEB_BIZ_BROADCASTS_CATALOG_ATTACHMENT, @@ -13854,10 +14911,16 @@ pub mod web { WA_WEB_BOT_ORPHAN_LOGIC_ENABLED, WA_WEB_BOT_TOS_CHECK_REFINIEMENT, WA_WEB_BROADCAST_DISAPPEARING_MESSAGES_FIX, + WA_WEB_BUTTONS_RESPONSE_PROP_REMOVAL_KILLSWITCH, + WA_WEB_CALLING_CALLS_TAB_EMPTY_STATE_UPDATE_ENABLED, + WA_WEB_CALLING_CHAT_EMPTY_STATE_UPDATE_ENABLED, WA_WEB_CALLING_DEEP_LINK_ERROR, + WA_WEB_CALLING_SIDENAV_CALLS_TAB_NUX_ENABLED, + WA_WEB_CALLING_WHATS_NEW_MODAL_UPDATE_ENABLED, WA_WEB_CANONICAL_REG_RELOAD_ENABLED, WA_WEB_CANONICAL_WAM_FALCO_BUFFER_ENABLED, WA_WEB_CANONICAL_WAM_FALCO_BUFFER_SIZE, + WA_WEB_CHAINING_FROM_MY_STATUS, WA_WEB_CHANGE_LIST_WDS_SUBMENU, WA_WEB_CHANNELS_COMET_VIDEO_PLAYER_ENABLED_V2, WA_WEB_CHAT_OPEN_OPTIMIZATIONS, @@ -13865,11 +14928,13 @@ pub mod web { WA_WEB_CHAT_THEMES, WA_WEB_CHAT_THEMES_LOGGING, WA_WEB_CHAT_THEMES_SOLID_WALLPAPER_SYNC_ENCODE, + WA_WEB_CHAT_THEMES_STOCK_WALLPAPER_SYNC_ENCODE, WA_WEB_CHATLIST_RENDER_CHAT_OPEN, WA_WEB_CLEAR_SELECTED_CHATS_ENABLED, WA_WEB_COMET_VIDEO_PLAYER_SNAPL, WA_WEB_COMPOSER_HEIGHT_INCREASE_ENABLED, WA_WEB_CONSOLE_LOG_LEVEL, + WA_WEB_CONTACT_AND_CHAT_FUZZY_SEARCH_ASYNC_ENABLED, WA_WEB_CONTACT_AND_CHAT_FUZZY_SEARCH_DISTANCE_THRESHOLD, WA_WEB_CONTACT_AND_CHAT_FUZZY_SEARCH_ENABLED, WA_WEB_CONTACT_AND_CHAT_FUZZY_SEARCH_SIMILARITY_OPTIMIZATION_ENABLED, @@ -13880,6 +14945,7 @@ pub mod web { WA_WEB_CREATE_GROUP_IN_FILTER, WA_WEB_DEBUG_COLOR_CODE_RETRY_MESSAGES, WA_WEB_DEFAULT_PROFILE_PICS, + WA_WEB_DEFENSE_MODE_QUARANTINE_EXTRA_PN_CHECK, WA_WEB_DISABLE_PREFETCH_LOADABLES, WA_WEB_DISCUSS_PRIVATELY, WA_WEB_DOWNLOAD_MIMETYPE_CHECK_BLOCK_ENABLED, @@ -13917,6 +14983,7 @@ pub mod web { WA_WEB_HYBRID_SIMPLE_CHAT_CONVERSATION_CONTEXT_MENU_ENABLED, WA_WEB_IMAGINE_UR_ENABLED, WA_WEB_IMPORTANT_MSG_NOTIFICATION, + WA_WEB_INLINE_MESSAGE_EDIT, WA_WEB_INVITE_LINK_PAGE_ENHANCEMENTS, WA_WEB_JUMP_TO_CART, WA_WEB_LARGE_GROUP_PRESENCE_ENABLED, @@ -13926,6 +14993,7 @@ pub mod web { WA_WEB_LOADER_BUTTON_UIX_IMPROVEMENT, WA_WEB_MATCH_PRIMARY_ICONS, WA_WEB_ME_TAB, + WA_WEB_MEDIA_LOADER_BUTTON_UIX_IMPROVEMENT, WA_WEB_MEDIA_UPLOAD_RETRY_RETRIES_COUNT, WA_WEB_MENTION_SEARCH, WA_WEB_MULTI_PPL_TYPING_INDICATOR_FOR_CHATLIST_GROUPS_VARIANT, @@ -13955,6 +15023,8 @@ pub mod web { WA_WEB_SHOW_STATUS_RING_FOR_NO_UNREAD, WA_WEB_SMALL_GROUP_PRESENCE_ENABLED, WA_WEB_STARRED_MSGS_SEARCH, + WA_WEB_STATUS_CHAIN_FROM_CHATLIST, + WA_WEB_STATUS_CHAIN_NEW_AT_END, WA_WEB_STATUS_COMET_VIDEO_PLAYER_ENABLED, WA_WEB_STATUS_FIRST_UPLOAD_FIX_ENABLED, WA_WEB_STATUS_QUESTION_STICKER_REPLY_ENABLED, @@ -13974,6 +15044,7 @@ pub mod web { WA_WEB_WAM_FALCO_LOGGING_ENABLED, WA_WEB_WAM_FALCO_MODE, WA_WEB_WAM_FALCO_SHADOW_EVENT_IDS, + WA_WEB_WIN_HYBRID_PLUS_ENABLED, WA_WEB_XB_BUBBLE_ENABLED, WA_WEBTP_EDIT_PDF_IN_WHATSAPP_ENABLED, WA_WEBTP_PDF_RENDERER_MODE_NO_EXPOSURE, @@ -13987,6 +15058,7 @@ pub mod web { WA_WEBTP_USE_PDF_RENDERER, WA_WEBTP_USE_THUMBNAIL_RENDERER, WA_WIN_PDF_RENDERING_ENABLED, + WA_WIN_WEBTP_PDF_VIEWER_PRELOAD_ENABLED, WABAI_CONSENT_COOLDOWN, WABAI_CONSENT_REQUIRED, WABAI_MESSAGE_FEEDBACK_ENABLED, @@ -14036,7 +15108,6 @@ pub mod web { WAWEB_ENABLE_LEGACY_IMAGE_ZOOM, WAWEB_STATUS_CLOSE_FRIENDS_VIEWER_SIDE_ENABLED, WDS_RADIUS_AND_CASING, - WDS_WEB_ACTION_TILE_REFRESH, WDS_WEB_BADGE, WDS_WEB_CHIP, WDS_WEB_COMPOSER_TOOLBAR_V2, @@ -14080,6 +15151,8 @@ pub mod web { WEB_ATTACH_MENU_ADD_DRAWING_ENABLED, WEB_AUTODOWNLOAD_STICKERS, WEB_BACKGROUND_SYNC_V2, + WEB_BATCHED_STATUS_SENDING_ENABLED, + WEB_BATCHED_STATUS_SPLIT_TO_PARTS, WEB_BB_GENAI_COMPOSER_MIN_WORDS, WEB_BIZ_PROFILE_OPTIONS, WEB_BIZ_QUALITY_TELEMETRY_ENABLED, @@ -14107,7 +15180,9 @@ pub mod web { WEB_CALLING_ENABLE_ON_WINDOWS, WEB_CALLING_FULL_SCREEN_TOGGLE_ENABLED, WEB_CALLING_OFFLINE_RESUME_ORDERING, + WEB_CALLING_PAUSE_BG_DURING_CALL_MODE, WEB_CALLING_PERF_OPTIMIZATIONS_BITMASK, + WEB_CALLING_SMOOTH_CALL_LINK_LOBBY, WEB_CALLING_SPEAKER_STRIP_RESIZE_ENABLED, WEB_CALLS_TAB_EMPTY_STATE_BUTTONS, WEB_CATALOG_RECOVERY_FLOW_ENABLED, @@ -14116,6 +15191,7 @@ pub mod web { WEB_CHANNEL_VIDEO_SERVER_TRANSCODE_UPLOAD, WEB_CHAT_INFO_ACTION_BUTTONS_REFRESH, WEB_CHAT_THEME_DRAWER_TITLE, + WEB_CHATLIST_FTS_LISTENER_CLEANUP, WEB_CHATPSA_FORWARDING, WEB_CHATS_CONTENT_VISIBILITY, WEB_COEX_SIMPLE_SIGNAL_ENABLED, @@ -14131,6 +15207,7 @@ pub mod web { WEB_DATE_MARKER_CALENDAR_ENABLED, WEB_DEPRECATE_MMS4_HASH_BASED_DOWNLOAD, WEB_DESIGN_REFRESH, + WEB_DETACHED_DOM_UNMOUNT_CLEANUP, WEB_DEXIE_HOOKS_SUPPORT_ENABLED, WEB_DISABLE_COMPOSE_BOX_FOR_DEPRECATED_CHATS, WEB_DISABLE_LOGS_LOW_END_DEVICE, @@ -14138,6 +15215,8 @@ pub mod web { WEB_DISPLAY_LID_CONTACTS, WEB_DRAWER_DESCRIPTOR_ENABLED, WEB_E2E_BACKFILL_EXPIRE_TIME, + WEB_E2E_STATUS_LIKES_SENDING_ENABLED, + WEB_EMAIL_INVITES_GROUP_INFO, WEB_ENABLE_BIZ_CATALOG_VIEW_PS_LOGGING, WEB_ENABLE_CAMERA_CAPTURE_REFRESH, WEB_ENABLE_IMPROVED_BULK_MERGE, @@ -14154,6 +15233,8 @@ pub mod web { WEB_GROUP_HOVER_CARD_VARIANT, WEB_GROUP_PROFILE_EDITOR, WEB_GUEST_CALLING_REPRESENTATION_ENABLED, + WEB_GUEST_CALLING_WAITING_ROOM_ADMIN_XP_ENABLED, + WEB_GUEST_CALLING_WAITING_ROOM_APPROVAL_NOTE_ENABLED, WEB_HISTORY_SYNC_ALLOW_DUPLICATE_IN_BULK_ERROR, WEB_HISTORY_SYNC_WORKER_ENABLED, WEB_HYBRID_APPLY_LATEST_DB_SCHEMA_OPTIMIZATION_ENABLED, @@ -14168,9 +15249,11 @@ pub mod web { WEB_IP_TOKEN_ENABLED, WEB_JPEG_QUALITY, WEB_LARGER_LINK_PREVIEWS, + WEB_LINK_PREVIEW_DEBOUNCE_PERIOD_MS, WEB_LINK_PREVIEW_SYNC_ENABLED, WEB_LOG_CAPACITY_OVERRIDE, WEB_LOGOUT_UNMIGRATED_COMPANION, + WEB_LOOM_STUCK_TRACE_TIMEOUT_MS, WEB_LOW_END_DEVICE_LEVEL, WEB_MAC_BETA_UPSELL, WEB_MATERIAL_REFRESH, @@ -14179,9 +15262,12 @@ pub mod web { WEB_MEDIA_COMPUTE_IN_WORKER_ENABLED, WEB_MEDIA_ENCRYPT_UPLOAD_IN_WORKER_ENABLED, WEB_MEDIA_WORKER_SPLIT_ENABLED, + WEB_MEMLAB_FIXES, + WEB_MEMLAB_FIXES_2, WEB_MEMORY_REDUCTION, WEB_MENU_SHARE_GROUP, WEB_MESSAGE_CUSTOM_ARIA_LABEL, + WEB_MESSAGE_DROP_BULK_DB_OPERATION_FALLBACK_ENABLED, WEB_MESSAGE_LIST_A11Y_REDESIGN, WEB_MESSAGE_PLUGIN_FRONTEND_REGISTRATION_ENABLED, WEB_MESSAGE_PROCESSING_CACHE_SIZE, @@ -14211,6 +15297,7 @@ pub mod web { WEB_ORIGINAL_PHOTO_QUALITY_UPLOAD_ENABLED, WEB_OTP_COPY_CODE_DISABLED, WEB_PATHFINDER_LOGGING, + WEB_PAYMENT_NOTIFICATIONS_ACK_KICK_FIX_ENABLED, WEB_PDF_THUMBNAIL_SIZE_IN_BYTES, WEB_PENDING_MESSAGE_CACHE_ENABLED, WEB_PHONE_NUMBER_GLOBAL_SEARCH, @@ -14238,6 +15325,7 @@ pub mod web { WEB_RESUME_OPTIMIZED_READ_RECEIPT_SEND_INTERVAL, WEB_SCREEN_LOCK_MAX_RETRIES, WEB_SEARCH_RESULTS_TYPE_DATE_FILTERS, + WEB_SELF_ADV_DAILY_USE_LID, WEB_SEND_HID_FAILED_DECRYPT_IN_RECEIPTS_ENABLED, WEB_SEND_INVISIBLE_MSG_MAX_GROUP_SIZE, WEB_SEND_INVISIBLE_MSG_MIN_GROUP_SIZE, @@ -14246,11 +15334,13 @@ pub mod web { WEB_SHOW_TO_HIDE_ENABLED, WEB_SIGNAL_FUTURE_MESSAGES_MAX, WEB_SOCKET_PARALLEL_CONNECTION_ENABLED, + WEB_STATUS_BATCH_SIZE, WEB_STATUS_CROSSPOSTING_ENABLED, WEB_STATUS_LIKES_SEND_V2_ENABLED, - WEB_STATUS_PSA, WEB_STATUS_RANKING, WEB_STATUS_RANKING_ENABLED, + WEB_STATUS_RECV_VIA_SMAX, + WEB_STATUS_SEND_VIA_SMAX, WEB_STICKER_SUGGESTIONS_ENABLE, WEB_STICKY_HD_PHOTO_SETTING_ENABLED, WEB_STORE_QUOTA_MANAGER_ENABLED, @@ -14264,7 +15354,6 @@ pub mod web { WEB_TOP_LEVEL_MESSAGE_SECRET_ENFORCEMENT_ENABLED, WEB_UI_REFRESH_M1, WEB_USE_KALEIDOSCOPE_MEDIA_CHECK_ENABLED, - WEB_VIEW_MODE_USAGE_ENABLED, WEB_VOIP_ADAPTIVE_SCTP_PREWARM, WEB_VOIP_AUDIO_CAPTURE_IMPL, WEB_VOIP_AUDIO_PLAYBACK_IMPL, @@ -14273,7 +15362,11 @@ pub mod web { WEB_VOIP_DYNAMIC_THREAD_PREALLOCATE_COUNT, WEB_VOIP_LOAD_WASM_VARIANT, WEB_VOIP_LOW_RESOURCE_DEVICE, + WEB_VOIP_OUTGOING_CALL_SETUP_LATENCY_MODE, + WEB_VOIP_RUNTIME_STACK_SELECTION_ENABLED, WEB_VOIP_SCTP_WORKER_SAFARI_EXP, + WEB_VOIP_SKIP_OFFLINE_WAIT_ON_CALL_INTENT, + WEB_VOIP_USE_CONTENT_ADDRESSED_WASM, WEB_VOIP_VIDEO_CAPTURE_IMPL, WEB_VOIP_VIDEO_LOW_CAP_HEIGHT, WEB_VOIP_VIDEO_LOW_CAP_WIDTH, @@ -14283,6 +15376,7 @@ pub mod web { WEB_WAFFLE, WEB_WAM_MAX_BUFFER_UPLOAD_SIZE_BYTES, WEB_WHATS_NEW_AUTO_MODAL, + WEB_WHATS_NEW_AUTO_MODAL_CONTENT_VERSION, WEB_WHATS_NEW_AUTO_MODAL_SHORT_COOLDOWN, WEB_WHATS_NEW_BANNER, WEB_WHATS_NEW_BANNER_SHORT_COOLDOWN, @@ -14301,6 +15395,10 @@ pub mod web { WIN_HYBRID_BT_ENABLED, WIN_HYBRID_FORCE_PERSISTENT_STORAGE_PERMISSION, WIN_HYBRID_VOIP_ANR_OPTIMIZATIONS, + WIN_HYBRID_VSR_BUTTON_ENABLED, + WIN_HYBRID_VSR_BUTTON_ENABLED_2, + WIN_HYBRID_VSR_ENABLED, + WIN_HYBRID_VSR_ENABLED_2, WIN_NETWORK_STATE_WATCHDOG_INTERVAL, WINDOWS_CONTACTS_INITIAL_SYNC_DELAY, WINDOWS_CONTACTS_SYNC_INTERVAL, @@ -14309,6 +15407,7 @@ pub mod web { WINRT_RENDERER, WMI_ASYNC_AWAIT_PREP, WMI_JM_TO_TS_M1, + WMI_JM_TO_TS_SERVICED, WMI_TASK_SCHEDULER_SECOND_STEP, WMI_WORKER_SCHEDULER_WEB, XPLAT_ATTACHMENT_FORMAT_CHECK_V2, @@ -14424,6 +15523,2398 @@ pub mod group { ]; } +/// `WAWebHybridABPropsConfigs` — 339 flags. +pub mod hybrid { + use super::{AbDefault, AbProp, AbPropType}; + + pub const ADV_ACCEPT_HOSTED_DEVICES: AbProp = AbProp { + name: "adv_accept_hosted_devices", + code: 6939, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_3P_AGENT_MEDIA_SUPPORT_MODE: AbProp = AbProp { + name: "ai_3p_agent_media_support_mode", + code: 34393, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const AI_ASSET_REPLACEMENT_ENABLED: AbProp = AbProp { + name: "ai_asset_replacement_enabled", + code: 28265, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_BIZAI_2WAY_INTEGRATION_ENABLED: AbProp = AbProp { + name: "ai_bizai_2way_integration_enabled", + code: 26613, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_BIZAI_2WAY_INTEGRATION_HISTORY_SYNC_PRE_CHATD_ENABLED: AbProp = AbProp { + name: "ai_bizai_2way_integration_history_sync_pre_chatd_enabled", + code: 26614, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_BOT_INTEGRATION_BOT_PROFILE: AbProp = AbProp { + name: "ai_bot_integration_bot_profile", + code: 25268, + value_type: AbPropType::Str, + default: AbDefault::Str(""), + }; + pub const AI_BOT_INTEGRATION_ENABLED: AbProp = AbProp { + name: "ai_bot_integration_enabled", + code: 25119, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_BOT_INTEGRATION_HISTORY_SYNC_ENABLED: AbProp = AbProp { + name: "ai_bot_integration_history_sync_enabled", + code: 25269, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_BOT_INTEGRATION_HISTORY_SYNC_PRE_CHATD_ENABLED: AbProp = AbProp { + name: "ai_bot_integration_history_sync_pre_chatd_enabled", + code: 25469, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_CHAT_META_AI_BANNER_M2_ENABLED: AbProp = AbProp { + name: "ai_chat_meta_ai_banner_m2_enabled", + code: 18784, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_CHAT_META_AI_GLASSES_BANNER_ENABLED: AbProp = AbProp { + name: "ai_chat_meta_ai_glasses_banner_enabled", + code: 20405, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_GENAI_STRAW_HAT: AbProp = AbProp { + name: "ai_genai_straw_hat", + code: 28268, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_GIZMO_INTEGRATION_ENABLED: AbProp = AbProp { + name: "ai_gizmo_integration_enabled", + code: 28584, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_GROUP_CALL_ADD_IN_CALL_AHGC_ENABLED: AbProp = AbProp { + name: "ai_group_call_add_in_call_ahgc_enabled", + code: 24654, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_GROUP_CALL_ADD_IN_CALL_LGC_ENABLED: AbProp = AbProp { + name: "ai_group_call_add_in_call_lgc_enabled", + code: 31717, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_GROUP_CALL_MAX_VERSION_BY_COUNTRY: AbProp = AbProp { + name: "ai_group_call_max_version_by_country", + code: 24656, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const AI_GROUP_CALL_MAX_VERSION_BY_PLATFORM: AbProp = AbProp { + name: "ai_group_call_max_version_by_platform", + code: 24655, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const AI_GROUP_CALL_META_AI_ANIMATION_VERSION: AbProp = AbProp { + name: "ai_group_call_meta_ai_animation_version", + code: 32245, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const AI_GROUP_CALL_START_CALL_AHGC_ENABLED: AbProp = AbProp { + name: "ai_group_call_start_call_ahgc_enabled", + code: 31716, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_GROUP_CALL_START_CALL_LOGGING_ENABLED: AbProp = AbProp { + name: "ai_group_call_start_call_logging_enabled", + code: 32527, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_GROUP_CALL_START_CALL_NOTICE_ID: AbProp = AbProp { + name: "ai_group_call_start_call_notice_id", + code: 31736, + value_type: AbPropType::Str, + default: AbDefault::Str(""), + }; + pub const AI_GROUP_CALL_VERSION: AbProp = AbProp { + name: "ai_group_call_version", + code: 24652, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const AI_GROUPS_OPEN_ENABLED: AbProp = AbProp { + name: "ai_groups_open_enabled", + code: 22165, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_HATCH_INTEGRATION_BOT_PROFILE: AbProp = AbProp { + name: "ai_hatch_integration_bot_profile", + code: 26190, + value_type: AbPropType::Str, + default: AbDefault::Str(""), + }; + pub const AI_HATCH_INTEGRATION_ENABLED: AbProp = AbProp { + name: "ai_hatch_integration_enabled", + code: 26189, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_HATCH_INTEGRATION_HISTORY_SYNC_ENABLED: AbProp = AbProp { + name: "ai_hatch_integration_history_sync_enabled", + code: 26517, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_HATCH_INTEGRATION_HISTORY_SYNC_PRE_CHATD_ENABLED: AbProp = AbProp { + name: "ai_hatch_integration_history_sync_pre_chatd_enabled", + code: 26445, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_HATCH_INTEGRATION_TAB_ENABLED: AbProp = AbProp { + name: "ai_hatch_integration_tab_enabled", + code: 27356, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_MAIBA_WASS_MIGRATION_RECEIVING: AbProp = AbProp { + name: "ai_maiba_wass_migration_receiving", + code: 27083, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_MAIBA_WASS_MIGRATION_SENDING: AbProp = AbProp { + name: "ai_maiba_wass_migration_sending", + code: 27084, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_SEARCH_EXPERIENCE_ENABLED: AbProp = AbProp { + name: "ai_search_experience_enabled", + code: 8025, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_SEARCH_EXPERIENCE_WEB_ENABLED: AbProp = AbProp { + name: "ai_search_experience_web_enabled", + code: 18740, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_SEARCH_MAX_NUM_SUGGESTIONS: AbProp = AbProp { + name: "ai_search_max_num_suggestions", + code: 8076, + value_type: AbPropType::Int, + default: AbDefault::Int(5), + }; + pub const AI_SEARCH_META_AI_SEND_BUTTON_ENABLED: AbProp = AbProp { + name: "ai_search_meta_ai_send_button_enabled", + code: 20603, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const AI_SEARCH_NULL_STATE_CONVO_STARTER_SUGGESTIONS_UPDATE_INTERVAL: AbProp = AbProp { + name: "ai_search_null_state_convo_starter_suggestions_update_interval", + code: 17623, + value_type: AbPropType::Int, + default: AbDefault::Int(86400), + }; + pub const AI_SEARCH_NULL_STATE_ENABLED: AbProp = AbProp { + name: "ai_search_null_state_enabled", + code: 8026, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AI_SEARCH_NULL_STATE_ROW_COUNT: AbProp = AbProp { + name: "ai_search_null_state_row_count", + code: 8407, + value_type: AbPropType::Int, + default: AbDefault::Int(3), + }; + pub const AI_SEARCH_NULL_STATE_UPDATE_INTERVAL: AbProp = AbProp { + name: "ai_search_null_state_update_interval", + code: 8100, + value_type: AbPropType::Int, + default: AbDefault::Int(86400), + }; + pub const AI_SIMPLIFIED_PROFILE_PAGE_ENABLED: AbProp = AbProp { + name: "ai_simplified_profile_page_enabled", + code: 17104, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AIGC_VERSION: AbProp = AbProp { + name: "aigc_version", + code: 23692, + value_type: AbPropType::Int, + default: AbDefault::Int(1), + }; + pub const APP_EXIT_REASON_VERSION: AbProp = AbProp { + name: "app_exit_reason_version", + code: 8147, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const ATTACH_INVITEE_USER_PN_IN_OFFER: AbProp = AbProp { + name: "attach_invitee_user_pn_in_offer", + code: 34040, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ATTACH_TRANSPORT_RTX: AbProp = AbProp { + name: "attach_transport_rtx", + code: 16201, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AUDIO_LEVEL_SPEAKING_THRESHOLD: AbProp = AbProp { + name: "audio_level_speaking_threshold", + code: 1213, + value_type: AbPropType::Int, + default: AbDefault::Int(30), + }; + pub const AURA_STICKERS_BENEFIT_ACTIVE: AbProp = AbProp { + name: "aura_stickers_benefit_active", + code: 24801, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AURA_STICKERS_ENABLED: AbProp = AbProp { + name: "aura_stickers_enabled", + code: 24800, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AURA_STICKERS_OVERLAY_ANIMATION_ENABLED: AbProp = AbProp { + name: "aura_stickers_overlay_animation_enabled", + code: 25210, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const AURA_STICKERS_PREVIEW_MAX_ANIMATION_COUNT: AbProp = AbProp { + name: "aura_stickers_preview_max_animation_count", + code: 26602, + value_type: AbPropType::Int, + default: AbDefault::Int(5), + }; + pub const BUG_REPORTING_ABPROPS_UPLOADED_ON_SUBMISSOIN: AbProp = AbProp { + name: "bug_reporting_abprops_uploaded_on_submissoin", + code: 24850, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BUG_REPORTING_ASYNC_ATTACHMENTS_ENABLED: AbProp = AbProp { + name: "bug_reporting_async_attachments_enabled", + code: 23978, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BUG_REPORTING_ATTACH_PATHFINDER_PRE_BUG_CREATION: AbProp = AbProp { + name: "bug_reporting_attach_pathfinder_pre_bug_creation", + code: 26311, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const BUG_REPORTING_ATTACH_VIEW_DUMP_PRE_BUG_CREATION: AbProp = AbProp { + name: "bug_reporting_attach_view_dump_pre_bug_creation", + code: 26307, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const BUG_REPORTING_PRE_UPLOADED_ATTACHMENTS_ON_BUG_CREATION_ENABLED: AbProp = AbProp { + name: "bug_reporting_pre_uploaded_attachments_on_bug_creation_enabled", + code: 24422, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const BUG_REPORTING_RID_IN_FLYTRAP: AbProp = AbProp { + name: "bug_reporting_rid_in_flytrap", + code: 24421, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALL_INFO_OPTIMIZATIONS_1ON1: AbProp = AbProp { + name: "call_info_optimizations_1on1", + code: 31095, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALL_INFO_OPTIMIZATIONS_AHGC_CALL_LINK: AbProp = AbProp { + name: "call_info_optimizations_ahgc_call_link", + code: 31096, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALL_INFO_OPTIMIZATIONS_LGC: AbProp = AbProp { + name: "call_info_optimizations_lgc", + code: 31094, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALL_INFO_OPTIMIZATIONS_VERSION: AbProp = AbProp { + name: "call_info_optimizations_version", + code: 27483, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALL_OFFER_FAILED_SOFT_LANDING_SCREEN_VERSION: AbProp = AbProp { + name: "call_offer_failed_soft_landing_screen_version", + code: 10559, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALL_SCREEN_SHARE_DUAL_STREAM_APP_UPDATE_DIALOG_ENABLED: AbProp = AbProp { + name: "call_screen_share_dual_stream_app_update_dialog_enabled", + code: 31922, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const CALLEE_ACCEPT_TIMEOUT_MS: AbProp = AbProp { + name: "callee_accept_timeout_ms", + code: 6007, + value_type: AbPropType::Int, + default: AbDefault::Int(30000), + }; + pub const CALLING_32P_VERSION: AbProp = AbProp { + name: "calling_32p_version", + code: 7709, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_AUDIO_SHARE_VERSION: AbProp = AbProp { + name: "calling_audio_share_version", + code: 6598, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_AV_SYNC_WEBRTC: AbProp = AbProp { + name: "calling_av_sync_webrtc", + code: 24599, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_BATTERY_THRESHOLD_PCT: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_battery_threshold_pct", + code: 33552, + value_type: AbPropType::Int, + default: AbDefault::Int(15), + }; + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_ENABLED: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_enabled", + code: 32896, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_INCLUDE_LOW_DATA_USAGE: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_include_low_data_usage", + code: 33235, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_POOR_NETWORK_TIME_MS: AbProp = AbProp { + name: "calling_dual_stream_camera_auto_off_poor_network_time_ms", + code: 33548, + value_type: AbPropType::Int, + default: AbDefault::Int(5800), + }; + pub const CALLING_LID_VERSION: AbProp = AbProp { + name: "calling_lid_version", + code: 3358, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_RUST_MIGRATION_BITMAP: AbProp = AbProp { + name: "calling_rust_migration_bitmap", + code: 17954, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_RUST_MIGRATION_INCOMING_ACK_STANZA_BITMAP: AbProp = AbProp { + name: "calling_rust_migration_incoming_ack_stanza_bitmap", + code: 28434, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_RUST_MIGRATION_INCOMING_STANZA_BITMAP: AbProp = AbProp { + name: "calling_rust_migration_incoming_stanza_bitmap", + code: 26876, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_SCREEN_SHARE_MILESTONE_VERSION: AbProp = AbProp { + name: "calling_screen_share_milestone_version", + code: 30350, + value_type: AbPropType::Int, + default: AbDefault::Int(2), + }; + pub const CALLING_UX_LOGGING_BITMAP: AbProp = AbProp { + name: "calling_ux_logging_bitmap", + code: 8175, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_VOICEMAIL_ATTACHED_ICCE_ENABLED: AbProp = AbProp { + name: "calling_voicemail_attached_icce_enabled", + code: 30383, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CALLING_VOICEMAIL_QUOTED_REPLIES_ENABLED: AbProp = AbProp { + name: "calling_voicemail_quoted_replies_enabled", + code: 30165, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CALLS_TAB_USERNAME_GLOBAL_SEARCH_ENABLED: AbProp = AbProp { + name: "calls_tab_username_global_search_enabled", + code: 17698, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CAMERA_ERROR_BANNERS_VERSION: AbProp = AbProp { + name: "camera_error_banners_version", + code: 10584, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const CAMERA_HEALTH_CHECK_DELAY: AbProp = AbProp { + name: "camera_health_check_delay", + code: 8739, + value_type: AbPropType::Int, + default: AbDefault::Int(5000), + }; + pub const CAMERA_HEALTH_CHECK_PERIOD: AbProp = AbProp { + name: "camera_health_check_period", + code: 8740, + value_type: AbPropType::Int, + default: AbDefault::Int(2000), + }; + pub const CCI_COMPLIANCE_CTWA: AbProp = AbProp { + name: "cci_compliance_ctwa", + code: 24983, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CCI_COMPLIANCE_CTWA_LEARN_MORE_HYPERLINK: AbProp = AbProp { + name: "cci_compliance_ctwa_learn_more_hyperlink", + code: 25366, + value_type: AbPropType::Str, + default: AbDefault::Str("https://faq.whatsapp.com/785493319976156/"), + }; + pub const CCI_COMPLIANCE_MM: AbProp = AbProp { + name: "cci_compliance_mm", + code: 24853, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const COEX_CALLING_ENABLED: AbProp = AbProp { + name: "coex_calling_enabled", + code: 18047, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const COEX_CALLING_ENABLED_BUSINESS: AbProp = AbProp { + name: "coex_calling_enabled_business", + code: 23933, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const COEX_CALLING_PERMISSIONS_3P_ENABLED: AbProp = AbProp { + name: "coex_calling_permissions_3p_enabled", + code: 23464, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CROSS_DEVICE_MESSAGE_EDITING: AbProp = AbProp { + name: "cross_device_message_editing", + code: 28340, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CTWA_FIX_UNKNOWN_AGM_INSERTION_ISSUE_FOR_BUSINESSES: AbProp = AbProp { + name: "ctwa_fix_unknown_agm_insertion_issue_for_businesses", + code: 28964, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CTWA_TOS_FILTERING_ENABLED: AbProp = AbProp { + name: "ctwa_tos_filtering_enabled", + code: 976, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const CUSTOM_NOTIFICATION_TONES: AbProp = AbProp { + name: "custom_notification_tones", + code: 18884, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const DATA_SHARING_TRANSPARENCY_INDICATOR_DURATION: AbProp = AbProp { + name: "data_sharing_transparency_indicator_duration", + code: 5990, + value_type: AbPropType::Int, + default: AbDefault::Int(604800), + }; + pub const DAU_FIX_DELAY_PRESENCE_ON_FOCUS: AbProp = AbProp { + name: "dau_fix_delay_presence_on_focus", + code: 18189, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const DEFENSE_MODE_AVAILABLE: AbProp = AbProp { + name: "defense_mode_available", + code: 13874, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const DEFENSE_MODE_QUARANTINE: AbProp = AbProp { + name: "defense_mode_quarantine", + code: 24959, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const DEFENSE_MODE_QUARANTINE_BULK_UNBLOCK_LIMIT: AbProp = AbProp { + name: "defense_mode_quarantine_bulk_unblock_limit", + code: 21921, + value_type: AbPropType::Int, + default: AbDefault::Int(50), + }; + pub const DEFENSE_MODE_QUARANTINE_MESSAGE_EXPIRATION_WINDOW: AbProp = AbProp { + name: "defense_mode_quarantine_message_expiration_window", + code: 21918, + value_type: AbPropType::Int, + default: AbDefault::Int(1210000), + }; + pub const DEVICE_SWITCHING_ENABLED: AbProp = AbProp { + name: "device_switching_enabled", + code: 3205, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const DISABLE_LIBAOM_REGISTRATION: AbProp = AbProp { + name: "disable_libaom_registration", + code: 23836, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const DISABLE_RAISE_HAND_1ON1: AbProp = AbProp { + name: "disable_raise_hand_1on1", + code: 27177, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const DISCLOSURE_FOR_THE_MARKETING_MESSAGE_BODY_LINKS_ENABLED: AbProp = AbProp { + name: "disclosure_for_the_marketing_message_body_links_enabled", + code: 12994, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const EARLY_AUDIO_DRIVER_CAPTURE_AT_NATIVE: AbProp = AbProp { + name: "early_audio_driver_capture_at_native", + code: 13166, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const EARLY_AUDIO_DRIVER_PRE_BUFFERING: AbProp = AbProp { + name: "early_audio_driver_pre_buffering", + code: 13168, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const EARLY_BOT_CONNECT_EVENT_BITMAP: AbProp = AbProp { + name: "early_bot_connect_event_bitmap", + code: 14200, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const EDUCATIONAL_DIALOGS_BUTTON_ENABLED: AbProp = AbProp { + name: "educational_dialogs_button_enabled", + code: 14676, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_3P_CONTACTS_SHARE_HYBRID: AbProp = AbProp { + name: "enable_3p_contacts_share_hybrid", + code: 20849, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_AUDIO_DEVICE_ASYNC_START: AbProp = AbProp { + name: "enable_audio_device_async_start", + code: 13231, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_AUTO_ADD_CALL_LINK_CREATOR: AbProp = AbProp { + name: "enable_auto_add_call_link_creator", + code: 15184, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_AV_DOWNGRADE_1ON1: AbProp = AbProp { + name: "enable_av_downgrade_1on1", + code: 18165, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_AVATARS_ON_WEB_COMPANION: AbProp = AbProp { + name: "enable_avatars_on_web_companion", + code: 18081, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_CACHED_MEDIA_MANAGER: AbProp = AbProp { + name: "enable_cached_media_manager", + code: 4812, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const ENABLE_CALL_CONTROL_M5: AbProp = AbProp { + name: "enable_call_control_m5", + code: 8524, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_CALL_LINK_CALL_LOG_AGGREGATION: AbProp = AbProp { + name: "enable_call_link_call_log_aggregation", + code: 16523, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_CALL_LINKS_PUSH_NOTIFICATION: AbProp = AbProp { + name: "enable_call_links_push_notification", + code: 13679, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_CALL_RESULT_FIX_FOR_404_ACCEPT_NACK: AbProp = AbProp { + name: "enable_call_result_fix_for_404_accept_nack", + code: 10565, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_CALL_TRANSFER_NOTIFICATION: AbProp = AbProp { + name: "enable_call_transfer_notification", + code: 29242, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_CALLING_PHONE_NUMBER_PRIVACY: AbProp = AbProp { + name: "enable_calling_phone_number_privacy", + code: 17731, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_CALLING_USERNAME: AbProp = AbProp { + name: "enable_calling_username", + code: 13359, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_EARLY_AUDIO_DRIVER_START: AbProp = AbProp { + name: "enable_early_audio_driver_start", + code: 13807, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_FORCE_VOIP_LOGGING: AbProp = AbProp { + name: "enable_force_voip_logging", + code: 7300, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_GRID_LAYOUT_TILE_UNIFICATION: AbProp = AbProp { + name: "enable_grid_layout_tile_unification", + code: 18066, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_HYBRID_CALL_LINKS_CREATION: AbProp = AbProp { + name: "enable_hybrid_call_links_creation", + code: 15502, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const ENABLE_HYBRID_CALL_LINKS_JOIN: AbProp = AbProp { + name: "enable_hybrid_call_links_join", + code: 15501, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const ENABLE_HYBRID_OPEN_WITH_SHARED_BUFFER: AbProp = AbProp { + name: "enable_hybrid_open_with_shared_buffer", + code: 34175, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_HYBRID_VIDEO_TRANSCODING: AbProp = AbProp { + name: "enable_hybrid_video_transcoding", + code: 19895, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_HYBRID_VIDEO_TRANSCODING_FOR_VALID_MP4: AbProp = AbProp { + name: "enable_hybrid_video_transcoding_for_valid_mp4", + code: 20070, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_JOIN_ONGOING_CALL_REFACTOR: AbProp = AbProp { + name: "enable_join_ongoing_call_refactor", + code: 34093, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_LAZY_LOADING_OF_CALL_VIEW_ELEMENTS: AbProp = AbProp { + name: "enable_lazy_loading_of_call_view_elements", + code: 5053, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_LID_CALL_LINK: AbProp = AbProp { + name: "enable_lid_call_link", + code: 8180, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_NEW_CALL_LINK_REPRESENTATION: AbProp = AbProp { + name: "enable_new_call_link_representation", + code: 16589, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_NEW_ONGOING_CALL_CELL_UI: AbProp = AbProp { + name: "enable_new_ongoing_call_cell_ui", + code: 11426, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_OFFER_V2_UPGRADE: AbProp = AbProp { + name: "enable_offer_v2_upgrade", + code: 26435, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_POLL_RESULTS_CONTACT_INFO_ENTRY_POINT: AbProp = AbProp { + name: "enable_poll_results_contact_info_entry_point", + code: 33818, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_POLL_SETTINGS_LABEL_IMPROVED_LAYOUT: AbProp = AbProp { + name: "enable_poll_settings_label_improved_layout", + code: 32778, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_PRE_WARM_AUDIO_COMPONENT: AbProp = AbProp { + name: "enable_pre_warm_audio_component", + code: 15994, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_RATE_APP_PROMPT: AbProp = AbProp { + name: "enable_rate_app_prompt", + code: 19894, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_RING_FOR_GC_ON_OFFER_EXPIRE: AbProp = AbProp { + name: "enable_ring_for_gc_on_offer_expire", + code: 10103, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_SCHEDULE_CALL_FROM_CALLS_TAB: AbProp = AbProp { + name: "enable_schedule_call_from_calls_tab", + code: 15213, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_SETUP_ERROR_RESULT_CHECK: AbProp = AbProp { + name: "enable_setup_error_result_check", + code: 28689, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_SHARING_FILES_FROM_WEB_WINDOWS_HYBRID: AbProp = AbProp { + name: "enable_sharing_files_from_web_windows_hybrid", + code: 21184, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_SILENT_OFFER: AbProp = AbProp { + name: "enable_silent_offer", + code: 3235, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_TOOLTIP_FOR_MEDIA_HUB: AbProp = AbProp { + name: "enable_tooltip_for_media_hub", + code: 21535, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_TURN_ON_CALL_NOTIFICATION_REMINDERS: AbProp = AbProp { + name: "enable_turn_on_call_notification_reminders", + code: 5360, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_UGC_VOICE_FS_LOGGING: AbProp = AbProp { + name: "enable_ugc_voice_fs_logging", + code: 14641, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_UNIFIED_CALL_BUTTONS_IN_CHAT: AbProp = AbProp { + name: "enable_unified_call_buttons_in_chat", + code: 13497, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_UWP_DEVICE_SWITCH_BANNER: AbProp = AbProp { + name: "enable_uwp_device_switch_banner", + code: 10416, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_UWP_SCREEN_SHARE_TEACHING_TIP: AbProp = AbProp { + name: "enable_uwp_screen_share_teaching_tip", + code: 6264, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const ENABLE_UWP_SHARE_ANY_WINDOW: AbProp = AbProp { + name: "enable_uwp_share_any_window", + code: 4801, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_UWP_SWAP_VIDEO_STREAM: AbProp = AbProp { + name: "enable_uwp_swap_video_stream", + code: 10241, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const ENABLE_VIDEO_METRICS_FIX: AbProp = AbProp { + name: "enable_video_metrics_fix", + code: 20520, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WAITING_ROOM_ADMIN_UI: AbProp = AbProp { + name: "enable_waiting_room_admin_ui", + code: 21676, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WAITING_ROOM_LOGGING: AbProp = AbProp { + name: "enable_waiting_room_logging", + code: 24991, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WAITING_ROOM_UI: AbProp = AbProp { + name: "enable_waiting_room_ui", + code: 19819, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WEB_CALLING: AbProp = AbProp { + name: "enable_web_calling", + code: 15461, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WEBRTC_VIDEO_JB: AbProp = AbProp { + name: "enable_webrtc_video_jb", + code: 27591, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WINDOWS_HYBRID_JUMPLIST_CONTACTS: AbProp = AbProp { + name: "enable_windows_hybrid_jumplist_contacts", + code: 21057, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WINDOWS_JUMPLIST_HYBRID: AbProp = AbProp { + name: "enable_windows_jumplist_hybrid", + code: 20899, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WINDOWS_MOCKS_CAPTURE_DRIVERS: AbProp = AbProp { + name: "enable_windows_mocks_capture_drivers", + code: 31159, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WINDOWS_XDR_CHAT_HANDOFF: AbProp = AbProp { + name: "enable_windows_xdr_chat_handoff", + code: 24783, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const ENABLE_WINDOWS_XDR_WNS_PKEY: AbProp = AbProp { + name: "enable_windows_xdr_wns_pkey", + code: 32324, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GC_DEVICE_SWITCH_SHOW_ENTRY_POINT: AbProp = AbProp { + name: "gc_device_switch_show_entry_point", + code: 33281, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const GC_DEVICE_SWITCHING_KILLSWITCH: AbProp = AbProp { + name: "gc_device_switching_killswitch", + code: 26182, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GENAI_EARLY_AUDIO_PRE_BUF_SIZE: AbProp = AbProp { + name: "genai_early_audio_pre_buf_size", + code: 15306, + value_type: AbPropType::Int, + default: AbDefault::Int(100), + }; + pub const GIPHY_PMA_SHUTOFF_ENABLED: AbProp = AbProp { + name: "giphy_pma_shutoff_enabled", + code: 27942, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_CALL_MAX_PARTICIPANTS: AbProp = AbProp { + name: "group_call_max_participants", + code: 4190, + value_type: AbPropType::Int, + default: AbDefault::Int(32), + }; + pub const GROUP_CALLING_WAVE_RECEIVING_ENABLED: AbProp = AbProp { + name: "group_calling_wave_receiving_enabled", + code: 29161, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_CALLING_WAVE_SENDING_ENABLED: AbProp = AbProp { + name: "group_calling_wave_sending_enabled", + code: 29247, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_CREATE_ADD_USING_LID_JIDS: AbProp = AbProp { + name: "group_create_add_using_lid_jids", + code: 16192, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_AFTER_JOIN_PREREQUISITES: AbProp = AbProp { + name: "group_history_after_join_prerequisites", + code: 28787, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_BUNDLE_TIME_LIMIT_RECEIVER_ENFORCEMENT_SECS: AbProp = AbProp { + name: "group_history_bundle_time_limit_receiver_enforcement_secs", + code: 25910, + value_type: AbPropType::Int, + default: AbDefault::Int(1209600), + }; + pub const GROUP_HISTORY_MESSAGE_COUNT_LIMIT: AbProp = AbProp { + name: "group_history_message_count_limit", + code: 18405, + value_type: AbPropType::Int, + default: AbDefault::Int(100), + }; + pub const GROUP_HISTORY_MESSAGE_COUNT_RECEIVER_UPPER_LIMIT: AbProp = AbProp { + name: "group_history_message_count_receiver_upper_limit", + code: 19811, + value_type: AbPropType::Int, + default: AbDefault::Int(100), + }; + pub const GROUP_HISTORY_MESSAGES_TIME_LIMIT_RECEIVER_ENFORCEMENT_SECS: AbProp = AbProp { + name: "group_history_messages_time_limit_receiver_enforcement_secs", + code: 21313, + value_type: AbPropType::Int, + default: AbDefault::Int(1209600), + }; + pub const GROUP_HISTORY_NEW_USER_THRESHOLD_RECEIVER_ENFORCEMENT_SECS: AbProp = AbProp { + name: "group_history_new_user_threshold_receiver_enforcement_secs", + code: 30345, + value_type: AbPropType::Int, + default: AbDefault::Int(2592000), + }; + pub const GROUP_HISTORY_NEW_USER_THRESHOLD_SECS: AbProp = AbProp { + name: "group_history_new_user_threshold_secs", + code: 30333, + value_type: AbPropType::Int, + default: AbDefault::Int(2592000), + }; + pub const GROUP_HISTORY_NOTICE_RECEIVE: AbProp = AbProp { + name: "group_history_notice_receive", + code: 15722, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_OUT_OF_WINDOW_PIN_SENDER: AbProp = AbProp { + name: "group_history_out_of_window_pin_sender", + code: 26037, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_OUT_OF_WINDOW_PINS_RECEIVER: AbProp = AbProp { + name: "group_history_out_of_window_pins_receiver", + code: 26039, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_RECEIVE: AbProp = AbProp { + name: "group_history_receive", + code: 15311, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_RECEIVER_DEDUP: AbProp = AbProp { + name: "group_history_receiver_dedup", + code: 30462, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_RECEIVER_FLOATING_BANNER: AbProp = AbProp { + name: "group_history_receiver_floating_banner", + code: 21568, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_REPORTING: AbProp = AbProp { + name: "group_history_reporting", + code: 22329, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const GROUP_HISTORY_SEND: AbProp = AbProp { + name: "group_history_send", + code: 15313, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_SETTING_DECOUPLE_ENABLED: AbProp = AbProp { + name: "group_history_setting_decouple_enabled", + code: 29973, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_SETTINGS: AbProp = AbProp { + name: "group_history_settings", + code: 21261, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_SETTINGS_QUERY: AbProp = AbProp { + name: "group_history_settings_query", + code: 22230, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_SETTINGS_TOGGLE_UI: AbProp = AbProp { + name: "group_history_settings_toggle_ui", + code: 21481, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_HISTORY_SUPPORT_HISTORY_SYNC_RECEIVER_PRE_CHAT: AbProp = AbProp { + name: "group_history_support_history_sync_receiver_pre_chat", + code: 20658, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_MEMBER_UPDATES_HIDE_IN_THREAD_ENABLED: AbProp = AbProp { + name: "group_member_updates_hide_in_thread_enabled", + code: 24584, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_MEMBER_UPDATES_PAST_PARTICIPANT_MIGRATION_ENABLED: AbProp = AbProp { + name: "group_member_updates_past_participant_migration_enabled", + code: 31614, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_MEMBER_UPDATES_USERNAMES_DB_ENABLED: AbProp = AbProp { + name: "group_member_updates_usernames_db_enabled", + code: 24586, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_MEMBER_UPDATES_USERNAMES_ENABLED: AbProp = AbProp { + name: "group_member_updates_usernames_enabled", + code: 24617, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_MEMBER_UPDATES_USERNAMES_UI_ENABLED: AbProp = AbProp { + name: "group_member_updates_usernames_ui_enabled", + code: 24585, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const GROUP_USERNAME_UPDATES_AS_MEMBER_UPDATES_ENABLED: AbProp = AbProp { + name: "group_username_updates_as_member_updates_enabled", + code: 24477, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const HAND_RAISE_RECEIVER_ENABLED: AbProp = AbProp { + name: "hand_raise_receiver_enabled", + code: 13540, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const HEARTBEAT_INTERVAL_S: AbProp = AbProp { + name: "heartbeat_interval_s", + code: 1430, + value_type: AbPropType::Int, + default: AbDefault::Int(10), + }; + pub const HIDE_SILENT_SYSTEM_MESSAGE_ENABLED: AbProp = AbProp { + name: "hide_silent_system_message_enabled", + code: 24268, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const HSM_TAG_IN_HISTORY_SYNC_DESERIALIZATION_ENABLED: AbProp = AbProp { + name: "hsm_tag_in_history_sync_deserialization_enabled", + code: 25804, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const HYBRID_EDUCATIONAL_DIALOG_START_AT: AbProp = AbProp { + name: "hybrid_educational_dialog_start_at", + code: 14675, + value_type: AbPropType::Str, + default: AbDefault::Str(" "), + }; + pub const HYBRID_EDUCATIONAL_DIALOGS_ENABLED: AbProp = AbProp { + name: "hybrid_educational_dialogs_enabled", + code: 14674, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const IGNORE_JOINABLE_TERMINATE_ON_EXPIRED_OFFER: AbProp = AbProp { + name: "ignore_joinable_terminate_on_expired_offer", + code: 11519, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const IGNORE_ONE_TO_ONE_TERMINATE_IN_GROUP_CALL: AbProp = AbProp { + name: "ignore_one_to_one_terminate_in_group_call", + code: 10273, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const IN_APP_BUG_REPORTING_DESCRIPTION_GOOD_QUALITY_CHARS: AbProp = AbProp { + name: "in_app_bug_reporting_description_good_quality_chars", + code: 22361, + value_type: AbPropType::Int, + default: AbDefault::Int(50), + }; + pub const IN_APP_BUG_REPORTING_DESCRIPTION_MIN_CHARS: AbProp = AbProp { + name: "in_app_bug_reporting_description_min_chars", + code: 17295, + value_type: AbPropType::Int, + default: AbDefault::Int(10), + }; + pub const IN_APP_BUG_REPORTING_SHOW_QUALITY_HINTS_V1: AbProp = AbProp { + name: "in_app_bug_reporting_show_quality_hints_v1", + code: 22363, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const IS_META_EMPLOYEE_OR_INTERNAL_TESTER: AbProp = AbProp { + name: "is_meta_employee_or_internal_tester", + code: 1777, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const JOINABLE_CLIENT_POLL_INTERVAL_MIN: AbProp = AbProp { + name: "joinable_client_poll_interval_min", + code: 522, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const KALEIDOSCOPE_THUMBNAIL_VALIDATION: AbProp = AbProp { + name: "kaleidoscope_thumbnail_validation", + code: 18114, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const KS_USE_COMPONENT_MODEL: AbProp = AbProp { + name: "ks_use_component_model", + code: 26966, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const LOBBY_TIMEOUT_MIN: AbProp = AbProp { + name: "lobby_timeout_min", + code: 1565, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const MARK_AS_VERIFIED_ENABLED: AbProp = AbProp { + name: "mark_as_verified_enabled", + code: 29343, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MAX_GROUP_SIZE_FOR_LONG_RINGTONE: AbProp = AbProp { + name: "max_group_size_for_long_ringtone", + code: 4710, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const MAX_NUM_PARTICIPANTS_FOR_SS: AbProp = AbProp { + name: "max_num_participants_for_ss", + code: 3694, + value_type: AbPropType::Int, + default: AbDefault::Int(8), + }; + pub const MAX_NUMBER_OF_FREQUENTLY_USED_CONTACTS_SHARED_WITH_DEVICE: AbProp = AbProp { + name: "max_number_of_frequently_used_contacts_shared_with_device", + code: 10977, + value_type: AbPropType::Int, + default: AbDefault::Int(15), + }; + pub const MAX_NUMBER_OF_RECENT_CONTACTS_SHARED_WITH_DEVICE: AbProp = AbProp { + name: "max_number_of_recent_contacts_shared_with_device", + code: 10978, + value_type: AbPropType::Int, + default: AbDefault::Int(15), + }; + pub const MAY_HAVE_MESSAGES_ENABLED: AbProp = AbProp { + name: "may_have_messages_enabled", + code: 25303, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MC_ENABLED: AbProp = AbProp { + name: "mc_enabled", + code: 32843, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MEMBER_NAME_TAG_DB_ENABLED: AbProp = AbProp { + name: "member_name_tag_db_enabled", + code: 16551, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const MEMBER_NAME_TAG_RECEIVER_ENABLED: AbProp = AbProp { + name: "member_name_tag_receiver_enabled", + code: 13523, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MEMBER_NAME_TAG_SENDER_ENABLED: AbProp = AbProp { + name: "member_name_tag_sender_enabled", + code: 13524, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MESSAGE_CAPPING_UPSELL_VERSION: AbProp = AbProp { + name: "message_capping_upsell_version", + code: 19781, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const MM_1PD_POST_DC_DEPTH_LIMIT: AbProp = AbProp { + name: "mm_1pd_post_dc_depth_limit", + code: 26281, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const MM_1PD_POST_DC_NEW_SCHEMA_ENABLED: AbProp = AbProp { + name: "mm_1pd_post_dc_new_schema_enabled", + code: 26280, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_1PD_POST_DC_OLD_SCHEMA_DISABLED: AbProp = AbProp { + name: "mm_1pd_post_dc_old_schema_disabled", + code: 26282, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_DATA_SHARING_DISCLOSURE_ENABLED: AbProp = AbProp { + name: "mm_data_sharing_disclosure_enabled", + code: 5869, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_DATA_SHARING_DISCLOSURE_ENABLED_ADDITIONAL_TRANSPARENCY_LARGE_SCREENS: AbProp = + AbProp { + name: "mm_data_sharing_disclosure_enabled_additional_transparency_large_screens", + code: 25421, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_DATA_SHARING_DISCLOSURE_ENABLED_COMPANION_HISTORY_SYNC: AbProp = AbProp { + name: "mm_data_sharing_disclosure_enabled_companion_history_sync", + code: 21288, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_DISCLOSURE_HANDLE_TOS_FAILURES_ENABLED: AbProp = AbProp { + name: "mm_disclosure_handle_tos_failures_enabled", + code: 28572, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_DISCLOSURE_LEARN_MORE_ARTICLE_ID: AbProp = AbProp { + name: "mm_disclosure_learn_more_article_id", + code: 25021, + value_type: AbPropType::Str, + default: AbDefault::Str("263784176043634"), + }; + pub const MM_OPTIMIZED_DELIVERY_APP_CTA_ENABLED: AbProp = AbProp { + name: "mm_optimized_delivery_app_cta_enabled", + code: 22776, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_OPTIMIZED_DELIVERY_ARCHIVE_SIGNAL_SHARING_ENABLED: AbProp = AbProp { + name: "mm_optimized_delivery_archive_signal_sharing_enabled", + code: 28558, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_OPTIMIZED_DELIVERY_REPLACING_SHIMMED_LINKS_ENABLED: AbProp = AbProp { + name: "mm_optimized_delivery_replacing_shimmed_links_enabled", + code: 21782, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_OPTIMIZED_DELIVERY_TOKEN_FALLBACK_DISABLED: AbProp = AbProp { + name: "mm_optimized_delivery_token_fallback_disabled", + code: 29002, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const MM_OPTIMIZED_DELIVERY_UNIQUE_TOKEN_PER_MESSAGE_ID_ENABLED: AbProp = AbProp { + name: "mm_optimized_delivery_unique_token_per_message_id_enabled", + code: 29037, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const MM_SIGNAL_SHARING_COLLECTION_WINDOW_LOGGING_ENABLED: AbProp = AbProp { + name: "mm_signal_sharing_collection_window_logging_enabled", + code: 18126, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const MM_SIGNAL_SHARING_VERIFICATION_SYSTEM_LID_ENABLED: AbProp = AbProp { + name: "mm_signal_sharing_verification_system_lid_enabled", + code: 16727, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const MM_USER_CONTROLS_ENTRY_POINTS_UPDATE_M1_MENU: AbProp = AbProp { + name: "mm_user_controls_entry_points_update_m1_menu", + code: 20381, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const NEW_CHAT_MSG_CAPPING_FIRST_WARNING_THRESHOLD_PERCENTAGE: AbProp = AbProp { + name: "new_chat_msg_capping_first_warning_threshold_percentage", + code: 18967, + value_type: AbPropType::Int, + default: AbDefault::Int(50), + }; + pub const NOISE_PQ_MODE: AbProp = AbProp { + name: "noise_pq_mode", + code: 20161, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const OPTIMIZED_DELIVERY_BLOCK_AND_REPORT_ENTRY_POINTS_ALLOWLIST_WEB: AbProp = AbProp { + name: "optimized_delivery_block_and_report_entry_points_allowlist_web", + code: 18736, + value_type: AbPropType::Str, + default: AbDefault::Str("4,10,12,13,14,15,17,18,24,31,32,33,34,35,36,39,40,45"), + }; + pub const OPTIMIZED_DELIVERY_MULTIPLE_COLLECTION_WINDOWS_ENABLED: AbProp = AbProp { + name: "optimized_delivery_multiple_collection_windows_enabled", + code: 14588, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const OPTIMIZED_DELIVERY_SIGNAL_COLLECTION_CONFIG: AbProp = AbProp { + name: "optimized_delivery_signal_collection_config", + code: 10302, + value_type: AbPropType::Str, + default: AbDefault::Str("{}"), + }; + pub const OPTIMIZED_DELIVERY_SIGNAL_COLLECTION_ENABLED: AbProp = AbProp { + name: "optimized_delivery_signal_collection_enabled", + code: 9348, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const OPTIMIZED_DELIVERY_SIGNAL_COLLECTION_ON_COMPANIONS_ENABLED: AbProp = AbProp { + name: "optimized_delivery_signal_collection_on_companions_enabled", + code: 15884, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const OPTIMIZED_DELIVERY_TOKENS_STORAGE_CONFIG: AbProp = AbProp { + name: "optimized_delivery_tokens_storage_config", + code: 10303, + value_type: AbPropType::Str, + default: AbDefault::Str("{}"), + }; + pub const P2P_PILLS_ALLOWLIST: AbProp = AbProp { + name: "p2p_pills_allowlist", + code: 29554, + value_type: AbPropType::Str, + default: AbDefault::Str( + "[{ \"business_id\": \"34666845417\", \"pills\": [\"CHAT\", \"PROFILE\", \"BOOK_APPOINTMENT\", \"CATALOG\", \"BESTSELLERS\", \"OFFERS\", \"ABOUT_US\"] }]", + ), + }; + pub const P2P_PILLS_ALLOWLIST_ENTRIES: AbProp = AbProp { + name: "p2p_pills_allowlist_entries", + code: 29708, + value_type: AbPropType::Str, + default: AbDefault::Str( + "{ \"entries\": [{ \"business_id\": \"34666845417\", \"pills\": [\"CHAT\", \"PROFILE\", \"ABOUT_US\"] }]}", + ), + }; + pub const P2P_PILLS_AUTO_SEND_MESSAGES: AbProp = AbProp { + name: "p2p_pills_auto_send_messages", + code: 30208, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const P2P_PILLS_ENABLED: AbProp = AbProp { + name: "p2p_pills_enabled", + code: 27959, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const P2P_PILLS_ENABLED_FOR_INELIGIBLE_CONTACTS: AbProp = AbProp { + name: "p2p_pills_enabled_for_ineligible_contacts", + code: 29715, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const P2P_PILLS_ENTRIES: AbProp = AbProp { + name: "p2p_pills_entries", + code: 31469, + value_type: AbPropType::Str, + default: AbDefault::Str( + "{\"enabled_for\": {\"sender\": true,\"receiver\": true},\"enabled_on\": {\"contact_card\": true,\"p2p_link\": true,\"phone_number\": true,\"username\": true}}", + ), + }; + pub const P2P_PILLS_ENTRIES_ENABLED: AbProp = AbProp { + name: "p2p_pills_entries_enabled", + code: 31471, + value_type: AbPropType::Str, + default: AbDefault::Str( + "{\"enabled_for\": {\"sender\": true,\"receiver\": true},\"enabled_on\": {\"contact_card\": true,\"p2p_link\": true,\"phone_number\": true,\"username\": true}}", + ), + }; + pub const P2P_PILLS_GRAPHQL_ENABLED: AbProp = AbProp { + name: "p2p_pills_graphql_enabled", + code: 30629, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const P2P_PILLS_MAX_WAIT_ON_CONTACT_CARD_SEND: AbProp = AbProp { + name: "p2p_pills_max_wait_on_contact_card_send", + code: 30943, + value_type: AbPropType::Int, + default: AbDefault::Int(5), + }; + pub const P2P_PILLS_NEW_BUSINESS_METADATA_ENABLED: AbProp = AbProp { + name: "p2p_pills_new_business_metadata_enabled", + code: 30578, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_BR_P2M_PIX_COPY_CODE_BUYER_LOGGING: AbProp = AbProp { + name: "payments_br_p2m_pix_copy_code_buyer_logging", + code: 27028, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_BR_P2M_PIX_IN_GROUPS_BUYER_LOGGING: AbProp = AbProp { + name: "payments_br_p2m_pix_in_groups_buyer_logging", + code: 27029, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_BR_P2P_PIX_COPY_CODE_BUYER_LOGGING: AbProp = AbProp { + name: "payments_br_p2p_pix_copy_code_buyer_logging", + code: 27114, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_BR_PAYMENT_LINKS_BUYER_LOGGING: AbProp = AbProp { + name: "payments_br_payment_links_buyer_logging", + code: 27027, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PAYMENTS_BR_PIX_ON_WEB: AbProp = AbProp { + name: "payments_br_pix_on_web", + code: 16156, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PENDING_GROUP_REQUESTS_PERSISTENT_BANNER: AbProp = AbProp { + name: "pending_group_requests_persistent_banner", + code: 20545, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const POLL_ADD_OPTION_ENABLED: AbProp = AbProp { + name: "poll_add_option_enabled", + code: 24517, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const POLL_ADD_OPTION_RECEIVING_ENABLED: AbProp = AbProp { + name: "poll_add_option_receiving_enabled", + code: 25758, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const POLL_CREATOR_EDIT_ENABLED: AbProp = AbProp { + name: "poll_creator_edit_enabled", + code: 24887, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const POLL_CREATOR_EDIT_RECEIVING_VERSION: AbProp = AbProp { + name: "poll_creator_edit_receiving_version", + code: 24886, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const POLL_END_TIME_ENABLED: AbProp = AbProp { + name: "poll_end_time_enabled", + code: 24405, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const POLL_END_TIME_RECEIVING_ENABLED: AbProp = AbProp { + name: "poll_end_time_receiving_enabled", + code: 24884, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const POLL_HIDE_VOTERS_ENABLED: AbProp = AbProp { + name: "poll_hide_voters_enabled", + code: 24518, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const POLL_HIDE_VOTERS_RECEIVING_ENABLED: AbProp = AbProp { + name: "poll_hide_voters_receiving_enabled", + code: 24885, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const PREFER_LID_FOR_CHATD_LOGIN: AbProp = AbProp { + name: "prefer_lid_for_chatd_login", + code: 19191, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PRIVACY_SCREEN_ENABLED: AbProp = AbProp { + name: "privacy_screen_enabled", + code: 26820, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PRIVACY_SETTINGS_ABOUT_LID_MIGRATION_ENABLE: AbProp = AbProp { + name: "privacy_settings_about_lid_migration_enable", + code: 16195, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PRIVACY_SETTINGS_GROUP_ADD_LID_MIGRATION_ENABLE: AbProp = AbProp { + name: "privacy_settings_group_add_lid_migration_enable", + code: 16274, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PRIVACY_SETTINGS_PROFILE_LID_MIGRATION_ENABLE: AbProp = AbProp { + name: "privacy_settings_profile_lid_migration_enable", + code: 16161, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PRIVACY_SETTINGS_STICKERS_LID_MIGRATION_ENABLE: AbProp = AbProp { + name: "privacy_settings_stickers_lid_migration_enable", + code: 16338, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const PTV_QUOTED_REPLIES_CUTOUT_ENABLED: AbProp = AbProp { + name: "ptv_quoted_replies_cutout_enabled", + code: 30384, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const REACTIONS_RECEIVER_ENABLED: AbProp = AbProp { + name: "reactions_receiver_enabled", + code: 13542, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const REPORT_CALL_REPLAYER_ID: AbProp = AbProp { + name: "report_call_replayer_id", + code: 1834, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const REUSE_CACHED_CERTS_FOR_DATA_CHANNEL: AbProp = AbProp { + name: "reuse_cached_certs_for_data_channel", + code: 12913, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SAGA_MESSAGE_FEEDBACK_USING_CANONICAL_ENT: AbProp = AbProp { + name: "saga_message_feedback_using_canonical_ent", + code: 23328, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SECURITY_FIXES_BITMAP: AbProp = AbProp { + name: "security_fixes_bitmap", + code: 3094, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const SFU_SECONDARY_REMOTE_BWE_IMPL: AbProp = AbProp { + name: "sfu_secondary_remote_bwe_impl", + code: 11472, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const SHIMMED_LINKS_IN_THE_MARKETING_MESSAGE_BODY_ENABLED: AbProp = AbProp { + name: "shimmed_links_in_the_marketing_message_body_enabled", + code: 12995, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SHOW_INTEGRITY_SCREENSHARING_FRICTION_UI: AbProp = AbProp { + name: "show_integrity_screensharing_friction_ui", + code: 16411, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SHOW_INTEGRITY_SCREENSHARING_FRICTION_UI_LOGGING_ENABLED: AbProp = AbProp { + name: "show_integrity_screensharing_friction_ui_logging_enabled", + code: 17158, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SILENT_GROUP_USERNAME_ACTIVITIES_ENABLED: AbProp = AbProp { + name: "silent_group_username_activities_enabled", + code: 24269, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SMOOTHIE_PERFORMANCE_RESIZE_FOLLOWUP: AbProp = AbProp { + name: "smoothie_performance_resize_followup", + code: 18992, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const STICKERS_EMOJI_TAGGING_ENABLED: AbProp = AbProp { + name: "stickers_emoji_tagging_enabled", + code: 26465, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const SUPPORT_CONTACT_FORM_USING_GRAPHQL: AbProp = AbProp { + name: "support_contact_form_using_graphql", + code: 26001, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const UNIFIED_SESSION_LOG_CALL_EVENT: AbProp = AbProp { + name: "unified_session_log_call_event", + code: 8582, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const UNIFY_END_CALL_EVENTS: AbProp = AbProp { + name: "unify_end_call_events", + code: 2856, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const USE_CACHED_APP_SETTINGS_FROM_GLOBAL_CTX: AbProp = AbProp { + name: "use_cached_app_settings_from_global_ctx", + code: 13428, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const USERNAME_CONTACT_DISPLAY: AbProp = AbProp { + name: "username_contact_display", + code: 4746, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const USERNAME_ENABLED_ON_COMPANION: AbProp = AbProp { + name: "username_enabled_on_companion", + code: 23817, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const USERNAME_KEY_REDESIGN_ENABLED: AbProp = AbProp { + name: "username_key_redesign_enabled", + code: 29026, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const USERNAME_LID_MIGRATION_CALLING: AbProp = AbProp { + name: "username_lid_migration_calling", + code: 21890, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const USERNAME_MAX_LENGTH: AbProp = AbProp { + name: "username_max_length", + code: 20459, + value_type: AbPropType::Int, + default: AbDefault::Int(35), + }; + pub const USERNAME_MIN_LENGTH: AbProp = AbProp { + name: "username_min_length", + code: 20494, + value_type: AbPropType::Int, + default: AbDefault::Int(3), + }; + pub const USERNAME_SEARCH: AbProp = AbProp { + name: "username_search", + code: 15956, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const USERNAME_SUGGESTIONS_ENABLED: AbProp = AbProp { + name: "username_suggestions_enabled", + code: 21984, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const UWP_VOIP_INCOMING_CALL_NOTIFICATION_VERSION: AbProp = AbProp { + name: "uwp_voip_incoming_call_notification_version", + code: 7541, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const VID_PORT_ENABLE_CAPTURE_FPS_MEDIAN_FILTER: AbProp = AbProp { + name: "vid_port_enable_capture_fps_median_filter", + code: 29214, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const VID_PORT_FRM_BUF_MUTEX_FIXES: AbProp = AbProp { + name: "vid_port_frm_buf_mutex_fixes", + code: 22525, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const VOICE_AI_CONVERSATION_STARTER_LATENCY_TRACKING: AbProp = AbProp { + name: "voice_ai_conversation_starter_latency_tracking", + code: 19624, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const VOICE_CALL_STRING_TEST: AbProp = AbProp { + name: "voice_call_string_test", + code: 27841, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const VOICE_CHAT_COMPANION_EXPERIENCE_VERSION: AbProp = AbProp { + name: "voice_chat_companion_experience_version", + code: 17052, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const VOIP_CALL_COORDINATOR_VERSION: AbProp = AbProp { + name: "voip_call_coordinator_version", + code: 9502, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const VOIP_STACK_INCOMING_MESSAGE_OWNERSHIP_TRANSFER: AbProp = AbProp { + name: "voip_stack_incoming_message_ownership_transfer", + code: 16481, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_CALLING_BPN_SELF_PN_REMOVAL: AbProp = AbProp { + name: "wa_calling_bpn_self_pn_removal", + code: 32546, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_CAPPING_LOCAL_DATA_LOGIC_UPDATE: AbProp = AbProp { + name: "wa_capping_local_data_logic_update", + code: 21348, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_INDIVIDUAL_NEW_CHAT_MSG_CAPPING_ENABLED: AbProp = AbProp { + name: "wa_individual_new_chat_msg_capping_enabled", + code: 20865, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_INDIVIDUAL_NEW_CHAT_MSG_CAPPING_FETCH_TTL_SECONDS: AbProp = AbProp { + name: "wa_individual_new_chat_msg_capping_fetch_ttl_seconds", + code: 20649, + value_type: AbPropType::Int, + default: AbDefault::Int(3600), + }; + pub const WA_INDIVIDUAL_NEW_CHAT_MSG_CAPPING_MV_GET_SUBSCRIPTION_V2: AbProp = AbProp { + name: "wa_individual_new_chat_msg_capping_mv_get_subscription_v2", + code: 20667, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_INDIVIDUAL_NEW_CHAT_MSG_FCI_STALENESS_TTL_IN_SECONDS: AbProp = AbProp { + name: "wa_individual_new_chat_msg_fci_staleness_ttl_in_seconds", + code: 21410, + value_type: AbPropType::Int, + default: AbDefault::Int(120), + }; + pub const WA_INDIVIDUAL_NEW_CHAT_MSG_LATEST_RAMPUP_DATE: AbProp = AbProp { + name: "wa_individual_new_chat_msg_latest_rampup_date", + code: 20601, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const WA_INDIVIDUAL_NEW_CHAT_THREAD_CAPPING_LIMIT: AbProp = AbProp { + name: "wa_individual_new_chat_thread_capping_limit", + code: 29369, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const WA_WEB_ADAPTIVE_LAYOUT_ENABLED: AbProp = AbProp { + name: "wa_web_adaptive_layout_enabled", + code: 30140, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WA_WIN_PDF_RENDERING_ENABLED: AbProp = AbProp { + name: "wa_win_pdf_rendering_enabled", + code: 29548, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_ADD_CONTACT: AbProp = AbProp { + name: "web_add_contact", + code: 26892, + value_type: AbPropType::Str, + default: AbDefault::Str(""), + }; + pub const WEB_CHANNEL_VIDEO_SERVER_TRANSCODE_UPLOAD: AbProp = AbProp { + name: "web_channel_video_server_transcode_upload", + code: 19920, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_CHAT_INFO_ACTION_BUTTONS_REFRESH: AbProp = AbProp { + name: "web_chat_info_action_buttons_refresh", + code: 14664, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_GROUP_BULK_ADD_CONTACT: AbProp = AbProp { + name: "web_group_bulk_add_contact", + code: 30417, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_IP_TOKEN_ENABLED: AbProp = AbProp { + name: "web_ip_token_enabled", + code: 20043, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEB_WINDOWS_CALLING_32P_VERSION: AbProp = AbProp { + name: "web_windows_calling_32p_version", + code: 31845, + value_type: AbPropType::Int, + default: AbDefault::Int(3), + }; + pub const WEBVIEW2_DISABLE_GPU_ACCELERATION: AbProp = AbProp { + name: "webview2_disable_gpu_acceleration", + code: 18262, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WEBVIEW2_DISABLE_GPU_ACCELERATION_MEMORY_THRESHOLD_MB: AbProp = AbProp { + name: "webview2_disable_gpu_acceleration_memory_threshold_mb", + code: 23073, + value_type: AbPropType::Int, + default: AbDefault::Int(-1), + }; + pub const WEBVIEW2_ENABLE_OFFLINE_SUPPORT: AbProp = AbProp { + name: "webview2_enable_offline_support", + code: 21793, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_CALL_LOG_SEND_OUTGOING_SYNCD_MUTATIONS: AbProp = AbProp { + name: "win_call_log_send_outgoing_syncd_mutations", + code: 5308, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_ENABLE_SS_BUTTON_AUDIO: AbProp = AbProp { + name: "win_enable_ss_button_audio", + code: 9633, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_HYBRID_BT_ENABLED: AbProp = AbProp { + name: "win_hybrid_bt_enabled", + code: 30041, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_HYBRID_FORCE_PERSISTENT_STORAGE_PERMISSION: AbProp = AbProp { + name: "win_hybrid_force_persistent_storage_permission", + code: 20260, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + pub const WIN_HYBRID_VOIP_ANR_OPTIMIZATIONS: AbProp = AbProp { + name: "win_hybrid_voip_anr_optimizations", + code: 22616, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const WIN_HYBRID_VSR_BUTTON_ENABLED_2: AbProp = AbProp { + name: "win_hybrid_vsr_button_enabled_2", + code: 34279, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_HYBRID_VSR_ENABLED_2: AbProp = AbProp { + name: "win_hybrid_vsr_enabled_2", + code: 34280, + value_type: AbPropType::Bool, + default: AbDefault::Bool(false), + }; + pub const WIN_NETWORK_STATE_WATCHDOG_INTERVAL: AbProp = AbProp { + name: "win_network_state_watchdog_interval", + code: 7737, + value_type: AbPropType::Int, + default: AbDefault::Int(30), + }; + pub const WINDOWS_CONTACTS_INITIAL_SYNC_DELAY: AbProp = AbProp { + name: "windows_contacts_initial_sync_delay", + code: 24883, + value_type: AbPropType::Int, + default: AbDefault::Int(10), + }; + pub const WINDOWS_CONTACTS_SYNC_INTERVAL: AbProp = AbProp { + name: "windows_contacts_sync_interval", + code: 24882, + value_type: AbPropType::Int, + default: AbDefault::Int(60), + }; + pub const WINDOWS_GRACEFUL_DEGRADATION_VERSION: AbProp = AbProp { + name: "windows_graceful_degradation_version", + code: 8454, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const WINDOWS_SS_CAPTURE_DRIVER_TYPE: AbProp = AbProp { + name: "windows_ss_capture_driver_type", + code: 10434, + value_type: AbPropType::Int, + default: AbDefault::Int(0), + }; + pub const WINRT_RENDERER: AbProp = AbProp { + name: "winrt_renderer", + code: 10966, + value_type: AbPropType::Bool, + default: AbDefault::Bool(true), + }; + + /// All 339 flags in this registry, sorted by name. + pub const ALL: &[AbProp] = &[ + ADV_ACCEPT_HOSTED_DEVICES, + AI_3P_AGENT_MEDIA_SUPPORT_MODE, + AI_ASSET_REPLACEMENT_ENABLED, + AI_BIZAI_2WAY_INTEGRATION_ENABLED, + AI_BIZAI_2WAY_INTEGRATION_HISTORY_SYNC_PRE_CHATD_ENABLED, + AI_BOT_INTEGRATION_BOT_PROFILE, + AI_BOT_INTEGRATION_ENABLED, + AI_BOT_INTEGRATION_HISTORY_SYNC_ENABLED, + AI_BOT_INTEGRATION_HISTORY_SYNC_PRE_CHATD_ENABLED, + AI_CHAT_META_AI_BANNER_M2_ENABLED, + AI_CHAT_META_AI_GLASSES_BANNER_ENABLED, + AI_GENAI_STRAW_HAT, + AI_GIZMO_INTEGRATION_ENABLED, + AI_GROUP_CALL_ADD_IN_CALL_AHGC_ENABLED, + AI_GROUP_CALL_ADD_IN_CALL_LGC_ENABLED, + AI_GROUP_CALL_MAX_VERSION_BY_COUNTRY, + AI_GROUP_CALL_MAX_VERSION_BY_PLATFORM, + AI_GROUP_CALL_META_AI_ANIMATION_VERSION, + AI_GROUP_CALL_START_CALL_AHGC_ENABLED, + AI_GROUP_CALL_START_CALL_LOGGING_ENABLED, + AI_GROUP_CALL_START_CALL_NOTICE_ID, + AI_GROUP_CALL_VERSION, + AI_GROUPS_OPEN_ENABLED, + AI_HATCH_INTEGRATION_BOT_PROFILE, + AI_HATCH_INTEGRATION_ENABLED, + AI_HATCH_INTEGRATION_HISTORY_SYNC_ENABLED, + AI_HATCH_INTEGRATION_HISTORY_SYNC_PRE_CHATD_ENABLED, + AI_HATCH_INTEGRATION_TAB_ENABLED, + AI_MAIBA_WASS_MIGRATION_RECEIVING, + AI_MAIBA_WASS_MIGRATION_SENDING, + AI_SEARCH_EXPERIENCE_ENABLED, + AI_SEARCH_EXPERIENCE_WEB_ENABLED, + AI_SEARCH_MAX_NUM_SUGGESTIONS, + AI_SEARCH_META_AI_SEND_BUTTON_ENABLED, + AI_SEARCH_NULL_STATE_CONVO_STARTER_SUGGESTIONS_UPDATE_INTERVAL, + AI_SEARCH_NULL_STATE_ENABLED, + AI_SEARCH_NULL_STATE_ROW_COUNT, + AI_SEARCH_NULL_STATE_UPDATE_INTERVAL, + AI_SIMPLIFIED_PROFILE_PAGE_ENABLED, + AIGC_VERSION, + APP_EXIT_REASON_VERSION, + ATTACH_INVITEE_USER_PN_IN_OFFER, + ATTACH_TRANSPORT_RTX, + AUDIO_LEVEL_SPEAKING_THRESHOLD, + AURA_STICKERS_BENEFIT_ACTIVE, + AURA_STICKERS_ENABLED, + AURA_STICKERS_OVERLAY_ANIMATION_ENABLED, + AURA_STICKERS_PREVIEW_MAX_ANIMATION_COUNT, + BUG_REPORTING_ABPROPS_UPLOADED_ON_SUBMISSOIN, + BUG_REPORTING_ASYNC_ATTACHMENTS_ENABLED, + BUG_REPORTING_ATTACH_PATHFINDER_PRE_BUG_CREATION, + BUG_REPORTING_ATTACH_VIEW_DUMP_PRE_BUG_CREATION, + BUG_REPORTING_PRE_UPLOADED_ATTACHMENTS_ON_BUG_CREATION_ENABLED, + BUG_REPORTING_RID_IN_FLYTRAP, + CALL_INFO_OPTIMIZATIONS_1ON1, + CALL_INFO_OPTIMIZATIONS_AHGC_CALL_LINK, + CALL_INFO_OPTIMIZATIONS_LGC, + CALL_INFO_OPTIMIZATIONS_VERSION, + CALL_OFFER_FAILED_SOFT_LANDING_SCREEN_VERSION, + CALL_SCREEN_SHARE_DUAL_STREAM_APP_UPDATE_DIALOG_ENABLED, + CALLEE_ACCEPT_TIMEOUT_MS, + CALLING_32P_VERSION, + CALLING_AUDIO_SHARE_VERSION, + CALLING_AV_SYNC_WEBRTC, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_BATTERY_THRESHOLD_PCT, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_ENABLED, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_INCLUDE_LOW_DATA_USAGE, + CALLING_DUAL_STREAM_CAMERA_AUTO_OFF_POOR_NETWORK_TIME_MS, + CALLING_LID_VERSION, + CALLING_RUST_MIGRATION_BITMAP, + CALLING_RUST_MIGRATION_INCOMING_ACK_STANZA_BITMAP, + CALLING_RUST_MIGRATION_INCOMING_STANZA_BITMAP, + CALLING_SCREEN_SHARE_MILESTONE_VERSION, + CALLING_UX_LOGGING_BITMAP, + CALLING_VOICEMAIL_ATTACHED_ICCE_ENABLED, + CALLING_VOICEMAIL_QUOTED_REPLIES_ENABLED, + CALLS_TAB_USERNAME_GLOBAL_SEARCH_ENABLED, + CAMERA_ERROR_BANNERS_VERSION, + CAMERA_HEALTH_CHECK_DELAY, + CAMERA_HEALTH_CHECK_PERIOD, + CCI_COMPLIANCE_CTWA, + CCI_COMPLIANCE_CTWA_LEARN_MORE_HYPERLINK, + CCI_COMPLIANCE_MM, + COEX_CALLING_ENABLED, + COEX_CALLING_ENABLED_BUSINESS, + COEX_CALLING_PERMISSIONS_3P_ENABLED, + CROSS_DEVICE_MESSAGE_EDITING, + CTWA_FIX_UNKNOWN_AGM_INSERTION_ISSUE_FOR_BUSINESSES, + CTWA_TOS_FILTERING_ENABLED, + CUSTOM_NOTIFICATION_TONES, + DATA_SHARING_TRANSPARENCY_INDICATOR_DURATION, + DAU_FIX_DELAY_PRESENCE_ON_FOCUS, + DEFENSE_MODE_AVAILABLE, + DEFENSE_MODE_QUARANTINE, + DEFENSE_MODE_QUARANTINE_BULK_UNBLOCK_LIMIT, + DEFENSE_MODE_QUARANTINE_MESSAGE_EXPIRATION_WINDOW, + DEVICE_SWITCHING_ENABLED, + DISABLE_LIBAOM_REGISTRATION, + DISABLE_RAISE_HAND_1ON1, + DISCLOSURE_FOR_THE_MARKETING_MESSAGE_BODY_LINKS_ENABLED, + EARLY_AUDIO_DRIVER_CAPTURE_AT_NATIVE, + EARLY_AUDIO_DRIVER_PRE_BUFFERING, + EARLY_BOT_CONNECT_EVENT_BITMAP, + EDUCATIONAL_DIALOGS_BUTTON_ENABLED, + ENABLE_3P_CONTACTS_SHARE_HYBRID, + ENABLE_AUDIO_DEVICE_ASYNC_START, + ENABLE_AUTO_ADD_CALL_LINK_CREATOR, + ENABLE_AV_DOWNGRADE_1ON1, + ENABLE_AVATARS_ON_WEB_COMPANION, + ENABLE_CACHED_MEDIA_MANAGER, + ENABLE_CALL_CONTROL_M5, + ENABLE_CALL_LINK_CALL_LOG_AGGREGATION, + ENABLE_CALL_LINKS_PUSH_NOTIFICATION, + ENABLE_CALL_RESULT_FIX_FOR_404_ACCEPT_NACK, + ENABLE_CALL_TRANSFER_NOTIFICATION, + ENABLE_CALLING_PHONE_NUMBER_PRIVACY, + ENABLE_CALLING_USERNAME, + ENABLE_EARLY_AUDIO_DRIVER_START, + ENABLE_FORCE_VOIP_LOGGING, + ENABLE_GRID_LAYOUT_TILE_UNIFICATION, + ENABLE_HYBRID_CALL_LINKS_CREATION, + ENABLE_HYBRID_CALL_LINKS_JOIN, + ENABLE_HYBRID_OPEN_WITH_SHARED_BUFFER, + ENABLE_HYBRID_VIDEO_TRANSCODING, + ENABLE_HYBRID_VIDEO_TRANSCODING_FOR_VALID_MP4, + ENABLE_JOIN_ONGOING_CALL_REFACTOR, + ENABLE_LAZY_LOADING_OF_CALL_VIEW_ELEMENTS, + ENABLE_LID_CALL_LINK, + ENABLE_NEW_CALL_LINK_REPRESENTATION, + ENABLE_NEW_ONGOING_CALL_CELL_UI, + ENABLE_OFFER_V2_UPGRADE, + ENABLE_POLL_RESULTS_CONTACT_INFO_ENTRY_POINT, + ENABLE_POLL_SETTINGS_LABEL_IMPROVED_LAYOUT, + ENABLE_PRE_WARM_AUDIO_COMPONENT, + ENABLE_RATE_APP_PROMPT, + ENABLE_RING_FOR_GC_ON_OFFER_EXPIRE, + ENABLE_SCHEDULE_CALL_FROM_CALLS_TAB, + ENABLE_SETUP_ERROR_RESULT_CHECK, + ENABLE_SHARING_FILES_FROM_WEB_WINDOWS_HYBRID, + ENABLE_SILENT_OFFER, + ENABLE_TOOLTIP_FOR_MEDIA_HUB, + ENABLE_TURN_ON_CALL_NOTIFICATION_REMINDERS, + ENABLE_UGC_VOICE_FS_LOGGING, + ENABLE_UNIFIED_CALL_BUTTONS_IN_CHAT, + ENABLE_UWP_DEVICE_SWITCH_BANNER, + ENABLE_UWP_SCREEN_SHARE_TEACHING_TIP, + ENABLE_UWP_SHARE_ANY_WINDOW, + ENABLE_UWP_SWAP_VIDEO_STREAM, + ENABLE_VIDEO_METRICS_FIX, + ENABLE_WAITING_ROOM_ADMIN_UI, + ENABLE_WAITING_ROOM_LOGGING, + ENABLE_WAITING_ROOM_UI, + ENABLE_WEB_CALLING, + ENABLE_WEBRTC_VIDEO_JB, + ENABLE_WINDOWS_HYBRID_JUMPLIST_CONTACTS, + ENABLE_WINDOWS_JUMPLIST_HYBRID, + ENABLE_WINDOWS_MOCKS_CAPTURE_DRIVERS, + ENABLE_WINDOWS_XDR_CHAT_HANDOFF, + ENABLE_WINDOWS_XDR_WNS_PKEY, + GC_DEVICE_SWITCH_SHOW_ENTRY_POINT, + GC_DEVICE_SWITCHING_KILLSWITCH, + GENAI_EARLY_AUDIO_PRE_BUF_SIZE, + GIPHY_PMA_SHUTOFF_ENABLED, + GROUP_CALL_MAX_PARTICIPANTS, + GROUP_CALLING_WAVE_RECEIVING_ENABLED, + GROUP_CALLING_WAVE_SENDING_ENABLED, + GROUP_CREATE_ADD_USING_LID_JIDS, + GROUP_HISTORY_AFTER_JOIN_PREREQUISITES, + GROUP_HISTORY_BUNDLE_TIME_LIMIT_RECEIVER_ENFORCEMENT_SECS, + GROUP_HISTORY_MESSAGE_COUNT_LIMIT, + GROUP_HISTORY_MESSAGE_COUNT_RECEIVER_UPPER_LIMIT, + GROUP_HISTORY_MESSAGES_TIME_LIMIT_RECEIVER_ENFORCEMENT_SECS, + GROUP_HISTORY_NEW_USER_THRESHOLD_RECEIVER_ENFORCEMENT_SECS, + GROUP_HISTORY_NEW_USER_THRESHOLD_SECS, + GROUP_HISTORY_NOTICE_RECEIVE, + GROUP_HISTORY_OUT_OF_WINDOW_PIN_SENDER, + GROUP_HISTORY_OUT_OF_WINDOW_PINS_RECEIVER, + GROUP_HISTORY_RECEIVE, + GROUP_HISTORY_RECEIVER_DEDUP, + GROUP_HISTORY_RECEIVER_FLOATING_BANNER, + GROUP_HISTORY_REPORTING, + GROUP_HISTORY_SEND, + GROUP_HISTORY_SETTING_DECOUPLE_ENABLED, + GROUP_HISTORY_SETTINGS, + GROUP_HISTORY_SETTINGS_QUERY, + GROUP_HISTORY_SETTINGS_TOGGLE_UI, + GROUP_HISTORY_SUPPORT_HISTORY_SYNC_RECEIVER_PRE_CHAT, + GROUP_MEMBER_UPDATES_HIDE_IN_THREAD_ENABLED, + GROUP_MEMBER_UPDATES_PAST_PARTICIPANT_MIGRATION_ENABLED, + GROUP_MEMBER_UPDATES_USERNAMES_DB_ENABLED, + GROUP_MEMBER_UPDATES_USERNAMES_ENABLED, + GROUP_MEMBER_UPDATES_USERNAMES_UI_ENABLED, + GROUP_USERNAME_UPDATES_AS_MEMBER_UPDATES_ENABLED, + HAND_RAISE_RECEIVER_ENABLED, + HEARTBEAT_INTERVAL_S, + HIDE_SILENT_SYSTEM_MESSAGE_ENABLED, + HSM_TAG_IN_HISTORY_SYNC_DESERIALIZATION_ENABLED, + HYBRID_EDUCATIONAL_DIALOG_START_AT, + HYBRID_EDUCATIONAL_DIALOGS_ENABLED, + IGNORE_JOINABLE_TERMINATE_ON_EXPIRED_OFFER, + IGNORE_ONE_TO_ONE_TERMINATE_IN_GROUP_CALL, + IN_APP_BUG_REPORTING_DESCRIPTION_GOOD_QUALITY_CHARS, + IN_APP_BUG_REPORTING_DESCRIPTION_MIN_CHARS, + IN_APP_BUG_REPORTING_SHOW_QUALITY_HINTS_V1, + IS_META_EMPLOYEE_OR_INTERNAL_TESTER, + JOINABLE_CLIENT_POLL_INTERVAL_MIN, + KALEIDOSCOPE_THUMBNAIL_VALIDATION, + KS_USE_COMPONENT_MODEL, + LOBBY_TIMEOUT_MIN, + MARK_AS_VERIFIED_ENABLED, + MAX_GROUP_SIZE_FOR_LONG_RINGTONE, + MAX_NUM_PARTICIPANTS_FOR_SS, + MAX_NUMBER_OF_FREQUENTLY_USED_CONTACTS_SHARED_WITH_DEVICE, + MAX_NUMBER_OF_RECENT_CONTACTS_SHARED_WITH_DEVICE, + MAY_HAVE_MESSAGES_ENABLED, + MC_ENABLED, + MEMBER_NAME_TAG_DB_ENABLED, + MEMBER_NAME_TAG_RECEIVER_ENABLED, + MEMBER_NAME_TAG_SENDER_ENABLED, + MESSAGE_CAPPING_UPSELL_VERSION, + MM_1PD_POST_DC_DEPTH_LIMIT, + MM_1PD_POST_DC_NEW_SCHEMA_ENABLED, + MM_1PD_POST_DC_OLD_SCHEMA_DISABLED, + MM_DATA_SHARING_DISCLOSURE_ENABLED, + MM_DATA_SHARING_DISCLOSURE_ENABLED_ADDITIONAL_TRANSPARENCY_LARGE_SCREENS, + MM_DATA_SHARING_DISCLOSURE_ENABLED_COMPANION_HISTORY_SYNC, + MM_DISCLOSURE_HANDLE_TOS_FAILURES_ENABLED, + MM_DISCLOSURE_LEARN_MORE_ARTICLE_ID, + MM_OPTIMIZED_DELIVERY_APP_CTA_ENABLED, + MM_OPTIMIZED_DELIVERY_ARCHIVE_SIGNAL_SHARING_ENABLED, + MM_OPTIMIZED_DELIVERY_REPLACING_SHIMMED_LINKS_ENABLED, + MM_OPTIMIZED_DELIVERY_TOKEN_FALLBACK_DISABLED, + MM_OPTIMIZED_DELIVERY_UNIQUE_TOKEN_PER_MESSAGE_ID_ENABLED, + MM_SIGNAL_SHARING_COLLECTION_WINDOW_LOGGING_ENABLED, + MM_SIGNAL_SHARING_VERIFICATION_SYSTEM_LID_ENABLED, + MM_USER_CONTROLS_ENTRY_POINTS_UPDATE_M1_MENU, + NEW_CHAT_MSG_CAPPING_FIRST_WARNING_THRESHOLD_PERCENTAGE, + NOISE_PQ_MODE, + OPTIMIZED_DELIVERY_BLOCK_AND_REPORT_ENTRY_POINTS_ALLOWLIST_WEB, + OPTIMIZED_DELIVERY_MULTIPLE_COLLECTION_WINDOWS_ENABLED, + OPTIMIZED_DELIVERY_SIGNAL_COLLECTION_CONFIG, + OPTIMIZED_DELIVERY_SIGNAL_COLLECTION_ENABLED, + OPTIMIZED_DELIVERY_SIGNAL_COLLECTION_ON_COMPANIONS_ENABLED, + OPTIMIZED_DELIVERY_TOKENS_STORAGE_CONFIG, + P2P_PILLS_ALLOWLIST, + P2P_PILLS_ALLOWLIST_ENTRIES, + P2P_PILLS_AUTO_SEND_MESSAGES, + P2P_PILLS_ENABLED, + P2P_PILLS_ENABLED_FOR_INELIGIBLE_CONTACTS, + P2P_PILLS_ENTRIES, + P2P_PILLS_ENTRIES_ENABLED, + P2P_PILLS_GRAPHQL_ENABLED, + P2P_PILLS_MAX_WAIT_ON_CONTACT_CARD_SEND, + P2P_PILLS_NEW_BUSINESS_METADATA_ENABLED, + PAYMENTS_BR_P2M_PIX_COPY_CODE_BUYER_LOGGING, + PAYMENTS_BR_P2M_PIX_IN_GROUPS_BUYER_LOGGING, + PAYMENTS_BR_P2P_PIX_COPY_CODE_BUYER_LOGGING, + PAYMENTS_BR_PAYMENT_LINKS_BUYER_LOGGING, + PAYMENTS_BR_PIX_ON_WEB, + PENDING_GROUP_REQUESTS_PERSISTENT_BANNER, + POLL_ADD_OPTION_ENABLED, + POLL_ADD_OPTION_RECEIVING_ENABLED, + POLL_CREATOR_EDIT_ENABLED, + POLL_CREATOR_EDIT_RECEIVING_VERSION, + POLL_END_TIME_ENABLED, + POLL_END_TIME_RECEIVING_ENABLED, + POLL_HIDE_VOTERS_ENABLED, + POLL_HIDE_VOTERS_RECEIVING_ENABLED, + PREFER_LID_FOR_CHATD_LOGIN, + PRIVACY_SCREEN_ENABLED, + PRIVACY_SETTINGS_ABOUT_LID_MIGRATION_ENABLE, + PRIVACY_SETTINGS_GROUP_ADD_LID_MIGRATION_ENABLE, + PRIVACY_SETTINGS_PROFILE_LID_MIGRATION_ENABLE, + PRIVACY_SETTINGS_STICKERS_LID_MIGRATION_ENABLE, + PTV_QUOTED_REPLIES_CUTOUT_ENABLED, + REACTIONS_RECEIVER_ENABLED, + REPORT_CALL_REPLAYER_ID, + REUSE_CACHED_CERTS_FOR_DATA_CHANNEL, + SAGA_MESSAGE_FEEDBACK_USING_CANONICAL_ENT, + SECURITY_FIXES_BITMAP, + SFU_SECONDARY_REMOTE_BWE_IMPL, + SHIMMED_LINKS_IN_THE_MARKETING_MESSAGE_BODY_ENABLED, + SHOW_INTEGRITY_SCREENSHARING_FRICTION_UI, + SHOW_INTEGRITY_SCREENSHARING_FRICTION_UI_LOGGING_ENABLED, + SILENT_GROUP_USERNAME_ACTIVITIES_ENABLED, + SMOOTHIE_PERFORMANCE_RESIZE_FOLLOWUP, + STICKERS_EMOJI_TAGGING_ENABLED, + SUPPORT_CONTACT_FORM_USING_GRAPHQL, + UNIFIED_SESSION_LOG_CALL_EVENT, + UNIFY_END_CALL_EVENTS, + USE_CACHED_APP_SETTINGS_FROM_GLOBAL_CTX, + USERNAME_CONTACT_DISPLAY, + USERNAME_ENABLED_ON_COMPANION, + USERNAME_KEY_REDESIGN_ENABLED, + USERNAME_LID_MIGRATION_CALLING, + USERNAME_MAX_LENGTH, + USERNAME_MIN_LENGTH, + USERNAME_SEARCH, + USERNAME_SUGGESTIONS_ENABLED, + UWP_VOIP_INCOMING_CALL_NOTIFICATION_VERSION, + VID_PORT_ENABLE_CAPTURE_FPS_MEDIAN_FILTER, + VID_PORT_FRM_BUF_MUTEX_FIXES, + VOICE_AI_CONVERSATION_STARTER_LATENCY_TRACKING, + VOICE_CALL_STRING_TEST, + VOICE_CHAT_COMPANION_EXPERIENCE_VERSION, + VOIP_CALL_COORDINATOR_VERSION, + VOIP_STACK_INCOMING_MESSAGE_OWNERSHIP_TRANSFER, + WA_CALLING_BPN_SELF_PN_REMOVAL, + WA_CAPPING_LOCAL_DATA_LOGIC_UPDATE, + WA_INDIVIDUAL_NEW_CHAT_MSG_CAPPING_ENABLED, + WA_INDIVIDUAL_NEW_CHAT_MSG_CAPPING_FETCH_TTL_SECONDS, + WA_INDIVIDUAL_NEW_CHAT_MSG_CAPPING_MV_GET_SUBSCRIPTION_V2, + WA_INDIVIDUAL_NEW_CHAT_MSG_FCI_STALENESS_TTL_IN_SECONDS, + WA_INDIVIDUAL_NEW_CHAT_MSG_LATEST_RAMPUP_DATE, + WA_INDIVIDUAL_NEW_CHAT_THREAD_CAPPING_LIMIT, + WA_WEB_ADAPTIVE_LAYOUT_ENABLED, + WA_WIN_PDF_RENDERING_ENABLED, + WEB_ADD_CONTACT, + WEB_CHANNEL_VIDEO_SERVER_TRANSCODE_UPLOAD, + WEB_CHAT_INFO_ACTION_BUTTONS_REFRESH, + WEB_GROUP_BULK_ADD_CONTACT, + WEB_IP_TOKEN_ENABLED, + WEB_WINDOWS_CALLING_32P_VERSION, + WEBVIEW2_DISABLE_GPU_ACCELERATION, + WEBVIEW2_DISABLE_GPU_ACCELERATION_MEMORY_THRESHOLD_MB, + WEBVIEW2_ENABLE_OFFLINE_SUPPORT, + WIN_CALL_LOG_SEND_OUTGOING_SYNCD_MUTATIONS, + WIN_ENABLE_SS_BUTTON_AUDIO, + WIN_HYBRID_BT_ENABLED, + WIN_HYBRID_FORCE_PERSISTENT_STORAGE_PERMISSION, + WIN_HYBRID_VOIP_ANR_OPTIMIZATIONS, + WIN_HYBRID_VSR_BUTTON_ENABLED_2, + WIN_HYBRID_VSR_ENABLED_2, + WIN_NETWORK_STATE_WATCHDOG_INTERVAL, + WINDOWS_CONTACTS_INITIAL_SYNC_DELAY, + WINDOWS_CONTACTS_SYNC_INTERVAL, + WINDOWS_GRACEFUL_DEGRADATION_VERSION, + WINDOWS_SS_CAPTURE_DRIVER_TYPE, + WINRT_RENDERER, + ]; +} + /// Every registry's `ALL`, for whole-catalog iteration: /// `ALL.iter().flat_map(|r| r.iter())`. -pub const ALL: &[&[AbProp]] = &[web::ALL, group::ALL]; +pub const ALL: &[&[AbProp]] = &[web::ALL, group::ALL, hybrid::ALL]; diff --git a/wacore/src/store/device.rs b/wacore/src/store/device.rs index 4f9d4ad12..01f6dacea 100644 --- a/wacore/src/store/device.rs +++ b/wacore/src/store/device.rs @@ -437,9 +437,12 @@ impl Device { adv_secret_key, account: None, push_name: String::new(), - app_version_primary: 2, - app_version_secondary: 3000, - app_version_tertiary: 1042742319, + // The build the vendored whatspec artifacts describe, so a device + // that never reaches sw.js still announces a version whose stanza + // shapes and feature flags this client actually implements. + app_version_primary: crate::version::WA_WEB_VERSION.0, + app_version_secondary: crate::version::WA_WEB_VERSION.1, + app_version_tertiary: crate::version::WA_WEB_VERSION.2, app_version_last_fetched_ms: 0, device_props: Arc::new(DEVICE_PROPS.clone()), client_profile: ClientProfile::web(), diff --git a/wacore/src/version.rs b/wacore/src/version.rs index ddd3c7ae9..28d82fb49 100644 --- a/wacore/src/version.rs +++ b/wacore/src/version.rs @@ -1,3 +1,7 @@ +mod generated; + +pub use generated::{WA_WEB_VERSION, WA_WEB_VERSION_STR}; + const REVISION_KEY: &str = "client_revision"; const ASSETS_KEY: &str = "assets-manifest-"; diff --git a/wacore/src/version/generated.rs b/wacore/src/version/generated.rs new file mode 100644 index 000000000..95f447232 --- /dev/null +++ b/wacore/src/version/generated.rs @@ -0,0 +1,12 @@ +//! Auto-generated WhatsApp Web version stamp (WhatsApp 2.3000.1044659339). DO NOT EDIT. +//! +//! The WhatsApp Web build the committed whatspec artifacts were extracted from. +//! +//! Regenerate with `cargo run -p whatspec-codegen`; never edit by hand. + +/// The version string whatspec stamped on the IR: `2.3000.1044659339`. +pub const WA_WEB_VERSION_STR: &str = "2.3000.1044659339"; + +/// The same version as the `(primary, secondary, tertiary)` triple the +/// client payload carries. +pub const WA_WEB_VERSION: (u32, u32, u32) = (2, 3000, 1044659339); diff --git a/waproto/src/whatsapp.desc b/waproto/src/whatsapp.desc index 94c73399f..8a457f2ee 100644 Binary files a/waproto/src/whatsapp.desc and b/waproto/src/whatsapp.desc differ diff --git a/waproto/src/whatsapp.desc.sha256 b/waproto/src/whatsapp.desc.sha256 index 1783af052..947779ec3 100644 --- a/waproto/src/whatsapp.desc.sha256 +++ b/waproto/src/whatsapp.desc.sha256 @@ -1,2 +1,2 @@ -proto 037b3f83b9eb77af23bd5cdcbb29022665bf63d9e92f7a2a83f5c34bf7e1d8d7 -desc fdcbc4ad2964e01ec571c3c8c46849e989d16693f9e49d85b2c970d02a10d802 +proto 9de9c5a64a60650755e0ed1c5c99a80ddd8825734d96c8b36c52c109b050040c +desc ffbbde96a40427cca35f7c208317fa8d6aaedd1a8c9af55df177ec1d4e58bb77 diff --git a/waproto/src/whatsapp.proto b/waproto/src/whatsapp.proto index 622aad506..e174f5a72 100644 --- a/waproto/src/whatsapp.proto +++ b/waproto/src/whatsapp.proto @@ -1,7 +1,7 @@ syntax = "proto2"; package whatsapp; -/// WhatsApp Version: 2.3000.1042742319 +/// WhatsApp Version: 2.3000.1044659339 message ADVDeviceIdentity { optional uint32 rawId = 1; @@ -82,6 +82,15 @@ message AIMetadataOperation { optional HatchMetadataSync hatchMetadataSync = 1; } +message AIProvenance { + optional Metadata c2PaMetadata = 1; + optional Metadata iptcMetadata = 2; + message Metadata { + optional bool createdWithGenAi = 1; + optional bool editedWithGenAi = 2; + } +} + message AIQueryFanout { optional MessageKey messageKey = 1; optional Message message = 2; @@ -115,7 +124,7 @@ message AIRichResponseContentItemsMetadata { repeated AIRichResponseContentItemMetadata itemsMetadata = 1; optional ContentType contentType = 2; message AIRichResponseContentItemMetadata { - oneof aIRichResponseContentItem { + oneof aiRichResponseContentItem { AIRichResponseContentItemsMetadata.AIRichResponseReelItem reelItem = 1; } } @@ -365,6 +374,7 @@ message BotAgeCollectionMetadata { message BotAgentDeepLinkMetadata { optional string token = 1; + optional bytes clientPublicKey = 2; } message BotAgentMetadata { @@ -440,6 +450,10 @@ message BotCapabilityMetadata { UNIFIED_RESPONSE_MARKDOWN_LINKS_ENABLED = 63; AI_RICH_RESPONSE_MAPS_V2_ENABLED = 64; AI_SUBSCRIPTION_METERING_ENABLED = 65; + RICH_RESPONSE_SPORTS_WIDGET_ENABLED = 66; + AI_RICH_RESPONSE_ARTIFACTS_ENABLED = 67; + AI_RICH_RESPONSE_EMAIL_CALENDAR_ENABLED = 68; + AI_RICH_RESPONSE_REMINDERS_ENABLED = 69; } } @@ -557,6 +571,10 @@ message BotGroupParticipantMetadata { optional string botFbid = 1; } +message BotHistoryShareMetadata { + repeated BotGroupParticipantMetadata participantsMetadata = 1; +} + message BotImagineMetadata { optional ImagineType imagineType = 1; optional string shortPrompt = 2; @@ -680,6 +698,7 @@ message BotMetadata { optional BotResolvedToolCallMetadata resolvedToolCallMetadata = 40; optional AISubscriptionUpsellMetadata subscriptionUpsellMetadata = 41; optional BotPttPromptMetadata pttPromptMetadata = 42; + optional BotHistoryShareMetadata botHistoryShareMetadata = 43; optional bytes internalMetadata = 999; } @@ -732,6 +751,7 @@ enum BotMetricsEntryPoint { GROUP_MEMBER = 54; CHATLIST_SEARCH = 55; NEW_CHAT_LIST = 56; + CONTACTS_TAB = 57; } message BotMetricsMetadata { optional string destinationId = 1; @@ -948,11 +968,18 @@ message BotSignatureVerificationUseCaseProof { optional BotSignatureUseCase useCase = 2; optional bytes signature = 3; repeated bytes certificateChain = 4; + repeated CertificateSKI certificateChainSki = 5; enum BotSignatureUseCase { UNSPECIFIED = 0; WA_BOT_MSG = 1; WA_TEE_BOT_MSG = 2; P2P_PILLS = 3; + WA_WAFFLE = 4; + WA_FEATURE_PKI = 5; + } + message CertificateSKI { + optional BotSignatureVerificationUseCaseProof.BotSignatureUseCase useCase = 1; + optional bytes ski = 2; } } @@ -1330,6 +1357,7 @@ message ClientPayload { SMART_GLASSES = 35; BLUE_VR = 36; AR_WRIST = 37; + WAIL = 38; } enum ReleaseChannel { RELEASE = 0; @@ -1370,6 +1398,21 @@ message ClientPayload { } } +message CoexStateSync { + repeated CollectionMutations collectionMutations = 1; + message CollectionMutations { + optional string collection = 1; + repeated CoexStateSync.Mutation mutations = 2; + } + + message Mutation { + optional SyncdIndex index = 1; + optional SyncdValue value = 2; + optional uint64 dirtyVersion = 3; + optional SyncdMutation.SyncdOperation operation = 4; + } +} + enum CollectionName { COLLECTION_NAME_UNKNOWN = 0; REGULAR = 1; @@ -1684,6 +1727,8 @@ message ContextInfo { optional CrossAppSource crossAppSource = 77; optional BusinessInteractionPills businessInteractionPills = 78; optional string posterStatusId = 79; + optional InstagramThreadLink instagramThreadLink = 80; + optional AIProvenance aiProvenance = 81; message AdReplyInfo { optional string advertiserName = 1; optional MediaType mediaType = 2; @@ -1702,6 +1747,7 @@ message ContextInfo { optional EntryPoint entryPoint = 3; optional bytes signedPayload = 4; optional BotSignatureVerificationMetadata signatureEnvelope = 5; + optional UnauthenticatedBusinessMetadata unauthenticatedBusinessMetadata = 6; enum EntryPoint { ENTRY_POINT_UNKNOWN = 0; P2P_LINK_SHARE = 1; @@ -1734,6 +1780,13 @@ message ContextInfo { optional string verifiedName = 1; repeated ContextInfo.BusinessInteractionPills.Pill pills = 2; } + + message UnauthenticatedBusinessMetadata { + optional string businessName = 1; + optional string businessCategory = 2; + optional bool businessIsOpen = 3; + optional int64 businessIsOpenSnapshotMs = 4; + } } message BusinessMessageForwardInfo { @@ -1837,6 +1890,10 @@ message ContextInfo { } } + message InstagramThreadLink { + optional string url = 1; + } + enum PairedMediaType { NOT_PAIRED_MEDIA = 0; SD_VIDEO_PARENT = 1; @@ -1956,6 +2013,7 @@ message Conversation { optional uint64 appealUpdateTime = 60; optional string authAgentParentCompanyName = 61; optional string authAgentObaPhoneNumber = 62; + optional IdentityVerificationState identityVerification = 63; enum EndOfHistoryTransferType { COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY = 0; COMPLETE_AND_NO_MORE_MESSAGE_REMAIN_ON_PRIMARY = 1; @@ -1996,6 +2054,17 @@ message DecryptMessageOutput { optional string error = 2; } +message DeriveMessageKeyInput { + required bytes epochRootKey = 1; + required bytes epochAnonId = 2; + required string threadId = 3; +} + +message DeriveMessageKeyOutput { + optional bytes messageKey = 1; + optional string error = 2; +} + message DeviceCapabilities { optional ChatLockSupportLevel chatLockSupportLevel = 1; optional LIDMigration lidMigration = 2; @@ -2003,6 +2072,11 @@ message DeviceCapabilities { optional UserHasAvatar userHasAvatar = 4; optional MemberNameTagPrimarySupport memberNameTagPrimarySupport = 5; optional AiThread aiThread = 6; + optional AiFbidMigration aiFbidMigration = 7; + message AiFbidMigration { + optional uint64 chatDbMigrationTimestamp = 1; + } + message AiThread { optional SupportLevel supportLevel = 1; enum SupportLevel { @@ -2106,6 +2180,7 @@ message DeviceProps { optional bool supportHatchHistory = 22; repeated string supportedBotChannelFbids = 23; optional bool supportInlineContacts = 24; + optional bool supportNewsletter = 25; } enum PlatformType { @@ -2134,6 +2209,7 @@ message DeviceProps { VR = 22; CLOUD_API = 23; SMARTGLASSES = 24; + WAIL = 25; } } @@ -2207,7 +2283,6 @@ message EncryptMessageOutput { optional string valueSecretRef = 3; optional uint64 offlineThreadingId = 4; optional uint64 timestampMs = 5; - optional bytes messageKey = 6; optional string error = 7; } @@ -2410,6 +2485,7 @@ message HandshakeMessage { HANDSHAKE_PQ_MODE_UNKNOWN = 0; XXKEM = 1; XXKEM_FS = 2; + XXKEM_EPH = 9; WA_CLASSICAL = 3; WA_PQ = 4; IKKEM = 5; @@ -2509,6 +2585,11 @@ message IdentityKeyPairStructure { optional bytes privateKey = 2; } +message IdentityVerificationState { + optional bool verified = 1; + optional uint64 actionSeq = 2; +} + message InThreadSurveyMetadata { optional string tessaSessionId = 1; optional string simonSessionId = 2; @@ -2625,6 +2706,8 @@ message LabyrinthWaCommand { EncryptMessageInput encryptMessageInput = 2; DecryptMessageInput decryptMessageInput = 3; OrfThreadIdInput orfThreadIdInput = 4; + DeriveMessageKeyInput deriveMessageKeyInput = 5; + RotateEpochInput rotateEpochInput = 6; } } @@ -2852,6 +2935,10 @@ message Message { optional SplitPaymentMessage splitPaymentMessage = 125; optional FutureProofMessage newsletterAdminProfileStatusMessage = 126; optional RootSecretDistributeMessage rootSecretDistributeMessage = 127; + optional SplitPaymentUpdateMessage splitPaymentUpdateMessage = 128; + optional MusicMessage musicMessage = 129; + optional StatusLinkPreviewMetadata statusLinkPreviewMetadata = 130; + optional FutureProofMessage botPlatformRegistrationSuccessMessage = 131; message AlbumMessage { optional uint32 expectedImageCount = 2; optional uint32 expectedVideoCount = 3; @@ -2923,6 +3010,12 @@ message Message { } } + message BotHistoryShareSyncMetadata { + optional string botJid = 1; + optional int64 historyShareCutoffTimestamp = 2; + repeated Message.HistoryShareMessageEntry historyShareMessages = 3; + } + message ButtonsMessage { optional string contentText = 6; optional string footerText = 7; @@ -2993,6 +3086,7 @@ message Message { optional string deeplinkPayload = 9; optional MessageContextInfo messageContextInfo = 10; optional uint32 callEntryPoint = 11; + optional string callReason = 12; } message CallLogMessage { @@ -3232,7 +3326,7 @@ message Message { optional bool viewOnce = 30; optional uint32 videoHeight = 31; optional uint32 videoWidth = 32; - optional Message.MMSThumbnailMetadata faviconMMSMetadata = 33; + optional Message.MMSThumbnailMetadata faviconMmsMetadata = 33; optional Message.LinkPreviewMetadata linkPreviewMetadata = 34; optional Message.PaymentLinkMetadata paymentLinkMetadata = 35; repeated Message.VideoEndCard endCardTiles = 36; @@ -3351,6 +3445,11 @@ message Message { } } + message HistoryShareMessageEntry { + optional string stanzaId = 1; + optional bytes messageSecretProof = 2; + } + message HistorySyncMessageAccessStatus { optional bool completeAccessGranted = 1; } @@ -3685,6 +3784,13 @@ message Message { optional uint32 thumbnailWidth = 7; } + message MarkAsVerifiedAction { + optional string userJidString = 1; + optional bool verified = 2; + optional bytes verifiedIdentityKey = 3; + optional uint64 actionSeq = 4; + } + message MessageHistoryBundle { optional string mimetype = 1; optional bytes fileSha256 = 2; @@ -3707,6 +3813,18 @@ message Message { message MessageHistoryNotice { optional ContextInfo contextInfo = 1; optional Message.MessageHistoryMetadata messageHistoryMetadata = 2; + optional Message.BotHistoryShareSyncMetadata botHistoryShareSyncMetadata = 3; + } + + message MusicMessage { + optional EmbeddedMusic embeddedMusic = 1; + optional string songUri = 2; + optional string artworkUri = 3; + optional int32 style = 4; + optional ContextInfo contextInfo = 5; + enum MusicMessageStyle { + UNKNOWN = 0; + } } message NewsletterAdminInviteMessage { @@ -3755,6 +3873,7 @@ message Message { message PaymentExtendedMetadata { optional uint32 type = 1; optional string platform = 2; + optional string messageParamsJson = 3; } message PaymentInviteMessage { @@ -3772,6 +3891,7 @@ message Message { FBPAY = 1; NOVI = 2; UPI = 3; + PIX = 4; } } @@ -3919,6 +4039,7 @@ message Message { optional HistorySyncChunkRetryResponse historySyncChunkRetryResponse = 10; optional FlowResponsesCsvBundle flowResponsesCsvBundle = 11; optional BizBroadcastInsightsContactListResponse bizBroadcastInsightsContactListResponse = 12; + optional ContactRefreshResponse contactRefreshResponse = 13; message BizBroadcastInsightsContactListResponse { optional string campaignId = 1; optional int64 timestampMs = 2; @@ -3940,6 +4061,13 @@ message Message { optional string nonce = 1; } + message ContactRefreshResponse { + repeated string coveredRequestIds = 1; + optional uint64 collectionVersion = 2; + optional int64 primaryDurationMs = 3; + optional uint32 uniqueContactCount = 4; + } + message FlowResponsesCsvBundle { optional string flowId = 1; optional string galaxyFlowDownloadRequestId = 2; @@ -4043,6 +4171,7 @@ message Message { GALAXY_FLOW_ACTION = 11; BUSINESS_BROADCAST_INSIGHTS_DELIVERED_TO = 12; BUSINESS_BROADCAST_INSIGHTS_REFRESH = 13; + CONTACT_REFRESH_REQUEST = 14; } message PinInChatMessage { optional MessageKey key = 1; @@ -4185,6 +4314,8 @@ message Message { optional uint32 afterReadDuration = 29; optional Message.ChatThemeSetting chatThemeSetting = 30; optional AIMetadataOperation aiMetadataOperation = 31; + optional Message.MarkAsVerifiedAction markAsVerifiedAction = 32; + optional CoexStateSync coexStateSync = 33; enum Type { REVOKE = 0; EPHEMERAL_SETTING = 3; @@ -4216,6 +4347,8 @@ message Message { MESSAGE_UNSCHEDULE = 32; CHAT_THEME_SETTING = 34; AI_METADATA_OPERATION = 35; + MARK_AS_VERIFIED_ACTION = 36; + COEX_STATE_SYNC = 37; } } @@ -4331,6 +4464,21 @@ message Message { } } + message SplitPaymentUpdateMessage { + optional string splitId = 1; + optional string participantJid = 2; + } + + message StatusLinkPreviewMetadata { + optional Style style = 1; + enum Style { + AUTO = 0; + COMPACT = 1; + FULL = 2; + IMMERSIVE = 3; + } + } + message StatusNotificationMessage { optional MessageKey responseMessageKey = 1; optional MessageKey originalMessageKey = 2; @@ -4340,6 +4488,7 @@ message Message { STATUS_ADD_YOURS = 1; STATUS_RESHARE = 2; STATUS_QUESTION_ANSWER_RESHARE = 3; + STATUS_GROUP_STATUS_REPLY = 4; } } @@ -4610,6 +4759,8 @@ message MessageContextInfo { repeated ThreadID threadId = 15; optional WebLinkRenderConfig weblinkRenderConfig = 16; optional bytes teeBotMetadata = 17; + optional NonE2EEAttestation accountEncryptionAttestation = 18; + optional bytes associatedPrimaryIdentityKey = 19; enum MessageAddonExpiryType { STATIC = 1; DEPENDENT_ON_PARENT = 2; @@ -4820,6 +4971,9 @@ enum MutationProps { BIZ_AI_SETTINGS_NUDGE_ACTION = 87; COEX_V2_VERSION_ACTION = 88; WASA_ROOT_SECRET_ACTION = 89; + BUBBLE_LOCK_MESSAGE_ACTION = 90; + LABEL_SUBLIST_ACTION = 91; + DEVICE_CAPABILITIES_V2 = 92; SHARE_OWN_PN = 10001; BUSINESS_BROADCAST_ACTION = 10002; AI_THREAD_DELETE_ACTION = 10003; @@ -4836,6 +4990,15 @@ message NoiseCertificate { } } +message NonE2EEAttestation { + optional AccountType accountType = 1; + enum AccountType { + E2EE = 0; + HYBRID_E2EE = 1; + NON_E2EE = 2; + } +} + message NotificationMessageInfo { optional MessageKey key = 1; optional Message message = 2; @@ -5183,6 +5346,38 @@ message Reportable { message ReportingTokenInfo { optional bytes reportingTag = 1; + optional uint64 reportingTagTimestamp = 2; +} + +message RotateEpochInput { + required bytes currentEpochRootKey = 1; + required uint64 currentEpochAnonId = 2; + required uint64 currentEpochFbid = 3; + required uint64 newEpochFbid = 4; + required bytes epochStoragePrivateKey = 5; + repeated RotateEpochMemberInput members = 6; +} + +message RotateEpochMemberEdge { + optional uint64 deviceId = 1; + optional bytes encryptedEpochKey = 2; + optional bytes deviceEpochHmac = 3; +} + +message RotateEpochMemberInput { + required uint64 deviceId = 1; + required bytes epochStoragePublicKey = 2; + required bytes devicePublicKey = 3; +} + +message RotateEpochOutput { + optional bytes newEpochRootKey = 1; + optional uint64 newEpochAnonId = 2; + optional bytes epochAnonId = 3; + optional bytes epochData = 4; + repeated RotateEpochMemberEdge memberEdges = 5; + optional bytes epochRootKeyFingerprint = 6; + optional string error = 7; } message RoutingInfo { @@ -5356,6 +5551,7 @@ message StatusAttribution { GOOGLE_PHOTOS = 10; SOUNDCLOUD = 11; SHAZAM = 12; + PICSART = 13; } } @@ -5414,6 +5610,7 @@ message StatusAttribution { NEWSLETTER_STATUS = 9; STATUS_CLOSE_SHARING = 10; PAID_PARTNERSHIP = 11; + USERNAME_STATUS = 12; } } @@ -5536,6 +5733,9 @@ message SyncActionValue { optional BizAISettingsNudgeAction bizAiSettingsNudgeAction = 87; optional CoexV2VersionAction coexV2VersionAction = 88; optional WASARootSecretAction wasaRootSecretAction = 89; + optional BubbleLockMessageAction bubbleLockMessageAction = 90; + optional LabelSublistAction labelSublistAction = 91; + optional DeviceCapabilities deviceCapabilitiesV2 = 92; message AgentAction { optional string name = 1; optional int32 deviceId = 2; @@ -5580,6 +5780,7 @@ message SyncActionValue { EXAMPLE_RESPONSES = 3; KNOWLEDGE = 4; LEAD_GEN = 5; + HANDOFF_REMOVAL_TIMING = 6; } } @@ -5592,6 +5793,10 @@ message SyncActionValue { optional string pnJid = 2; } + message BubbleLockMessageAction { + optional bool locked = 1; + } + message BusinessBroadcastAssociationAction { optional bool deleted = 1; } @@ -5629,6 +5834,7 @@ message SyncActionValue { optional string listName = 3; repeated string labelIds = 4; optional string audienceExpression = 5; + optional string customAudienceFbid = 6; } message CallLogAction { @@ -5767,6 +5973,7 @@ message SyncActionValue { LOCKED = 13; INVITES = 14; THIRD_PARTY = 15; + LEAD = 16; } } @@ -5774,6 +5981,10 @@ message SyncActionValue { repeated int32 sortedLabelIds = 1; } + message LabelSublistAction { + optional int32 subListId = 1; + } + message LidContactAction { optional string fullName = 1; optional string firstName = 2; @@ -5991,6 +6202,7 @@ message SyncActionValue { optional bool shouldPlaySoundForCallNotification = 31; optional string chatThemeId = 32; optional string colorSchemeId = 33; + optional string stockWallpaperImageId = 34; enum DisplayMode { DISPLAY_MODE_UNKNOWN = 0; ALWAYS = 1; @@ -6037,6 +6249,7 @@ message SyncActionValue { SHOULD_PLAY_SOUND_FOR_CALL_NOTIFICATION = 31; CHAT_THEME_ID = 32; COLOR_SCHEME_ID = 33; + STOCK_WALLPAPER_IMAGE_ID = 34; } enum SettingPlatform { PLATFORM_UNKNOWN = 0; @@ -6168,6 +6381,11 @@ message SyncActionValue { optional string id = 1; optional bytes rootSecret = 2; optional int64 epoch = 3; + optional Status status = 4; + enum Status { + INACTIVE = 0; + ACTIVE = 1; + } } }