Skip to content

Release 1.10.0#3261

Closed
github-actions[bot] wants to merge 10 commits intomainfrom
release/1.10.0
Closed

Release 1.10.0#3261
github-actions[bot] wants to merge 10 commits intomainfrom
release/1.10.0

Conversation

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented Mar 3, 2026

Release 1.10.0

This PR was created by the Create Release Branch workflow.

Checklist

  • Release notes reviewed and finalized
  • All SDK versions bumped
  • RC published and validated
  • Final release published via Release workflow

Note: This PR will be merged automatically by the Release workflow upon final release.

Note

Release v1.10.0 with Backend builder API and unified environment configuration

  • Adds BackendBuilder and Backend types to Node and WASM bindings, replacing discrete host/gateway parameters across createClient, getInboxIdByIdentity, revokeInstallationsSignatureRequest, applySignatureRequest, and fetchInboxStatesByInboxIds
  • Introduces a new xmtp_macro::napi_builder, wasm_builder, and uniffi_builder proc-macro attribute that generates binding-specific constructors and chainable setters from annotated structs
  • Adds XmtpEnv enum to node/wasm bindings and xmtp_configuration crate with centralized/decentralized variants and a validate_and_resolve config helper
  • ClientBundleBuilder now supports D14n mode with gateway-only configuration; V3 and D14n are selected automatically based on which hosts are provided
  • On WASM, GrpcUrlsProduction::NODE now resolves to https://api.production.xmtp.network:5558 instead of the gRPC endpoint
  • Improves device sync test coverage on Android, iOS, and mobile bindings for archive upload, processing, and message visibility
  • Behavioral Change: all Node and WASM public functions that previously accepted v3_host/gatewayHost/isSecure now require a Backend instance; the encryptionKey parameter is ignored in WASM client creation with a warning logged when provided

Macroscope summarized 5c42da5.

@github-actions github-actions bot requested review from a team as code owners March 3, 2026 18:00
macroscopeapp[bot]
macroscopeapp bot previously approved these changes Mar 3, 2026
Copy link
Contributor

@macroscopeapp macroscopeapp bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-evaluating approvability for da3a7ef

neekolas and others added 6 commits March 3, 2026 13:22
## Summary
- Upgrades the `check-swift` CI runner from `warp-macos-13-arm64-6x` to
`warp-macos-15-arm64-6x`

## Test plan
- [ ] Verify `check-swift` jobs pass on the new macOS 15 runner for both
x86_64 and aarch64 targets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- Macroscope's pull request summary starts here -->
<!-- Macroscope will only edit the content between these invisible
markers, and the markers themselves will not be visible in the GitHub
rendered markdown. -->
<!-- If you delete either of the start / end markers from your PR's
description, Macroscope will append its summary at the bottom of the
description. -->
> [!NOTE]
> ### Upgrade `check-swift` CI runner from macOS 13 to macOS 15
> Updates the runner label in
[test-bindings-check.yml](.github/workflows/test-bindings-check.yml)
from `warp-macos-13-arm64-6x` to `warp-macos-15-arm64-6x`.
>
> <!-- Macroscope's review summary starts here -->
>
> <sup><a href="https://app.macroscope.com">Macroscope</a> summarized
dbf0310.</sup>
> <!-- Macroscope's review summary ends here -->
>
<!-- macroscope-ui-refresh -->
<!-- Macroscope's pull request summary ends here -->

Co-authored-by: Sprite <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
<!-- Macroscope's pull request summary starts here -->
<!-- Macroscope will only edit the content between these invisible
markers, and the markers themselves will not be visible in the GitHub
rendered markdown. -->
<!-- If you delete either of the start / end markers from your PR's
description, Macroscope will append its summary at the bottom of the
description. -->
### Add intent hash to MLS staged commit log events and rename
`ProcessedWelcome` to `ReceivedWelcome`
- Adds a `hash` field to `MLSReceivedStagedCommit` and
`GroupSyncStagedCommitPresent` log events in
[`mls_sync.rs`](https://github.com/xmtp/libxmtp/pull/3268/files#diff-160aadcd7de477c1116260a79601a0548842f3bd91bf16bd8443debb66ce6684),
sourced from `message_envelope.payload_hash` and `intent_hash`
respectively.
- Renames the `ProcessedWelcome` event variant to `ReceivedWelcome` in
[`event_logging.rs`](https://github.com/xmtp/libxmtp/pull/3268/files#diff-b892bd1dce497466fd9fa05752e7d5858b05185df4cfbc2acd1e03982cfcca14)
and updates the emission site in
[`welcome_sync.rs`](https://github.com/xmtp/libxmtp/pull/3268/files#diff-5ad5d6ca4506c4960727c32b22b9168a128f14af4d61497cd168ba5c80fb43f5).
- Behavioral Change: any log consumers filtering on the
`ProcessedWelcome` event name must update to `ReceivedWelcome`.

<!-- Macroscope's review summary starts here -->

<sup><a href="https://app.macroscope.com">Macroscope</a> summarized
f773819.</sup>
<!-- Macroscope's review summary ends here -->

<!-- macroscope-ui-refresh -->
<!-- Macroscope's pull request summary ends here -->
## Summary

Several default RPC endpoints in `chain_urls_default.json` are broken or
unreliable in production, causing identity update validation failures:

| Chain | Old | New | Reason |
|---|---|---|---|
| eip155:137 (Polygon) | `polygon.llamarpc.com` |
`polygon.publicnode.com` | DNS failure |
| eip155:42161 (Arbitrum) | `arbitrum.llamarpc.com` |
`arb1.arbitrum.io/rpc` | DNS failure |
| eip155:1 (Ethereum) | `eth.llamarpc.com` |
`ethereum-rpc.publicnode.com` | Cloudflare 429 rate limit under load |
| eip155:8453 (Base) | `base.llamarpc.com` | `mainnet.base.org` |
Cloudflare 429 rate limit under load |
| eip155:10 (Optimism) | `rpc.ankr.com/optimism` | `mainnet.optimism.io`
| Ankr started requiring API keys |

All new endpoints verified responding with correct chain IDs.
## Summary

Adds a generic, binding-agnostic builder pattern macro system (`napi_builder`, `wasm_builder`, `uniffi_builder`) for cross-platform bindings in libxmtp.

- **`crates/xmtp_macro/src/builder.rs`** — Core builder expansion engine driven by `AnnotationConfig` (struct/impl/constructor/setter annotations, setter style, prefix). Fully binding-agnostic.
- **`SetterStyle` enum** — `NapiThis` (NAPI `This<'scope>` injection for JS chaining), `Consuming` (wasm_bindgen `mut self -> Self`), `MutRefChain` (`&mut self -> &mut Self` for UniFFI/tests).
- **`setter_prefix`** — `"set_"` for NAPI/WASM (avoids conflicts with auto-generated field property getters), `""` for UniFFI.
- **`setter_impl_ann`** — Splits constructor and setter impl blocks for UniFFI (Arc<Self> incompatible with `&mut self`).
- **Field modes** — `required` (constructor param), `optional` (Option<T> with setter), `default` (literal expression), `skip` (Default::default, no setter).
- Preserves non-builder struct-level attributes (e.g. `#[allow(dead_code)]`).

### Testing

- **12 macro unit tests** (`crates/xmtp_macro/src/builder_test.rs`) — field modes, setter styles, prefix, struct attributes
- **6 UniFFI Rust tests** (`bindings/mobile/src/builder_test.rs`) — constructor, setters, defaults, skip, chaining
- **4 Node TypeScript tests** (`bindings/node/test/Builder.test.ts`) — constructor, chaining, defaults via `yarn build:test`
- **4 WASM TypeScript tests** (`bindings/wasm/test/Builder.test.ts`) — same coverage, Chromium + Firefox via Playwright

## Test plan

- [x] `cargo test -p xmtp_macro` — 12 tests pass
- [x] `cargo test -p xmtpv3 --lib -- builder_test` — 6 tests pass
- [x] `dev/lint` — clean
- [x] Node TS tests pass (`yarn build:test && yarn test`)
- [x] WASM TS tests pass (`yarn build:test && yarn test`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
#3215)

## Summary

Introduces `BackendBuilder` and `Backend` types for Node and WASM bindings, enabling pre-configured API backend construction via the new builder macro system.

**Stacked on:** #3214 (cross-platform builder pattern macros)

### New types

- **`XmtpEnv`** enum in `xmtp_configuration` — 7 network environments (Local, Dev, Production, TestnetStaging, TestnetDev, Testnet, Mainnet) with centralized URL resolution from constants.
- **`BackendBuilder`** (Node + WASM) — Uses `napi_builder`/`wasm_builder` macros. Required `env` field, optional `api_url`, `gateway_host`, `readonly`, `app_version` setters, plus `authCallback`/`authHandle` methods. Builds a `Backend`.
- **`Backend`** — Wraps `XmtpClientBundle` with env/host getters. Passed to `createClientWithBackend()`.
- **`createClientWithBackend()`** (Node + WASM) — Creates a client from a pre-built Backend, reducing constructor params by extracting API config into the Backend.
- **`validate_and_resolve()`** in `xmtp_api_d14n::config` — Shared validation logic for env→URL resolution, `is_secure` inference, and auth requirement checking.

### Code deduplication

- Extracted shared helpers `build_store`, `parse_nonce`, and `create_client_inner` in Node bindings — both `createClient` and `createClientWithBackend` delegate to the same inner function.
- Extracted shared helpers `build_store` and `create_client_inner` in WASM bindings — same pattern.
- Made `v3_host` optional in `ClientBundleBuilder` (previously required) since `BackendBuilder` resolves it from `XmtpEnv`.

## Test plan

- [x] `cargo test -p xmtp_configuration` — XmtpEnv tests pass
- [x] `cargo check -p bindings_node` — compiles clean
- [x] `nix develop .#wasm -- cargo check -p bindings_wasm --target wasm32-unknown-unknown` — compiles clean
- [x] `dev/lint` — clean
- [x] All macro and mobile builder tests still pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…3217)

## Summary

- Update all static (free-standing) API functions in Node and WASM bindings to accept `&Backend` instead of raw `v3_host`/`gateway_host`/`is_secure` parameters
- Internally use `MessageBackendBuilder::from_bundle()` to create API clients from the pre-built `ClientBundle` inside Backend, consistent with `create_client_with_backend()`
- Remove `TrackedStatsClient` wrapping from these functions (no longer needed with `from_bundle()` path)

### Affected functions

**Node (`@xmtp/node-bindings`):**
| Function | Params removed |
|---|---|
| `getInboxIdForIdentifier` | `host`, `gatewayHost`, `isSecure` |
| `isInstallationAuthorized` | `host`, `gatewayHost` |
| `isAddressAuthorized` | `host`, `gatewayHost` |
| `revokeInstallationsSignatureRequest` | `host`, `gatewayHost` |
| `applySignatureRequest` | `host`, `gatewayHost` |
| `inboxStateFromInboxIds` | `host`, `gatewayHost` |

**WASM (`@xmtp/wasm-bindings`):**
| Function | Params removed |
|---|---|
| `getInboxIdForIdentifier` | `host`, `gatewayHost`, `isSecure` |
| `revokeInstallationsSignatureRequest` | `host`, `gatewayHost` |
| `applySignatureRequest` | `host`, `gatewayHost` |
| `inboxStateFromInboxIds` | `host`, `gatewayHost` |

All functions now take `backend: &Backend` as their first parameter instead.

## Test plan

- [x] `cargo check -p bindings_node` passes
- [x] `cargo check -p bindings_wasm --target wasm32-unknown-unknown` passes
- [x] `./dev/lint-rust` passes clean
- [ ] Downstream SDK tests updated to pass `Backend` instead of raw host strings

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@macroscopeapp macroscopeapp bot dismissed their stale review March 3, 2026 21:23

Dismissing my prior approval and re-evaluating approvability for da3a7ef

@claude
Copy link

claude bot commented Mar 3, 2026

Claude finished @github-actions[bot]'s task —— View job


PR Review Complete

Review Date: March 3, 2026, 21:24 UTC

This release PR (1.10.0) contains significant architectural changes beyond version bumps, contrary to the macroscopeapp review. I've identified several important concerns:


🔴 Critical Issues

1. Security: Mutex Poison Handling in Node Bindings (bindings/node/src/client/backend.rs:36-42)

The code uses .expect("lock poisoned") when mutex poisoning occurs, which will panic and crash the Node.js process. Since AuthCallback and AuthHandle contain sensitive authentication data, a panic could leak sensitive information in panic messages or logs.

*self.auth_callback.lock().expect("lock poisoned") = Some(callback.clone());

Recommendation: Return a proper error instead of panicking:

.map_err(|_| napi::Error::from_reason("Failed to acquire lock"))?

2. Security: TLS Validation Logic (crates/xmtp_api_d14n/src/config/backend_config.rs:22-25)

The is_url_secure() function only checks URL prefixes (https://, grpcs://) without validating the actual TLS configuration. This is insufficient for security-critical decisions.

Recommendation: Rename to has_secure_scheme() or add documentation clarifying this only checks the URL scheme, not actual TLS security.

3. Confusing Error Recovery Pattern (crates/xmtp_api_d14n/src/queries/client_bundle.rs:184-248)

The build() method silently ignores v3_host when gateway_host is set (line 186). This could confuse developers who set both parameters expecting hybrid mode.

Recommendation: Add a warning log or return an error when both are set to make the behavior explicit.


⚠️ High Priority Issues

4. Race Condition: consumed Flag Check (bindings/node/src/client/backend.rs:46-57)

The consumed flag check has a TOCTOU (time-of-check-time-of-use) race condition. Two threads could pass the check before either sets the flag.

let mut consumed = self.consumed.lock().map_err(...)?;
if *consumed { return Err(...); }
*consumed = true;

While unlikely in typical Node.js usage, this could cause issues in concurrent scenarios.

Recommendation: Use atomic operations or keep the lock held throughout the entire build process.

5. Missing Validation: Empty String Checks (crates/xmtp_api_d14n/src/config/backend_config.rs:35-46)

The validation accepts empty strings for api_url and gateway_host. This could lead to runtime errors when attempting connections.

Recommendation: Validate that strings are non-empty when provided.


📋 Medium Priority Issues

6. Test Coverage Gap

While the new builder macros have good test coverage (bindings/node/test/Builder.test.ts:20-24), the critical security path (auth + gateway validation) lacks dedicated tests.

Recommendation: Add tests for:

  • Auth callback/handle with missing gateway_host (should error)
  • Empty string validation
  • Concurrent build() calls

7. Inconsistent Error Messages

crates/xmtp_api_d14n/src/config/backend_config.rs:16-18 defines specific error types, but the Node.js binding translates these to generic strings, losing error context.


✅ Positive Observations

  • Well-structured builder macro architecture with clear separation of concerns
  • Comprehensive tests for builder patterns across all three bindings (Node/WASM/Mobile)
  • Good documentation in macro code
  • Type-safe API design with proper Option handling

📊 Summary

While this PR introduces a solid builder pattern architecture, the security-critical sections (authentication, TLS validation, mutex handling) need attention before release. The issues are fixable, but given this is a release PR, I recommend addressing the critical issues first.

Recommendation: Address critical issues #1-3 before merging to main.


@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 73.14991% with 283 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.38%. Comparing base (319b2e4) to head (da3a7ef).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
bindings/node/src/client/create_client.rs 0.00% 106 Missing ⚠️
bindings/node/src/client/backend.rs 0.00% 84 Missing ⚠️
crates/xmtp_macro/src/lib.rs 63.63% 24 Missing ⚠️
crates/xmtp_api_d14n/src/queries/client_bundle.rs 80.76% 15 Missing ⚠️
bindings/node/src/inbox_id.rs 0.00% 12 Missing ⚠️
bindings/node/src/client/options.rs 0.00% 11 Missing ⚠️
crates/xmtp_macro/src/builder.rs 94.11% 11 Missing ⚠️
bindings/node/src/signatures.rs 0.00% 8 Missing ⚠️
bindings/node/src/inbox_state.rs 0.00% 4 Missing ⚠️
crates/xmtp_api_d14n/src/queries/builder.rs 0.00% 4 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3261      +/-   ##
==========================================
- Coverage   73.52%   73.38%   -0.15%     
==========================================
  Files         452      452              
  Lines       56677    56832     +155     
==========================================
+ Hits        41673    41705      +32     
- Misses      15004    15127     +123     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

fixes device sync tests in mobile bindings, android, and ios so it
correctly verifies functionality

<!-- Macroscope's pull request summary starts here -->
<!-- Macroscope will only edit the content between these invisible
markers, and the markers themselves will not be visible in the GitHub
rendered markdown. -->
<!-- If you delete either of the start / end markers from your PR's
description, Macroscope will append its summary at the bottom of the
description. -->
> [!NOTE]
> ### Fix device sync mobile bindings tests for iOS, Android, and Rust
> - Adds new tests for the full device sync request flow in [Rust
bindings](https://github.com/xmtp/libxmtp/pull/3288/files#diff-04f42fcf088abf13f3a20c3e154feac6341b3e9938a0f46f831a23b21a0aed74),
[Android](https://github.com/xmtp/libxmtp/pull/3288/files#diff-33ca4980924b8d59d5ffc62a9e4dd6a5a30413b2183b9a946f9bba9faa3ac79f),
and
[iOS](https://github.com/xmtp/libxmtp/pull/3288/files#diff-c046ca278ac5c7d2a98b0d5353c906570b0a18bfe3a192448723a3ef4ceab6fa),
covering message replication, consent sync, and archive-based history
restore.
> - Replaces fixed delays with polling loops and explicit
`sendSyncRequest` calls to make tests deterministic and less flaky.
> - Adds archive upload/process tests (`testSyncDeviceArchive`) on both
Android and iOS that validate pre-installation history is restored via a
pinned archive.
> - Updates `getrandom` from 0.3 to 0.4 with the `sys_rng` feature in
the workspace hack crate to unblock builds.
> - Behavioral Change: `testDisablingHistoryTransferDoesNotTransfer` now
explicitly creates clients with `deviceSyncEnabled=false/true` and
tightens assertions around which messages are visible post-sync.
>
> <!-- Macroscope's review summary starts here -->
>
> <sup><a href="https://app.macroscope.com">Macroscope</a> summarized
190a4e7.</sup>
> <!-- Macroscope's review summary ends here -->
>
<!-- Macroscope's pull request summary ends here -->

---------

Co-authored-by: cameronvoell <[email protected]>
Co-authored-by: Dakota Brink <[email protected]>
Comment on lines +307 to 320
Client.create(
account = alixWallet,
options = createClientOptions(api = localApi, deviceSyncEnabled = false),
)
val alixGroup = alixClient.conversations.newGroup(listOf(boClient.inboxId))
val messageIdNotExpectedOnClient2 = alixGroup.send("hi")
delay(2000)
val initialMessageCount = alixGroup.messages().size
assertEquals(initialMessageCount, 1)
assertEquals(initialMessageCount, 2)
val alixClient2 =
Client.create(
account = alixWallet,
options =
ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
appContext = context,
dbEncryptionKey = dbEncryptionKey,
dbDirectory = context.filesDir.absolutePath.toString(),
),
options = createClientOptions(api = localApi, deviceSyncEnabled = true),
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low library/HistorySyncTest.kt:307

In testDisablingHistoryTransferDoesNotTransfer, alixClient and alixClient2 are created via direct Client.create() calls instead of the createClient() helper. This skips the cleanup tracking in createdClients, so dropLocalDatabaseConnection() is never called during tearDown(), leaving database connections and files leaked. Consider using createClient() to ensure automatic cleanup.

            val localApi = ClientOptions.Api(XMTPEnvironment.LOCAL, false)
-            val alixClient =
-                Client.create(
-                    account = alixWallet,
-                    options = createClientOptions(api = localApi, deviceSyncEnabled = false),
-                )
+            val alixClient = createClient(alixWallet, api = localApi, deviceSyncEnabled = false)
             val alixGroup = alixClient.conversations.newGroup(listOf(boClient.inboxId))
             val messageIdNotExpectedOnClient2 = alixGroup.send("hi")
             delay(2000)
             val initialMessageCount = alixGroup.messages().size
             assertEquals(initialMessageCount, 2)
-            val alixClient2 =
-                Client.create(
-                    account = alixWallet,
-                    options = createClientOptions(api = localApi, deviceSyncEnabled = true),
-                )
+            val alixClient2 = createClient(alixWallet, api = localApi, deviceSyncEnabled = true)
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file sdks/android/library/src/androidTest/java/org/xmtp/android/library/HistorySyncTest.kt around lines 307-320:

In `testDisablingHistoryTransferDoesNotTransfer`, `alixClient` and `alixClient2` are created via direct `Client.create()` calls instead of the `createClient()` helper. This skips the cleanup tracking in `createdClients`, so `dropLocalDatabaseConnection()` is never called during `tearDown()`, leaving database connections and files leaked. Consider using `createClient()` to ensure automatic cleanup.

Evidence trail:
- HistorySyncTest.kt lines 306-310 and 318-322: Direct `Client.create()` calls creating `alixClient` and `alixClient2`
- BaseInstrumentedTest.kt line 25: `private val createdClients = mutableListOf<Client>()` - tracking list
- BaseInstrumentedTest.kt lines 67-74: `createClient()` helper that adds to tracking list via `createdClients.add(client)` at line 73
- BaseInstrumentedTest.kt lines 40-60: `tearDown()` method that calls `dropLocalDatabaseConnection()` only on clients in `createdClients` (line 45)

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Mar 12, 2026

Approvability

Verdict: Needs human review

This release PR (1.10.0) includes version bumps, new BackendBuilder abstractions, new builder macros, API surface changes, and documented breaking changes to history sync behavior. The automated release bot author has no code ownership of the modified files, so designated owners should verify this release before merging.

You can customize Macroscope's approvability policy. Learn more.

@cameronvoell
Copy link
Contributor

release changes merged to main via #3327

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants