diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..79a6265 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [krypton-byte] diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index e9a5dda..bee8c8a 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -51,13 +51,9 @@ jobs: python-version: "3.12" - uses: astral-sh/setup-uv@v5 - uses: dtolnay/rust-toolchain@stable - - name: Rust cache (tryx root) + - name: Rust cache uses: Swatinem/rust-cache@v2 - - name: Rust cache (whatsapp-rust workspace) - uses: Swatinem/rust-cache@v2 - with: - workspaces: "libs/whatsapp-rust -> target" - name: Install dev dependencies run: uv sync --group dev --no-install-project - name: Build native extension diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index e4ee365..37c933c 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -50,14 +50,9 @@ jobs: - uses: dtolnay/rust-toolchain@stable - - name: Rust cache (tryx root) + - name: Rust cache uses: Swatinem/rust-cache@v2 - - name: Rust cache (whatsapp-rust workspace) - uses: Swatinem/rust-cache@v2 - with: - workspaces: "libs/whatsapp-rust -> target" - - name: Install dev dependencies run: uv sync --group dev --no-install-project diff --git a/Cargo.lock b/Cargo.lock index 01a29a3..4070b30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,18 +186,7 @@ checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", -] - -[[package]] -name = "audiopus_sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62314a1546a2064e033665d658e88c620a62904be945f8147e6b16c3db9f8651" -dependencies = [ - "cmake", - "log", - "pkg-config", + "syn 3.0.4", ] [[package]] @@ -277,27 +266,25 @@ dependencies = [ [[package]] name = "bon" -version = "3.9.3" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a602c73c7b0148ec6d12af6fd5cc7a46e2eacc8878271a999abac56eed12f561" +checksum = "9e3fac94a66da67200398458a25412bcc3f9b6443b5119a6cad9cf3ccfcd8cc6" dependencies = [ "bon-macros", - "rustversion", ] [[package]] name = "bon-macros" -version = "3.9.3" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dee98b0db6a962de883bf5d20362dee4d7ca0d12fe39a7c6c73c844e1cd7c1f" +checksum = "d4654961ad0494e4774c5c60b4cb4cd0ae9b9d92d039d901638b1dba97ebebf5" dependencies = [ - "darling 0.23.0", + "darling 0.24.1", "ident_case", - "prettyplease", + "prettyplease 0.3.0", "proc-macro2", "quote", - "rustversion", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] @@ -337,7 +324,7 @@ checksum = "2074a9c2f76b2ebe6af40f7bf67b6a19d6ce3663253ef2a55124dc93f38b230e" dependencies = [ "buffa", "buffa-descriptor", - "prettyplease", + "prettyplease 0.2.37", "proc-macro2", "quote", "syn 2.0.119", @@ -382,7 +369,7 @@ checksum = "46d07918caa9eeaaf06b7873925c53a61daac173539b4f7715090745e44e4e69" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -680,12 +667,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", + "darling_core 0.24.1", + "darling_macro 0.24.1", ] [[package]] @@ -704,15 +691,15 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" dependencies = [ "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] @@ -728,13 +715,13 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" dependencies = [ - "darling_core 0.23.0", + "darling_core 0.24.1", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] @@ -854,7 +841,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -1023,7 +1010,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -1400,9 +1387,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.37.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +checksum = "f1d20bef17f513b9b3004532233187769cd072d790971f4e4da0e346eb6401e8" dependencies = [ "cc", "pkg-config", @@ -1626,11 +1613,20 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "opus" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3809943dff6fbad5f0484449ea26bdb9cb7d8efdf26ed50d3c7f227f69eb5c" +checksum = "33718946cc77d4032911d4efe03a66dbcbfbd2bb16c3da06aaeadcc637c32216" dependencies = [ - "audiopus_sys", + "opusic-sys", +] + +[[package]] +name = "opusic-sys" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d1ecdf206421bc74343ab3bb2f30ad2abbfee41fa341f7181fecbaf957769a" +dependencies = [ + "cmake", ] [[package]] @@ -1732,6 +1728,16 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "prettyplease" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" +dependencies = [ + "proc-macro2", + "syn 3.0.4", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -1758,7 +1764,7 @@ checksum = "1c8d9ca532f185d5d4db7a7c9d51420b452168ea1c2b913953281bd6fe1fcbd0" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -1996,7 +2002,7 @@ checksum = "1c25ef604ac7dd839d44d64648952ea23c97866f124ff671b0ed2cf3ad9bb06e" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -2011,9 +2017,9 @@ dependencies = [ [[package]] name = "rtc-crypto" -version = "0.21.0-beta.1" +version = "0.21.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d47521f43ea9a6e16feafa78ba06633ca85a51f0ad66b906a5f01ccfe08ba90" +checksum = "df0f2e4801a79469b8094f715f563d946c76826336f8d9fefb47dc6628524f11" dependencies = [ "aes 0.8.4", "ccm", @@ -2030,9 +2036,9 @@ dependencies = [ [[package]] name = "rtc-datachannel" -version = "0.21.0-beta.1" +version = "0.21.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374adcfc6f138839109d84c521ccedae9410b11f62c1ae577cb786ed91494f50" +checksum = "0180e434128b3a3e9d8552ea958fd588839266cf08a2625741fbe65c292d1cb8" dependencies = [ "bytes", "log", @@ -2043,9 +2049,9 @@ dependencies = [ [[package]] name = "rtc-dtls" -version = "0.21.0-beta.1" +version = "0.21.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baf3ee5b4d481d57fdee828ed4abd281ba45ad98594502cd4e866d14316b48f" +checksum = "b6cb87e1ec1b828914aace884307974a9ed40747e2f6ccaab93a4fff42528a73" dependencies = [ "bytecheck", "byteorder", @@ -2063,9 +2069,9 @@ dependencies = [ [[package]] name = "rtc-sctp" -version = "0.21.0-beta.1" +version = "0.21.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db38ed06af7bea634b210c3e8cf0e78e3bb36669e120968f5961a3c12a209b67" +checksum = "9d9dabdca726a7c5eed4d4ae5f3f9d4e9baf7a2ed53efaedaae35b4bcc24bc2a" dependencies = [ "bytes", "crc32c", @@ -2079,9 +2085,9 @@ dependencies = [ [[package]] name = "rtc-shared" -version = "0.21.0-beta.1" +version = "0.21.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "108063844e58fa8470139c2d6bea3a28362e07d43194acef7e0d57d829d27cd6" +checksum = "998b045d95d158251842c5146918f3213346ca7724e8c6ac750c37d467dbbcdd" dependencies = [ "bitflags 1.3.2", "bytes", @@ -2235,7 +2241,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -2524,9 +2530,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" dependencies = [ "proc-macro2", "quote", @@ -2600,7 +2606,7 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -2691,7 +2697,7 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -2984,6 +2990,7 @@ dependencies = [ "buffa", "buffa-build", "bytes", + "cbc", "chrono", "compact_str", "ctr 0.10.1", @@ -3059,7 +3066,7 @@ version = "0.7.0" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -3619,7 +3626,7 @@ checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] diff --git a/README.id.md b/README.id.md index e923495..0211f8f 100644 --- a/README.id.md +++ b/README.id.md @@ -1,8 +1,13 @@ +
+Tryx + # Tryx [![PyPI version](https://img.shields.io/pypi/v/tryx?color=blue)](https://pypi.org/project/tryx/) [![Python](https://img.shields.io/pypi/pyversions/tryx.svg)](https://pypi.org/project/tryx/) [![License](https://img.shields.io/github/license/krypton-byte/tryx)](LICENSE) + +
[![Docs](https://img.shields.io/badge/docs-online-brightgreen)](https://krypton-byte.github.io/tryx/) **Bahasa:** [English](README.md) | [简体中文](README.zh.md) | Bahasa Indonesia diff --git a/README.md b/README.md index 95a24c2..fbbdeea 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +
+Tryx + # Tryx [![PyPI version](https://img.shields.io/pypi/v/tryx?color=blue)](https://pypi.org/project/tryx/) @@ -7,6 +10,8 @@ **Language:** English | [简体中文](README.zh.md) | [Bahasa Indonesia](README.id.md) +
+ Tryx is a Python automation library powered by Rust and PyO3. It provides a Python-friendly API on top of the `whatsapp-rust` crate, with async support, persistent sessions, and access to advanced WhatsApp Web protocol features. > Tryx is an independent project. It is not affiliated with WhatsApp, Meta, or their official products. diff --git a/README.zh.md b/README.zh.md index bc51c1e..371ee42 100644 --- a/README.zh.md +++ b/README.zh.md @@ -1,8 +1,13 @@ +
+Tryx + # Tryx [![PyPI version](https://img.shields.io/pypi/v/tryx?color=blue)](https://pypi.org/project/tryx/) [![Python](https://img.shields.io/pypi/pyversions/tryx.svg)](https://pypi.org/project/tryx/) [![License](https://img.shields.io/github/license/krypton-byte/tryx)](LICENSE) + +
[![Docs](https://img.shields.io/badge/docs-online-brightgreen)](https://krypton-byte.github.io/tryx/) **语言:** [English](README.md) | 简体中文 | [Bahasa Indonesia](README.id.md) diff --git a/assets/mascot.png b/assets/mascot.png new file mode 100644 index 0000000..7cf791c Binary files /dev/null and b/assets/mascot.png differ diff --git a/docs/api/client.md b/docs/api/client.md index 39c5d16..bbf05c9 100644 --- a/docs/api/client.md +++ b/docs/api/client.md @@ -1,4 +1,4 @@ -# Client API Gateway +# :material-api: Client API Gateway ::: tryx.client.Tryx options: diff --git a/docs/api/events.md b/docs/api/events.md index 4a18b08..e19e7da 100644 --- a/docs/api/events.md +++ b/docs/api/events.md @@ -1,4 +1,4 @@ -# Events API +# :material-broadcast: Events API ::: tryx.events.Dispatcher options: @@ -172,6 +172,40 @@ async def on_presence(client, event): pass ``` +## Example: Group Subject Change with LID Addressing + +When a group subject (name) is changed, the `Subject` action carries the renamer's identity. In LID-addressed groups, the phone-number alias arrives in a separate field: + +```python +from tryx.events import EvGroupUpdate, GroupNotificationAction + + +@app.on(EvGroupUpdate) +async def on_group_update(client, event): + action = event.data.action + + if isinstance(action, GroupNotificationAction.Subject): + renamer = action.subject_owner # JID (may be a LID) + renamer_pn = action.subject_owner_pn # phone-number JID (when LID addressing) + renamer_name = action.subject_owner_username # username (when enabled) + + # Prefer the phone-number JID for display when available + display_jid = renamer_pn or renamer + print( + f"Group renamed to {action.subject!r} " + f"by {display_jid}" + ) + + # Log all identity fields for audit + if renamer_pn: + print(f" LID: {renamer}, PN: {renamer_pn}") + if renamer_name: + print(f" Username: {renamer_name}") +``` + +!!! tip "LID vs Phone Number" + In WhatsApp's LID addressing mode, `subject_owner` may be a `@lid` JID that is not human-readable. The `subject_owner_pn` field provides the corresponding phone-number JID for display. When LID addressing is not active, `subject_owner_pn` is `None` and `subject_owner` already contains the phone-number JID. + ## Enum-like Support Types Common reason/state classes used by event payloads: diff --git a/docs/api/exceptions.md b/docs/api/exceptions.md index aa3c0bd..e40a726 100644 --- a/docs/api/exceptions.md +++ b/docs/api/exceptions.md @@ -1,4 +1,4 @@ -# Exceptions API +# :material-alert-circle: Exceptions API ::: tryx.exceptions.FailedBuildClient options: diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 0000000..99ad245 --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,7 @@ +--- +icon: material/api +--- + +# :material-api: API Reference + +Complete API documentation for all Tryx modules. diff --git a/docs/api/types.md b/docs/api/types.md index 05c9122..6e02eff 100644 --- a/docs/api/types.md +++ b/docs/api/types.md @@ -1,4 +1,4 @@ -# Types API +# :material-shape: Types API ::: tryx.types.JID options: diff --git a/docs/assets/mascot.png b/docs/assets/mascot.png new file mode 100644 index 0000000..7cf791c Binary files /dev/null and b/docs/assets/mascot.png differ diff --git a/docs/core-concepts/architecture.md b/docs/core-concepts/architecture.md index 4194aea..b469839 100644 --- a/docs/core-concepts/architecture.md +++ b/docs/core-concepts/architecture.md @@ -1,4 +1,4 @@ -# Architecture +# :material-puzzle: Architecture Tryx splits performance-sensitive protocol work (Rust) from application ergonomics (Python). This gives you WhatsApp protocol handling at native diff --git a/docs/core-concepts/event-model.md b/docs/core-concepts/event-model.md index f18709e..65e6bd5 100644 --- a/docs/core-concepts/event-model.md +++ b/docs/core-concepts/event-model.md @@ -1,4 +1,4 @@ -# Event Model +# :material-bell-ring: Event Model Tryx uses an event-driven architecture. All WhatsApp interactions — messages, presence changes, group updates, contact syncs — flow through typed event diff --git a/docs/core-concepts/index.md b/docs/core-concepts/index.md new file mode 100644 index 0000000..d0cbb41 --- /dev/null +++ b/docs/core-concepts/index.md @@ -0,0 +1,7 @@ +--- +icon: material/puzzle-outline +--- + +# :material-puzzle: Core Concepts + +Understand the architecture and design principles behind Tryx. diff --git a/docs/core-concepts/storage-backends.md b/docs/core-concepts/storage-backends.md index efc2f9a..7d203eb 100644 --- a/docs/core-concepts/storage-backends.md +++ b/docs/core-concepts/storage-backends.md @@ -1,4 +1,4 @@ -# Storage Backends +# :material-database: Storage Backends Tryx supports a **3-tier storage architecture** so you can pick the right balance between simplicity, performance, and flexibility for your project. diff --git a/docs/core-concepts/type-system.md b/docs/core-concepts/type-system.md index cd37b2d..4330d47 100644 --- a/docs/core-concepts/type-system.md +++ b/docs/core-concepts/type-system.md @@ -1,4 +1,4 @@ -# Type System +# :material-code-braces: Type System Tryx ships with complete `.pyi` stub files and a `py.typed` marker, enabling full editor intelligence, static analysis, and API discoverability. diff --git a/docs/faq/qna.md b/docs/faq/qna.md index cebc82e..a885128 100644 --- a/docs/faq/qna.md +++ b/docs/faq/qna.md @@ -1,4 +1,4 @@ -# FAQ +# :material-frequently-asked-questions: FAQ Quick answers to common questions. Jump to the linked pages for implementation details. diff --git a/docs/getting-started/authentication.md b/docs/getting-started/authentication.md index f9d7555..8edbd32 100644 --- a/docs/getting-started/authentication.md +++ b/docs/getting-started/authentication.md @@ -1,4 +1,4 @@ -# Authentication Flow +# :material-key-variant: Authentication Flow Tryx follows the WhatsApp multi-device pairing flow. The first run links a session, and later runs reuse stored state. diff --git a/docs/getting-started/contributing.md b/docs/getting-started/contributing.md index e92d8d8..3f5d25a 100644 --- a/docs/getting-started/contributing.md +++ b/docs/getting-started/contributing.md @@ -1,4 +1,4 @@ -# Contributing +# :material-account-group: Contributing This guide explains how to contribute to Tryx development. diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md new file mode 100644 index 0000000..ab1f94f --- /dev/null +++ b/docs/getting-started/index.md @@ -0,0 +1,7 @@ +--- +icon: material/rocket-launch-outline +--- + +# :material-rocket-launch: Getting Started + +Get up and running with Tryx quickly. diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 76e3c9c..80a8510 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -1,4 +1,4 @@ -# Installation +# :material-package-variant: Installation This guide sets up a working development environment for building with Tryx. diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md index 374aa80..1faa13f 100644 --- a/docs/getting-started/quickstart.md +++ b/docs/getting-started/quickstart.md @@ -1,4 +1,4 @@ -# Quick Start +# :material-rocket-launch: Quick Start Build a working WhatsApp bot in 5 minutes. This guide walks through the minimal setup, then expands with real functionality. diff --git a/docs/index.md b/docs/index.md index 997a3ae..f34b44b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,11 @@ +--- +icon: material/home +--- + +
+Tryx +
+ # Tryx **Rust-powered Python SDK for event-driven WhatsApp automation.** diff --git a/docs/operations/deployment.md b/docs/operations/deployment.md index e9bd46a..f50f4de 100644 --- a/docs/operations/deployment.md +++ b/docs/operations/deployment.md @@ -1,4 +1,4 @@ -# Deployment Guide +# :material-cloud-upload: Deployment Guide Deploy Tryx bots safely in production with stable session storage and predictable restarts. diff --git a/docs/operations/index.md b/docs/operations/index.md new file mode 100644 index 0000000..90185c6 --- /dev/null +++ b/docs/operations/index.md @@ -0,0 +1,7 @@ +--- +icon: material/cog-outline +--- + +# :material-cog: Operations + +Deployment, monitoring, and maintenance guides. diff --git a/docs/operations/performance.md b/docs/operations/performance.md index 88ab8b0..2b46c63 100644 --- a/docs/operations/performance.md +++ b/docs/operations/performance.md @@ -1,4 +1,4 @@ -# Performance Guide +# :material-speedometer: Performance Guide Optimize for predictable latency and stable memory under burst traffic. diff --git a/docs/operations/reliability.md b/docs/operations/reliability.md index 45759b6..501ff3a 100644 --- a/docs/operations/reliability.md +++ b/docs/operations/reliability.md @@ -1,4 +1,4 @@ -# Reliability Playbook +# :material-shield-check: Reliability Playbook This page focuses on idempotency, retry strategy, and safe handler design. diff --git a/docs/operations/security.md b/docs/operations/security.md index 642e73a..7a458a0 100644 --- a/docs/operations/security.md +++ b/docs/operations/security.md @@ -1,4 +1,4 @@ -# Security Practices +# :material-lock: Security Practices Secure your client around four risk zones: session state, operator controls, user input, and outbound behavior. diff --git a/docs/operations/troubleshooting.md b/docs/operations/troubleshooting.md index 8e07a4c..0fc5efd 100644 --- a/docs/operations/troubleshooting.md +++ b/docs/operations/troubleshooting.md @@ -1,4 +1,4 @@ -# Troubleshooting +# :material-wrench: Troubleshooting Use this page as a decision tree first, checklist second. diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 0af326a..8c4bcf4 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -1,5 +1,11 @@ {% extends "base.html" %} +{% block scripts %} + {{ super() }} + + +{% endblock %} + {% block outdated %} You're not viewing the latest version. diff --git a/docs/reference/changelog.md b/docs/reference/changelog.md index ca51fd0..7b3c1d3 100644 --- a/docs/reference/changelog.md +++ b/docs/reference/changelog.md @@ -1,4 +1,4 @@ -# Changelog Policy +# :material-history: Changelog Policy Tryx changelog is generated automatically with `python-semantic-release`. diff --git a/docs/reference/error-handling.md b/docs/reference/error-handling.md index c57fafa..05d8a1d 100644 --- a/docs/reference/error-handling.md +++ b/docs/reference/error-handling.md @@ -1,4 +1,4 @@ -# Error Handling +# :material-bug: Error Handling Use exception classes and failure classification to decide whether to retry, fail fast, or trigger operator action. diff --git a/docs/reference/glossary.md b/docs/reference/glossary.md index 2d0cd25..7cb37ff 100644 --- a/docs/reference/glossary.md +++ b/docs/reference/glossary.md @@ -1,4 +1,4 @@ -# Glossary +# :material-book-alphabetical: Glossary --- diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 0000000..39e2867 --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,7 @@ +--- +icon: material/bookshelf +--- + +# :material-bookshelf: Reference + +Additional resources, FAQ, and changelog. diff --git a/docs/reference/roadmap.md b/docs/reference/roadmap.md index 301658b..e252cd1 100644 --- a/docs/reference/roadmap.md +++ b/docs/reference/roadmap.md @@ -1,4 +1,4 @@ -# Roadmap +# :material-map: Roadmap ## Near-Term diff --git a/docs/tutorials/command-bot.md b/docs/tutorials/command-bot.md index 208ed90..88a9da7 100644 --- a/docs/tutorials/command-bot.md +++ b/docs/tutorials/command-bot.md @@ -1,4 +1,4 @@ -# Tutorial: Command Bot +# :material-console: Tutorial: Command Bot Build a command-driven WhatsApp bot that stays maintainable as command count grows. This tutorial progresses from a minimal router to a production-ready diff --git a/docs/tutorials/group-automation.md b/docs/tutorials/group-automation.md index 3ae71de..5927c51 100644 --- a/docs/tutorials/group-automation.md +++ b/docs/tutorials/group-automation.md @@ -1,4 +1,4 @@ -# Tutorial: Group Automation +# :material-account-multiple: Tutorial: Group Automation Automate full group lifecycle with safe participant governance. diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md new file mode 100644 index 0000000..9d98f9b --- /dev/null +++ b/docs/tutorials/index.md @@ -0,0 +1,7 @@ +--- +icon: material/school-outline +--- + +# :material-school: Tutorials + +Step-by-step guides to build real-world integrations. diff --git a/docs/tutorials/media-workflows.md b/docs/tutorials/media-workflows.md index 67899e6..cf9f6e3 100644 --- a/docs/tutorials/media-workflows.md +++ b/docs/tutorials/media-workflows.md @@ -1,4 +1,4 @@ -# Tutorial: Media Workflows +# :material-image-multiple: Tutorial: Media Workflows This tutorial covers send, download, and recovery flows for media-heavy bots. diff --git a/docs/tutorials/poll-survey.md b/docs/tutorials/poll-survey.md index d0ed405..f06abac 100644 --- a/docs/tutorials/poll-survey.md +++ b/docs/tutorials/poll-survey.md @@ -1,4 +1,4 @@ -# Tutorial: Poll Survey Workflow +# :material-poll: Tutorial: Poll Survey Workflow Create poll surveys, collect encrypted votes, and aggregate results. diff --git a/docs/tutorials/profile-privacy.md b/docs/tutorials/profile-privacy.md index c825837..eeea536 100644 --- a/docs/tutorials/profile-privacy.md +++ b/docs/tutorials/profile-privacy.md @@ -1,4 +1,4 @@ -# Tutorial: Profile and Privacy +# :material-account-cog: Tutorial: Profile and Privacy Build admin-controlled profile and privacy management commands. diff --git a/libs/whatsapp-rust b/libs/whatsapp-rust index 1489b7d..1ace865 160000 --- a/libs/whatsapp-rust +++ b/libs/whatsapp-rust @@ -1 +1 @@ -Subproject commit 1489b7da9a6a7e3cadc4337ee46399da7de25915 +Subproject commit 1ace865716726daec8d0f00335453fcb8de35d1b diff --git a/mkdocs.yml b/mkdocs.yml index c724ea9..0d9ba16 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,60 +9,67 @@ edit_uri: edit/main/docs/ nav: - Home: index.md - Getting Started: - - Installation: getting-started/installation.md - - Quick Start: getting-started/quickstart.md - - Authentication Flow: getting-started/authentication.md - - Contributing: getting-started/contributing.md + - getting-started/index.md + - getting-started/installation.md + - getting-started/quickstart.md + - getting-started/authentication.md + - getting-started/contributing.md - Core Concepts: - - Architecture: core-concepts/architecture.md - - Event Model: core-concepts/event-model.md - - Storage Backends: core-concepts/storage-backends.md - - Type System: core-concepts/type-system.md + - core-concepts/index.md + - core-concepts/architecture.md + - core-concepts/event-model.md + - core-concepts/storage-backends.md + - core-concepts/type-system.md - API Reference: - - Client API Gateway: api/client.md - - Storage Backends: api/backend.md - - Client Namespaces: - - Contact: api/contact.md - - Chat Actions: api/chat-actions.md - - Community: api/community.md - - Newsletter: api/newsletter.md - - Groups: api/groups.md - - Status: api/status.md - - Chatstate: api/chatstate.md - - Blocking: api/blocking.md - - Polls: api/polls.md - - Presence: api/presence.md - - Privacy: api/privacy.md - - Profile: api/profile.md - - Events API: api/events.md - - Types API: api/types.md - - Exceptions: api/exceptions.md - - Helpers: api/helpers.md - - WACore: api/wacore.md + - api/index.md + - api/client.md + - api/backend.md + - api/contact.md + - api/chat-actions.md + - api/community.md + - api/newsletter.md + - api/groups.md + - api/status.md + - api/chatstate.md + - api/blocking.md + - api/polls.md + - api/presence.md + - api/privacy.md + - api/profile.md + - api/events.md + - api/types.md + - api/exceptions.md + - api/helpers.md + - api/wacore.md - Tutorials: - - Command Bot: tutorials/command-bot.md - - Profile & Privacy: tutorials/profile-privacy.md - - Poll Survey: tutorials/poll-survey.md - - Media Workflows: tutorials/media-workflows.md - - Group Automation: tutorials/group-automation.md + - tutorials/index.md + - tutorials/command-bot.md + - tutorials/profile-privacy.md + - tutorials/poll-survey.md + - tutorials/media-workflows.md + - tutorials/group-automation.md - Operations: - - Deployment: operations/deployment.md - - Reliability: operations/reliability.md - - Troubleshooting: operations/troubleshooting.md - - Performance: operations/performance.md - - Security: operations/security.md + - operations/index.md + - operations/deployment.md + - operations/reliability.md + - operations/troubleshooting.md + - operations/performance.md + - operations/security.md - Reference: - - FAQ: faq/qna.md - - Glossary: reference/glossary.md - - Error Handling: reference/error-handling.md - - Roadmap: reference/roadmap.md - - Changelog: reference/changelog.md + - reference/index.md + - faq/qna.md + - reference/glossary.md + - reference/error-handling.md + - reference/roadmap.md + - reference/changelog.md theme: name: material variant: modern language: en custom_dir: docs/overrides + logo: assets/mascot.png + favicon: assets/mascot.png font: text: Inter code: JetBrains Mono @@ -70,6 +77,7 @@ theme: - navigation.sections - navigation.tabs - navigation.tabs.sticky + - navigation.indexes - navigation.top - navigation.path - navigation.tracking @@ -87,7 +95,7 @@ theme: - search.highlight - search.share - toc.follow - - toc.integrate + # - toc.integrate # not compatible with navigation.indexes palette: - media: "(prefers-color-scheme: light)" scheme: default diff --git a/python/tryx/events.pyi b/python/tryx/events.pyi index 118179d..a55ac7e 100644 --- a/python/tryx/events.pyi +++ b/python/tryx/events.pyi @@ -108,11 +108,32 @@ class BusinessStatusUpdateType: Unknown: BusinessStatusUpdateType class GroupNotificationAction: - """Opaque group update action variant. + """Group update action variant. The runtime returns one action object that describes what changed in a group. + Access the variant type via ``isinstance`` checks, for example:: + + from tryx.events import GroupNotificationAction + + if isinstance(action, GroupNotificationAction.Subject): + print(action.subject) + print(action.subject_owner_pn) """ + class Subject: + """Group subject (name) was changed.""" + + subject: str + """New group name.""" + subject_owner: JID | None + """JID of the user who renamed the group (follows addressing mode).""" + subject_owner_pn: JID | None + """Phone-number JID of the renamer when ``subject_owner`` is a LID.""" + subject_owner_username: str | None + """Renamer's username, when username addressing is enabled.""" + subject_timestamp: datetime | None + """Server timestamp of the rename.""" + class EvConnected: """Emitted when the session becomes connected.""" diff --git a/src/clients/tryx.rs b/src/clients/tryx.rs index 49eb52b..66ef8ea 100644 --- a/src/clients/tryx.rs +++ b/src/clients/tryx.rs @@ -34,7 +34,7 @@ use super::status::StatusClient; use super::tryx_client::TryxClient; use crate::clients::chat_actions::ChatActionsClient; use crate::log::init_logging; -use crate::backend::{SqliteStore, BackendBase}; +use crate::backend::SqliteStore; use crate::events::types::{ EvArchiveUpdate, EvBusinessStatusUpdate, EvChatPresence, EvClientOutDated, EvConnectFailure, EvConnected, EvContactNumberChanged, EvContactSyncRequested, EvContactUpdate, EvContactUpdated, EvDeleteChatUpdate, EvDeleteMessageForMeUpdate, EvDeviceListUpdate, EvDisappearingModeChanged, EvDisconnected, EvGroupUpdate, EvHistorySync, EvLoggedOut, EvMarkChatAsReadUpdate, EvMessage, EvMuteUpdate, EvNewsletterLiveUpdate, EvNotification, EvOfflineSyncCompleted, EvOfflineSyncPreview, EvPairError, EvPairSuccess, EvPairingCode, EvPairingQrCode, EvPictureUpdate, EvPinUpdate, EvPresence, EvPushNameUpdate, EvQrScannedWithoutMultidevice, EvReceipt, EvSelfPushNameUpdated, EvStarUpdate, EvStreamError, EvStreamReplaced, EvTemporaryBan, EvUndecryptableMessage, EvUserAboutUpdate }; diff --git a/src/clients/voip.rs b/src/clients/voip.rs index 4373a14..efd6a72 100644 --- a/src/clients/voip.rs +++ b/src/clients/voip.rs @@ -113,15 +113,20 @@ impl CallHandle { self.inner.is_muted() } - fn set_muted(&self, muted: bool) { - self.inner.set_muted(muted); + fn set_muted<'py>(&self, py: Python<'py>, muted: bool) -> PyResult> { + let call = self.inner.clone(); + let locals = get_current_locals(py)?; + future_into_py_with_locals(py, locals, async move { + let _ = call.set_muted(muted).await; + Ok(()) + }) } fn hangup<'py>(&self, py: Python<'py>) -> PyResult> { let call = self.inner.clone(); let locals = get_current_locals(py)?; future_into_py_with_locals(py, locals, async move { - call.hangup().await; + call.hangup_local().await; Ok(()) }) } diff --git a/src/events/types/message_and_updates.rs b/src/events/types/message_and_updates.rs index 849c687..dcbb4e9 100644 --- a/src/events/types/message_and_updates.rs +++ b/src/events/types/message_and_updates.rs @@ -719,6 +719,8 @@ pub enum GroupNotificationAction { Subject { subject: String, subject_owner: Option>, + subject_owner_pn: Option>, + subject_owner_username: Option, subject_timestamp: Option>, }, Description { @@ -885,14 +887,17 @@ impl EvGroupUpdate { let py_participants = py_group_participants(participants); GroupNotificationAction::Modify { participants: py_participants } }, - wacore::stanza::groups::GroupNotificationAction::Subject { subject, subject_owner, subject_time } => { + wacore::stanza::groups::GroupNotificationAction::Subject { subject, subject_owner, subject_owner_pn, subject_owner_username, subject_time } => { let py_subject_owner = subject_owner .as_ref() .map(|o| Py::new(py, JID::from(o.clone())).unwrap()); + let py_subject_owner_pn = subject_owner_pn + .as_ref() + .map(|o| Py::new(py, JID::from(o.clone())).unwrap()); let py_subject_timestamp = subject_time.map(|t| { PyDateTime::from_timestamp(py, t as f64, None).unwrap().into() }); - GroupNotificationAction::Subject { subject: subject.clone(), subject_owner: py_subject_owner, subject_timestamp: py_subject_timestamp } + GroupNotificationAction::Subject { subject: subject.clone(), subject_owner: py_subject_owner, subject_owner_pn: py_subject_owner_pn, subject_owner_username: subject_owner_username.clone(), subject_timestamp: py_subject_timestamp } }, wacore::stanza::groups::GroupNotificationAction::Description { id, description } => { GroupNotificationAction::Description { id: id.clone(), description: description.clone() }