D14z client prerelease updates
Introduction π
Purpose βΉοΈ
Scope π
How to use the Graphite Merge Queue
Add the label mergequeue to this PR to add it to the merge queue.
You must have a Graphite account in order to use the merge queue. Sign up using this link.
An organization admin has enabled the Graphite Merge Queue in this repository.
Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.
Claude finished @cameronvoell's task ββ View job
Code Review Complete β
Summary
This PR updates the XMTP iOS SDK with D14Z client prerelease changes, primarily focusing on API client caching improvements, a new message visibility options API, and a test for D14N staging testnet compatibility. Overall, the changes are well-structured and follow good practices.
π’ Strengths
1. API Client Caching Enhancement (Client.swift:96-133, 390-442)
- Excellent cache key design: The new
ApiClientCache.makeCacheKey()method properly incorporates all configuration parameters (v3Host, gatewayHost, isSecure, appVersion) to prevent cache collisions - Good documentation: Clear comments explain the caching strategy
- Proper actor isolation: Thread-safe implementation using Swift actors
2. MessageVisibilityOptions API (MessageVisibilityOptions.swift)
- Clean abstraction: New
MessageVisibilityOptionsstruct provides a clear API for controlling message push notifications - Good naming: The
shouldPushparameter is self-explanatory - Proper integration: Consistently integrated across Conversation, Dm, and Group types
3. Test Coverage (ClientTests.swift:345-372)
- Good addition: New test
testCreatesAD14NStagingClientvalidates integration with D14N staging environment - Uses production-like settings: Tests with
isSecure: trueand custom gateway URL
π‘ Issues & Concerns
1. Missing PR Description β οΈ
Location: PR body (Introduction, Purpose, Scope sections are empty)
Issue: The PR lacks any description of:
- What changes were made and why
- What the D14Z prerelease entails
- Breaking changes or migration notes
- Testing performed
Recommendation: Add a comprehensive PR description explaining:
## Introduction
D14Z prerelease updates for XMTP iOS SDK
## Purpose
- Improve API client caching to support gateway URLs
- Add MessageVisibilityOptions API for finer control over push notifications
- Validate compatibility with D14N staging testnet
## Scope
- API client caching refactor
- New MessageVisibilityOptions type
- Test coverage for D14N staging
2. Potential Breaking Change - Not Documented β οΈ
Location: Conversation.swift:140-154, 225-238
Issue: New visibilityOptions parameter added to prepareMessage() and send() methods. While it's optional (defaults to nil), this changes method signatures.
Example:
public func prepareMessage(
encodedContent: EncodedContent,
visibilityOptions: MessageVisibilityOptions? = nil // NEW parameter
) async throws -> String
Impact:
- Existing code will continue to work (backward compatible)
- However, developers should be informed about this new capability
Recommendation: Document this in release notes as a new feature, clarifying it's backward compatible.
3. Inconsistent Error Handling Pattern β οΈ
Location: Group.swift:334-343
Issue: Redundant try-catch that just rethrows:
do {
let opts = visibilityOptions?.toFfi() ?? FfiSendMessageOpts(shouldPush: true)
let messageId = try await ffiGroup.send(
contentBytes: encodedContent.serializedData(),
opts: opts
)
return messageId.toHex
} catch {
throw error // Just rethrows without adding value
}
Comparison: The equivalent code in Dm.swift:156-165 doesn't have this unnecessary wrapper.
Recommendation: Remove the do-catch block in Group.swift:334-343:
let opts = visibilityOptions?.toFfi() ?? FfiSendMessageOpts(shouldPush: true)
let messageId = try await ffiGroup.send(
contentBytes: encodedContent.serializedData(),
opts: opts
)
return messageId.toHex
4. Test Hardcodes Specific Gateway URL βΉοΈ
Location: ClientTests.swift:349
Issue: The test hardcodes a specific staging URL:
gatewayUrl: "https://payer.testnet-staging.xmtp.network:443"
Concern:
- If this URL changes, the test will break
- Other developers may not have access to this specific environment
Recommendation: Consider:
- Adding a comment explaining this is a specific test environment
- OR making this configurable via environment variables
- OR documenting required test infrastructure in CLAUDE.md or test documentation
5. libxmtp Version Discrepancy βΉοΈ
Location: Package.swift:27, XMTP.podspec:3
Observation:
- Package.swift still references:
swift-bindings-1.6.0-dev.c046238 - XMTP.podspec references:
4.6.0-dev
Question: Is this intentional? The version schemes differ:
- Package.swift:
1.6.0-dev.c046238(seems older) - Podspec:
4.6.0-dev(seems newer)
Recommendation: Verify version alignment. If intentional, add a comment explaining the different versioning schemes for Swift bindings vs. the SDK itself.
π Code Quality Observations
Positive Patterns:
- Consistent API design: The
MessageVisibilityOptionsparameter is consistently added across all conversation types - Good defaults: Default of
shouldPush: truemaintains expected behavior - Actor-based concurrency: Proper use of Swift actors for thread-safe caching
- Comprehensive logging: Good use of XMTPLogger for debugging (Client.swift:202-211)
Minor Style Issues:
- Inconsistent whitespace: Some methods have inconsistent indentation (acceptable for generated code like xmtpv3.swift, but manual code should be consistent)
- Long parameter lists: Some methods could benefit from parameter objects (e.g.,
ApiClientCache.makeCacheKeywith 4 parameters)
π Security Considerations
β No security concerns identified
- Encryption keys properly handled
- No secrets or credentials in code
- Gateway URLs are configuration, not secrets
- Actor isolation prevents race conditions in caching
β‘ Performance Considerations
β Performance improvements present
- Caching optimization: The improved cache key generation prevents unnecessary API client creation
- Potential issue: Cache grows unbounded - consider adding cache eviction policy if many different gateway/version combinations are used in practice
Recommendation: Consider adding cache size limits or LRU eviction if cache growth becomes an issue:
actor ApiClientCache {
private var apiClientCache: [String: (client: XmtpApiClient, lastUsed: Date)] = [:]
private let maxCacheSize = 10
// Add eviction logic when cache exceeds maxCacheSize
}
β Test Coverage Assessment
Good:
- New test for D14N staging environment
- Existing comprehensive client tests maintained
Could be improved:
- Missing tests for MessageVisibilityOptions: No tests verify that
shouldPush: falseactually prevents push notifications - Missing tests for cache key generation: No unit tests for
ApiClientCache.makeCacheKey()edge cases (nil handling, special characters in URLs, etc.) - No integration tests: The new gateway URL support isn't tested end-to-end beyond the staging test
Recommendation: Add tests:
func testMessageVisibilityOptions() async throws {
let opts = MessageVisibilityOptions(shouldPush: false)
XCTAssertFalse(opts.shouldPush)
XCTAssertEqual(opts.toFfi().shouldPush, false)
}
func testApiClientCacheKeyGeneration() {
let key1 = ApiClientCache.makeCacheKey(
v3Host: "host1", gatewayHost: nil,
isSecure: true, appVersion: nil
)
let key2 = ApiClientCache.makeCacheKey(
v3Host: "host1", gatewayHost: "gateway1",
isSecure: true, appVersion: nil
)
XCTAssertNotEqual(key1, key2)
}
π Action Items
High Priority:
- β οΈ Fill in PR description with Introduction, Purpose, and Scope
- β οΈ Remove unnecessary try-catch block in Group.swift:334-343
- β οΈ Verify and document version alignment between Package.swift and XMTP.podspec
Medium Priority:
- π Add tests for MessageVisibilityOptions functionality
- π Add tests for ApiClientCache.makeCacheKey() edge cases
- π Document the new feature in release notes or changelog
Low Priority:
- π‘ Consider cache eviction policy for unbounded cache growth
- π‘ Document or make configurable the hardcoded staging gateway URL in tests
β Verdict
Recommendation: APPROVE with minor changes
This PR introduces solid improvements to API client caching and adds a useful MessageVisibilityOptions API. The code quality is good, follows established patterns, and maintains backward compatibility. The main issues are:
- Missing PR description
- One unnecessary try-catch block
- Some missing test coverage
These are easily addressable and don't block the PR from being merged, but should be resolved before or shortly after merge.
Add prerelease gateway routing and message visibility controls across iOS client messaging and update binary target to swift-bindings-1.6.0-dev.c046238 with checksum c011e963334de61a3bf7d81164a127443c68486b3722912203a76ad2d0771d5f
This change introduces an optional ClientOptions.Api.gatewayUrl used in API client construction and caching, adds explicit FfiSendMessageOpts usage for message send paths with new MessageVisibilityOptions, regenerates FFI bindings to include updated send signatures and backend connection parameters, and bumps the CocoaPods spec for a prerelease. The package manifest is updated to consume a new prebuilt artifact with a specific version and checksum.
- Add
ClientOptions.Api.gatewayUrland cache keys that includev3Host,gatewayHost,isSecure, andappVersionviaApiClientCache.makeCacheKey, and updateClient.connectToApiBackend/Client.connectToSyncApiBackendto passv3HostandgatewayHost(Client.swift). - Route
MessageVisibilityOptionsthroughConversation.send/prepareMessageinto DM and Group paths (Conversation.swift). - Add visibility-aware send and prepare flows in
DmandGroup, derivingshouldPushvia codec and passingFfiSendMessageOptsto FFI send calls (Dm.swift, Group.swift). - Regenerate
xmtpv3bindings to useFfiSendMessageOpts, updated connect signature(v3Host,gatewayHost,isSecure,appVersion), addFfiCursor, non-optionalsequenceId,originatorId, and related changes (xmtpv3.swift). - Introduce
MessageVisibilityOptionswithshouldPushand FFI conversion (MessageVisibilityOptions.swift). - Update binary target URL and checksum in Package.swift and bump
XMTP.podspecto4.6.0-dev(XMTP.podspec). - Add a test covering gateway URL configuration in client creation (ClientTests.swift).
πWhere to Start
Start with the updated client connection and caching flow in Client.connectToApiBackend and ApiClientCache in Client.swift, then review the FFI signature changes in xmtpv3.swift to see how FfiSendMessageOpts and (v3Host,gatewayHost,isSecure,appVersion) propagate through send and connect paths.
π Macroscope summarized 4a8ee5d. 6 files reviewed, 8 issues evaluated, 6 issues filtered, 0 comments posted
ποΈ Filtered Issues
Sources/XMTPiOS/Client.swift β 0 comments posted, 4 evaluated, 2 filtered
- line 113: Cache key construction in
ApiClientCache.makeCacheKeycan collide for legitimate inputs. It uses a'|'delimiter and substitutes"none"for missing optionals. If any of the inputs contain a'|'character (e.g., a host or version string) or if a real gateway host/app version is literally"none", different configurations can yield identical cache keys, causing incorrect reuse of anXmtpApiClientacross distinct backends. Use an unambiguous encoding (e.g., JSON serialization of a struct, or escaping the delimiter) and avoid a sentinel like"none"βencodenilexplicitly. [ Low confidence ] - line 406: Ambiguous/misaligned connection configuration: both
v3Host(which in this code is a full URL including scheme and port viaapi.env.url) and a separateisSecureboolean are passed intoconnectToBackend. Ifv3Hostindicateshttp://β¦butisSecureistrue(or vice versa), the two sources of truth can contradict, leading to failed connections or confusing behavior depending on which parameter the backend honors. Enforce consistency by derivingisSecurefrom the URL or validating them together before callingconnectToBackendand surfacing a clear error if they mismatch. [ Low confidence ]
Sources/XMTPiOS/Dm.swift β 0 comments posted, 2 evaluated, 2 filtered
- line 159: Defaulting
shouldPushtotruewhenvisibilityOptionsis omitted inDm.send(encodedContent:visibilityOptions:)can cause unintended push notifications and breaks contract parity with the genericsend<T>(content:options:)path, which derivesshouldPushfrom the codec viaencodeContent. If a caller sends a pre-encodedEncodedContentwithout specifyingvisibilityOptions, the message will always push, even if the codec'sshouldPushfor that content type would befalse. This creates divergent behavior between the encoded and generic content paths and can lead to externally visible side effects (push notifications) that the caller did not intend. [ Low confidence ] - line 224: Defaulting
shouldPushtotruewhenvisibilityOptionsis omitted inDm.prepareMessage(encodedContent:visibilityOptions:)can cause unintended push notifications and breaks parity withprepareMessage<T>(content:options:), which computesshouldPushfrom the codec viaencodeContent. Sending a pre-encodedEncodedContentwithoutvisibilityOptionswill always push, even if codec-derivedshouldPushwould befalse. [ Low confidence ]
Sources/XMTPiOS/Group.swift β 0 comments posted, 2 evaluated, 2 filtered
- line 335: Defaulting
shouldPushtotruewhenvisibilityOptionsis omitted inGroup.send(encodedContent:visibilityOptions:)can cause unintended push notifications and breaks parity withsend<T>(content:options:), which computesshouldPushviaencodeContent. A pre-encodedEncodedContentsent withoutvisibilityOptionswill always push, diverging from codec-derived behavior. [ Low confidence ] - line 403: Defaulting
shouldPushtotruewhenvisibilityOptionsis omitted inGroup.prepareMessage(encodedContent:visibilityOptions:)can cause unintended push notifications and breaks parity withprepareMessage<T>(content:options:), which computesshouldPushviaencodeContent. Pre-encoded messages withoutvisibilityOptionswill always push, potentially surprising callers and diverging from codec-derived behavior. [ Low confidence ]