Skip to content

SwiftUI Frontend

MeroKitUI is an optional SwiftUI layer that ships alongside the core SDK — an @MainActor observable MeroClient plus ready-made views. It’s the native analog of mero-react’s MeroProvider/useMero + LoginModal: wire it in and you get login → home routing on auth state for free.

import MeroKit // core SDK
import MeroKitUI // SwiftUI frontend

(Add the MeroKitUI library product alongside MeroKit — see install.)

MeroRootView routes between LoginView and HomeView based on client.isAuthenticated. Inject a MeroClient via .environmentObject:

import MeroKitUI
import SwiftUI
@main
struct MyApp: App {
@StateObject private var client = MeroClient()
var body: some Scene {
WindowGroup {
MeroRootView() // routes Login ⇄ Home on auth state
.environmentObject(client)
}
}
}
MeroClient@MainActor ObservableObject · @Published isAuthenticatedMeroRootViewroutes on client.isAuthenticatedenvironmentObjectfalseLoginViewnode URL · username · password→ client.login(…)trueHomeViewsession info · run demo RPC→ client.logout()

An @MainActor public final class MeroClient: ObservableObject wrapping a Mero. Bind its published state directly in your own views.

Published state (read-only from views):

@Published public private(set) var isAuthenticated: Bool
@Published public private(set) var isLoading: Bool
@Published public private(set) var nodeURL: String
@Published public private(set) var username: String
@Published public private(set) var errorMessage: String?
@Published public private(set) var lastRpcResult: String?

Methods (errors surface via errorMessage, so these don’t throw):

public init(session: URLSession? = nil,
tokenStore: @escaping @Sendable () -> any TokenStore = { MemoryTokenStore() })
func login(nodeURL: String, username: String, password: String,
bootstrapSecret: String? = nil) async
func runSampleRpc(contextId: String, method: String) async
func logout() async

Use it in your own SwiftUI view without the bundled screens:

struct SignInView: View {
@EnvironmentObject private var client: MeroClient
@State private var user = ""; @State private var pass = ""
var body: some View {
VStack {
TextField("Username", text: $user)
SecureField("Password", text: $pass)
Button("Sign in") {
Task { await client.login(nodeURL: "https://your-node.example",
username: user, password: pass) }
}
if let error = client.errorMessage { Text(error).foregroundStyle(.red) }
}
.disabled(client.isLoading)
}
}

All three are public Views that read the MeroClient from @EnvironmentObject:

View Purpose
MeroRootView(defaultNodeURL:) routes LoginViewHomeView on auth state
LoginView(defaultNodeURL:) credential form → client.login(...)
HomeView(demoContextId:demoMethod:) signed-in screen: session info, demo RPC, logout