### Monitor WebSocket Connection State Source: https://context7.com/get-convex/convex-swift/llms.txt Use watchWebSocketState() to get a publisher that emits connection status changes. This is useful for displaying network status indicators to the user. You can observe transitions using Combine or async/await. ```swift import ConvexMobile import Combine let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") var cancellables = Set() client.watchWebSocketState() .sink { state in switch state { case .connecting: print("Connecting to Convex…") case .connected: print("Connected!") default: print("State: \(state)") } } .store(in: &cancellables) // Observe the first two state transitions using async/await let publisher = client.watchWebSocketState() var states: [WebSocketState] = [] for await state in publisher.prefix(2).values { states.append(state) } // states == [.connecting, .connected] ``` -------------------------------- ### Create ConvexClient Instance in Swift Source: https://context7.com/get-convex/convex-swift/llms.txt Instantiate the primary entry point, ConvexClient, once for your application. Use your Convex deployment URL obtained from the Convex dashboard. ```swift import ConvexMobile // Create a single shared client let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") ``` -------------------------------- ### ConvexClient Initialization Source: https://context7.com/get-convex/convex-swift/llms.txt Instantiate the ConvexClient once with your deployment URL and reuse it throughout your application. This is the primary entry point for interacting with the Convex backend. ```APIDOC ## ConvexClient — Creating a Client `ConvexClient` is the primary entry point. Instantiate it once with your deployment URL (found in the Convex dashboard under **Settings**) and reuse it throughout your app. ```swift import ConvexMobile // Create a single shared client let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") ``` ``` -------------------------------- ### Subscribe to Data and Perform Mutation in Swift Source: https://github.com/get-convex/convex-swift/blob/main/README.md Demonstrates how to subscribe to real-time data changes and execute a mutation with arguments. Ensure you have imported ConvexMobile and defined your data structure. The subscription loop processes updates as they arrive, and the mutation call sends data to the Convex backend. ```swift import ConvexMobile struct YourData: Decodable { let foo: String @ConvexInt var bar: Int } let client = ConvexClient(deploymentUrl: "your convex deployment URL") let yourData = client.subscribe(to: "your:data", yielding: YourData?.self) .replaceError(with: nil) .values for await latestValue in yourData { // Do something with the latest `YourData?` value here. // The loop body will execute each time the "your:data" query result changes. } try await client.mutation("your:mutation", with: ["anotherArg": "anotherVal", "anInt": 42]) ``` -------------------------------- ### Execute an Action with `action(_:with:)` Source: https://context7.com/get-convex/convex-swift/llms.txt Use `action` to execute serverless functions that can interact with third-party APIs or perform side-effects. The API is similar to `mutation`. Ensure the `ConvexClient` is initialized with your deployment URL. ```swift import ConvexMobile let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") struct SearchResult: Decodable { let title: String let url: String } // Action that returns a value do { let results: [SearchResult] = try await client.action( "search:query", with: ["q": "convex swift", "limit": 10] ) results.forEach { print("\($0.title) — \($0.url)") } } catch let ClientError.ConvexError(data) { print("Application-level error from action: \(data)") } catch { print("Unexpected: \(error)") } // Action with no return value try await client.action("email:sendWelcome", with: ["userId": "abc123"]) // Passing special floating-point values (NaN, ±Infinity are encoded correctly) struct FloatArgs: ConvexEncodable { // Use individual ConvexEncodable values in a dictionary } let result: String = try await client.action( "math:process", with: ["value": Double.infinity, "fallback": 0.0] ) ``` -------------------------------- ### Execute a Mutation with `mutation(_:with:)` Source: https://context7.com/get-convex/convex-swift/llms.txt Use `mutation` to perform transactional writes to the Convex database. It can return a decoded `Decodable` result or be used for fire-and-forget operations. Ensure the `ConvexClient` is initialized with your deployment URL. ```swift import ConvexMobile let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") struct NewMessage: Decodable { let id: String @ConvexInt var position: Int enum CodingKeys: String, CodingKey { case id = "_id" case position } } // Mutation that returns a value do { let result: NewMessage = try await client.mutation( "messages:send", with: ["author": "Alice", "body": "Hello, world!"] ) print("Inserted at position \(result.position), id=\(result.id)") } catch let error as ClientError { print("Convex error: \(error)") } catch { print("Unexpected error: \(error)") } // Mutation that returns nothing (fire-and-forget) try await client.mutation("messages:clearAll") // Passing integer arguments (uses ConvexEncodable encoding) try await client.mutation("counter:increment", with: ["amount": 5]) ``` -------------------------------- ### `action(_:with:)` — Execute an Action Source: https://context7.com/get-convex/convex-swift/llms.txt Executes a named Convex action, which runs in a serverless environment. Actions can perform side-effects, call third-party APIs, and return results. ```APIDOC ## `action(_:with:)` — Execute an Action Executes a named Convex action. Actions run in a serverless environment and can call third-party APIs, perform side-effects, and return results. The API mirrors `mutation`. ### Usage ```swift // Action that returns a value do { let results: [SearchResult] = try await client.action( "search:query", with: ["q": "convex swift", "limit": 10] ) results.forEach { print("\($0.title) — \($0.url)") } } catch let ClientError.ConvexError(data) { print("Application-level error from action: \(data)") } catch { print("Unexpected: \(error)") } // Action with no return value try await client.action("email:sendWelcome", with: ["userId": "abc123"]) // Passing special floating-point values (NaN, ±Infinity are encoded correctly) let result: String = try await client.action( "math:process", with: ["value": Double.infinity, "fallback": 0.0] ) ``` ### Parameters - `name`: The name of the action to execute. - `args`: A dictionary of arguments to pass to the action. ``` -------------------------------- ### Authenticated Client with AuthProvider Source: https://context7.com/get-convex/convex-swift/llms.txt Use ConvexClientWithAuth to integrate with any OIDC/OAuth provider for authentication. Implement the AuthProvider protocol and observe authentication state changes via the authState publisher. ```swift import ConvexMobile import Auth0 // Example; any OIDC/OAuth provider works // 1. Implement AuthProvider for your auth SDK class Auth0Provider: AuthProvider { typealias T = Credentials // Auth0 Credentials type private var storedOnIdToken: (@Sendable (String?) -> Void)? func login(onIdToken: @Sendable @escaping (String?) -> Void) async throws -> Credentials { storedOnIdToken = onIdToken let credentials = try await Auth0.webAuth().start() onIdToken(credentials.idToken) return credentials } func loginFromCache(onIdToken: @Sendable @escaping (String?) -> Void) async throws -> Credentials { storedOnIdToken = onIdToken let credentials = try await Auth0.credentialsManager.credentials() onIdToken(credentials.idToken) return credentials } func logout() async throws { try await Auth0.webAuth().clearSession() } func extractIdToken(from authResult: Credentials) -> String { return authResult.idToken } } // 2. Create the authenticated client let authProvider = Auth0Provider() let client = ConvexClientWithAuth( deploymentUrl: "https://your-deployment.convex.cloud", authProvider: authProvider ) // 3. Observe auth state changes var cancellables = Set() client.authState.sink { state in switch state { case .loading: print("Authenticating…") case .authenticated(let creds): print("Logged in: \(creds.idToken.prefix(10))…") case .unauthenticated: print("Logged out") } }.store(in: &cancellables) // 4. Trigger login (interactive) or restore from cache (silent) let result = await client.loginFromCache() // Try silent first if case .failure = result { await client.login() // Fall back to interactive } // 5. Normal queries/mutations/actions now include the auth token automatically let profile: UserProfile = try await client.action("users:me") // 6. Logout await client.logout() ``` -------------------------------- ### Subscribe to Convex Queries with Combine in Swift Source: https://context7.com/get-convex/convex-swift/llms.txt Subscribe to a Convex query and receive real-time updates via Combine publishers. Handles automatic subscription cancellation when no longer needed. Supports decoding results into Decodable Swift structs. ```swift import ConvexMobile import Combine struct Message: Decodable, Equatable { let author: String let body: String } let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") // Subscribe to a query with no arguments — receives live updates let messagePublisher: AnyPublisher<[Message]?, ClientError> = client.subscribe(to: "messages:list") // Consume using async/await for-loop (swift-concurrency) let safePublisher = messagePublisher.replaceError(with: nil).values for await messages in safePublisher { print("Current messages: \(messages ?? [])") // Loop body re-executes every time the backend result changes } // --- Or use Combine's sink --- var cancellables = Set() client.subscribe(to: "messages:list", yielding: [Message]?.self) .replaceError(with: nil) .sink { messages in print("Updated: \(messages ?? [])") } .store(in: &cancellables) // Subscribe with arguments (filter on the server) client.subscribe(to: "messages:byAuthor", with: ["author": "Alice"]) .replaceError(with: nil) .sink { (messages: [Message]?) in print("Alice's messages: \(messages ?? [])") } .store(in: &cancellables) // Handle errors explicitly client.subscribe(to: "messages:list", with: ["forceError": true]) .sink( receiveCompletion: { completion in if case .failure(let err) = completion { switch err { case .ConvexError(let data): print("App error: \(data)") case .ServerError(let msg): print("Server error: \(msg)") case .InternalError(let msg): print("Internal error: \(msg)") } } }, receiveValue: { (messages: [Message]?) in print(messages ?? []) } ) .store(in: &cancellables) ``` -------------------------------- ### subscribe(to:with:yielding:) - Reactive Query Subscriptions Source: https://context7.com/get-convex/convex-swift/llms.txt Subscribes to a Convex query and returns an `AnyPublisher` that emits new values whenever the server-side query result changes. The subscription is automatically cancelled when no subscribers are active. ```APIDOC ## subscribe(to:with:yielding:) — Reactive Query Subscriptions Subscribes to a Convex query and returns an `AnyPublisher` that emits a new value every time the server-side query result changes. The upstream Convex subscription is automatically cancelled when all downstream subscribers stop listening. ```swift import ConvexMobile import Combine struct Message: Decodable, Equatable { let author: String let body: String } let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") // Subscribe to a query with no arguments — receives live updates let messagePublisher: AnyPublisher<[Message]?, ClientError> = client.subscribe(to: "messages:list") // Consume using async/await for-loop (swift-concurrency) let safePublisher = messagePublisher.replaceError(with: nil).values for await messages in safePublisher { print("Current messages: \(messages ?? [])") // Loop body re-executes every time the backend result changes } // --- Or use Combine's sink --- var cancellables = Set() client.subscribe(to: "messages:list", yielding: [Message]?.self) .replaceError(with: nil) .sink { messages in print("Updated: \(messages ?? [])") } .store(in: &cancellables) // Subscribe with arguments (filter on the server) client.subscribe(to: "messages:byAuthor", with: ["author": "Alice"]) .replaceError(with: nil) .sink { (messages: [Message]?) in print("Alice's messages: \(messages ?? [])") } .store(in: &cancellables) // Handle errors explicitly client.subscribe(to: "messages:list", with: ["forceError": true]) .sink( receiveCompletion: { completion in if case .failure(let err) = completion { switch err { case .ConvexError(let data): print("App error: \(data)") case .ServerError(let msg): print("Server error: \(msg)") case .InternalError(let msg): print("Internal error: \(msg)") } } }, receiveValue: { (messages: [Message]?) in print(messages ?? []) } ) .store(in: &cancellables) ``` ``` -------------------------------- ### `@ConvexFloat` — Decoding Floating-Point Values Source: https://context7.com/get-convex/convex-swift/llms.txt A property wrapper for decoding Convex floating-point numbers, including special values like NaN and Infinity. ```APIDOC ## `@ConvexFloat` — Decoding Floating-Point Values A property wrapper for decoding Convex floating-point numbers. Regular finite floats decode from plain JSON numbers; special values (`NaN`, `±Infinity`) decode from a `{"$": ""}` envelope. ### Usage ```swift struct Measurement: Decodable { let label: String @ConvexFloat var value: Double @ConvexFloat var precision: Float // Optional variants for nullable fields @OptionalConvexFloat var upperBound: Double? @OptionalConvexFloat var lowerBound: Float? } let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") let measurement: Measurement = try await client.action("sensors:latest") print("\(measurement.label): \(measurement.value) ± \(measurement.precision)") // Special floats round-trip correctly struct Thresholds: Decodable, Equatable { @ConvexFloat var max: Double // Can be Double.infinity @ConvexFloat var sentinel: Float // Can be Float.nan } let t: Thresholds = try await client.action( "config:thresholds", with: ["sentinel": Float.nan, "max": Double.infinity] ) print(t.max.isInfinite) // true print(t.sentinel.isNaN) // true ``` ``` -------------------------------- ### ConvexClientWithAuth - Authenticated Client Source: https://context7.com/get-convex/convex-swift/llms.txt A subclass of `ConvexClient` that integrates with an `AuthProvider` to automatically attach JWT tokens to all backend requests. It also provides an `authState` publisher for observing authentication state transitions. ```APIDOC ## `ConvexClientWithAuth` — Authenticated Client A subclass of `ConvexClient` that integrates with an `AuthProvider` to attach JWT tokens to all backend requests. Exposes an `authState: AnyPublisher, Never>` publisher for observing authentication transitions. ```swift import ConvexMobile import Auth0 // Example; any OIDC/OAuth provider works // 1. Implement AuthProvider for your auth SDK class Auth0Provider: AuthProvider { typealias T = Credentials // Auth0 Credentials type private var storedOnIdToken: (@Sendable (String?) -> Void)? func login(onIdToken: @Sendable @escaping (String?) -> Void) async throws -> Credentials { storedOnIdToken = onIdToken let credentials = try await Auth0.webAuth().start() onIdToken(credentials.idToken) return credentials } func loginFromCache(onIdToken: @Sendable @escaping (String?) -> Void) async throws -> Credentials { storedOnIdToken = onIdToken let credentials = try await Auth0.credentialsManager.credentials() onIdToken(credentials.idToken) return credentials } func logout() async throws { try await Auth0.webAuth().clearSession() } func extractIdToken(from authResult: Credentials) -> String { return authResult.idToken } } // 2. Create the authenticated client let authProvider = Auth0Provider() let client = ConvexClientWithAuth( deploymentUrl: "https://your-deployment.convex.cloud", authProvider: authProvider ) // 3. Observe auth state changes var cancellables = Set() client.authState.sink { state in switch state { case .loading: print("Authenticating…") case .authenticated(let creds): print("Logged in: \(creds.idToken.prefix(10))…") case .unauthenticated: print("Logged out") } }.store(in: &cancellables) // 4. Trigger login (interactive) or restore from cache (silent) let result = await client.loginFromCache() // Try silent first if case .failure = result { await client.login() // Fall back to interactive } // 5. Normal queries/mutations/actions now include the auth token automatically let profile: UserProfile = try await client.action("users:me") // 6. Logout await client.logout() ``` ``` -------------------------------- ### watchWebSocketState() - Monitor Connection State Source: https://context7.com/get-convex/convex-swift/llms.txt Returns an `AnyPublisher` that emits connectivity state changes, such as `connecting` and `connected`. This is useful for displaying network status indicators to the user. ```APIDOC ## `watchWebSocketState()` — Monitor Connection State Returns an `AnyPublisher` that emits connectivity state changes (`connecting`, `connected`, etc.), useful for showing network status indicators. ```swift import ConvexMobile import Combine let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") var cancellables = Set() client.watchWebSocketState() .sink { state in switch state { case .connecting: print("Connecting to Convex…") case .connected: print("Connected!") default: print("State: \(state)") } } .store(in: &cancellables) // Observe the first two state transitions using async/await let publisher = client.watchWebSocketState() var states: [WebSocketState] = [] for await state in publisher.prefix(2).values { states.append(state) } // states == [.connecting, .connected] ``` ``` -------------------------------- ### `mutation(_:with:)` — Execute a Mutation Source: https://context7.com/get-convex/convex-swift/llms.txt Executes a named Convex mutation for transactional writes to the database. It can return a decoded result or be used for fire-and-forget operations. ```APIDOC ## `mutation(_:with:)` — Execute a Mutation Executes a named Convex mutation and either returns a decoded `Decodable` result or discards it. Mutations are transactional writes to the Convex database. ### Usage ```swift // Mutation that returns a value do { let result: NewMessage = try await client.mutation( "messages:send", with: ["author": "Alice", "body": "Hello, world!"] ) print("Inserted at position \(result.position), id=\(result.id)") } catch let error as ClientError { print("Convex error: \(error)") } catch { print("Unexpected error: \(error)") } // Mutation that returns nothing (fire-and-forget) try await client.mutation("messages:clearAll") // Passing integer arguments (uses ConvexEncodable encoding) try await client.mutation("counter:increment", with: ["amount": 5]) ``` ### Parameters - `name`: The name of the mutation to execute. - `args`: A dictionary of arguments to pass to the mutation. ``` -------------------------------- ### `@ConvexInt` — Decoding Integer Values Source: https://context7.com/get-convex/convex-swift/llms.txt A property wrapper for decoding Convex integers, which are transmitted as base64-encoded 64-bit values. ```APIDOC ## `@ConvexInt` — Decoding Integer Values A property wrapper for decoding Convex integers, which are transmitted as base64-encoded 64-bit values in a `{"$": ""}` envelope rather than plain JSON numbers. ### Usage ```swift // Required for any Int, Int32, or Int64 field coming from Convex struct Counter: Decodable { let name: String @ConvexInt var count: Int @ConvexInt var version: Int64 @ConvexInt var smallCount: Int32 enum CodingKeys: String, CodingKey { case name case count case version case smallCount } } // For optional integers use @OptionalConvexInt struct Stats: Decodable { @OptionalConvexInt var highScore: Int? @OptionalConvexInt var streak: Int32? enum CodingKeys: String, CodingKey { case highScore case streak } } let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") let counter: Counter = try await client.action("counters:get", with: ["name": "visits"]) print("Visit count: \(counter.count)") ``` ``` -------------------------------- ### Add Convex Swift Package to Xcode Project Source: https://context7.com/get-convex/convex-swift/llms.txt Add the Convex Swift client library to your Xcode project using Swift Package Manager. This is the standard way to include external dependencies in your Swift projects. ```swift // Package.swift dependencies: [ .package(url: "https://github.com/get-convex/convex-swift", from: "0.8.1") ], targets: [ .target(name: "YourApp", dependencies: ["ConvexMobile"]) ] ``` -------------------------------- ### Decode Convex Floating-Point Values with `@ConvexFloat` Source: https://context7.com/get-convex/convex-swift/llms.txt Use the `@ConvexFloat` property wrapper to decode floating-point numbers from Convex. Special values like `NaN` and `±Infinity` are decoded from a `{" $float": ""}` envelope. Use `@OptionalConvexFloat` for nullable fields. ```swift import ConvexMobile struct Measurement: Decodable { let label: String @ConvexFloat var value: Double @ConvexFloat var precision: Float // Optional variants for nullable fields @OptionalConvexFloat var upperBound: Double? @OptionalConvexFloat var lowerBound: Float? } let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") let measurement: Measurement = try await client.action("sensors:latest") print("\(measurement.label): \(measurement.value) ± \(measurement.precision)") // Special floats round-trip correctly struct Thresholds: Decodable, Equatable { @ConvexFloat var max: Double // Can be Double.infinity @ConvexFloat var sentinel: Float // Can be Float.nan } let t: Thresholds = try await client.action( "config:thresholds", with: ["sentinel": Float.nan, "max": Double.infinity] ) print(t.max.isInfinite) // true print(t.sentinel.isNaN) // true ``` -------------------------------- ### ConvexEncodable - Encoding Arguments Source: https://context7.com/get-convex/convex-swift/llms.txt Types must conform to `ConvexEncodable` to be passed as arguments to queries, mutations, or actions. Common Swift types have built-in conformances. Custom types can implement `convexEncode() throws -> String`. ```APIDOC ## `ConvexEncodable` — Encoding Arguments Protocol that types must conform to in order to be passed as query/mutation/action arguments. All common Swift types have built-in conformances; custom types can conform by implementing `convexEncode() throws -> String`. ```swift import ConvexMobile // Built-in conformances: Int, Int32, Int64, Float, Double, Bool, String, // [String: ConvexEncodable?], [ConvexEncodable?] let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") // String, Bool, numeric values try await client.mutation("log:record", with: [ "message": "Hello", "level": 3, // Int → encoded as {"$integer": ...} "score": 9.8, // Double → plain JSON number "active": true, "tag": nil // Optional → encodes as JSON null ]) // Nested dictionaries and arrays try await client.mutation("data:save", with: [ "metadata": ["source": "ios", "version": 2] as [String: ConvexEncodable?], "tags": (["swift", "mobile", nil] as [ConvexEncodable?]) ]) // Custom struct encoding — build the args dict manually struct CreateUser { let name: String let age: Int let score: Double func toArgs() -> [String: ConvexEncodable?] { ["name": name, "age": age, "score": score] } } let user = CreateUser(name: "Bob", age: 30, score: 98.6) try await client.mutation("users:create", with: user.toArgs()) ``` ``` -------------------------------- ### Encoding Arguments with ConvexEncodable Source: https://context7.com/get-convex/convex-swift/llms.txt Conform to ConvexEncodable to pass custom types as arguments. Built-in types like Int, String, and Bool are supported directly. Custom structs can be encoded by manually building a dictionary of arguments. ```swift import ConvexMobile // Built-in conformances: Int, Int32, Int64, Float, Double, Bool, String, // [String: ConvexEncodable?], [ConvexEncodable?] let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") // String, Bool, numeric values try await client.mutation("log:record", with: [ "message": "Hello", "level": 3, // Int → encoded as {"$integer": ...} "score": 9.8, // Double → plain JSON number "active": true, "tag": nil // Optional → encodes as JSON null ]) // Nested dictionaries and arrays try await client.mutation("data:save", with: [ "metadata": ["source": "ios", "version": 2] as [String: ConvexEncodable?], "tags": (["swift", "mobile", nil] as [ConvexEncodable?]) ]) // Custom struct encoding — build the args dict manually struct CreateUser { let name: String let age: Int let score: Double func toArgs() -> [String: ConvexEncodable?] { ["name": name, "age": age, "score": score] } } let user = CreateUser(name: "Bob", age: 30, score: 98.6) try await client.mutation("users:create", with: user.toArgs()) ``` -------------------------------- ### Decode Convex Integers with `@ConvexInt` Source: https://context7.com/get-convex/convex-swift/llms.txt Use the `@ConvexInt` property wrapper to decode integer values from Convex, which are transmitted as base64-encoded 64-bit values. This is required for `Int`, `Int32`, or `Int64` fields. For optional fields, use `@OptionalConvexInt`. ```swift import ConvexMobile // Required for any Int, Int32, or Int64 field coming from Convex struct Counter: Decodable { let name: String @ConvexInt var count: Int @ConvexInt var version: Int64 @ConvexInt var smallCount: Int32 enum CodingKeys: String, CodingKey { case name case count case version case smallCount } } // For optional integers use @OptionalConvexInt struct Stats: Decodable { @OptionalConvexInt var highScore: Int? // nil if field absent or null @OptionalConvexInt var streak: Int32? enum CodingKeys: String, CodingKey { case highScore case streak } } let client = ConvexClient(deploymentUrl: "https://your-deployment.convex.cloud") let counter: Counter = try await client.action("counters:get", with: ["name": "visits"]) print("Visit count: \(counter.count)") // Correctly decoded from base64 integer wire format ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.