Skip to content

System Overview

MeroKit is a thin composition of value-type clients over one URLSession transport, fronted by the Mero actor. The device never runs a node — every capability is an async HTTP(S) call to a remote one. It’s a faithful Swift port of the Mero.js wire contract.

import MeroKit
let mero = Mero(config: MeroConfig(
baseURL: URL(string: "https://your-node.example")!,
tokenStore: KeychainTokenStore()
))
try await mero.authenticate(Credentials(username: "alice", password: "s3cr3t"))
mero.auth // AuthApi — login, tokens, key management
mero.admin // AdminApi — contexts, apps, namespaces, groups, blobs, TEE
mero.rpc // RpcClient — execute WASM contract methods
mero.http // the transport in use (advanced callers)

For the visual layer map, see The device is a thin client on the home page.

Mero is declared as an actor, so its token state and refresh logic are race-free without locks. This matters for one thing above all: single-flight refresh. When several concurrent requests all get a 401, the actor serialises them so exactly one refresh runs; the rest await its result and retry with the rotated token. Refresh tokens are single-use, so this is what keeps concurrent traffic from revoking the token family. See the token lifecycle.

Practically, that means you await every instance member:

let authed = await mero.isAuthenticated
await mero.logout()

Transport — HttpClient / URLSessionHttpClient

Section titled “Transport — HttpClient / URLSessionHttpClient”

A URLSession-based client (URLSessionHttpClient) implementing the HttpClient protocol. It attaches Authorization: Bearer, runs the reactive 401 → refresh → retry cycle, handles the terminal x-auth-error cases, and retries transient network/5xx failures with backoff. Mero builds it from your MeroConfig and wires it with TransportHooks back into its own token state. Advanced callers can reach it as mero.http — see the error model and the transport types.

API clients — AuthApi, AdminApi, RpcClient

Section titled “API clients — AuthApi, AdminApi, RpcClient”

All three are lightweight Sendable structs built over the shared HttpClient; none manages tokens itself — the transport’s hooks do.

  • AuthApi (mero.auth) — the node’s /auth and identity/key endpoints: generateTokens, refreshToken, providers, and root/client key management. See the auth API reference.
  • AdminApi (mero.admin) — the node’s /admin-api surface: contexts, applications, packages, namespaces, groups, blobs, aliases, capabilities, metadata, upgrades/migration, and TEE. See the admin API reference.
  • RpcClient (mero.rpc) — JSON-RPC to /jsonrpc; executes WASM contract methods and decodes the result into your type. See executing methods.

Where tokens persist between launches. KeychainTokenStore (secure, backed by the iOS/macOS Keychain) or MemoryTokenStore (ephemeral, the default). Conform to the TokenStore protocol to use your own.

A separate library product (import MeroKitUI) with an @MainActor ObservableObject MeroClient plus drop-in MeroRootView / LoginView / HomeView — the native analog of mero-react’s MeroProvider/useMero + LoginModal. See the SwiftUI frontend guide.

No third-party packages. MeroKit is built entirely on the Apple platform SDKs:

Framework Used for
URLSession (Foundation) all HTTP requests
Foundation JSON coding, URLs, dates
Security the Keychain token store
SwiftUI the optional MeroKitUI layer

Swift 5.9+, iOS 15+ / macOS 12+, with Strict Concurrency enabled.

Every call is HTTP to a single remote merod node:

Client Node surface
mero.auth GET/POST /auth/*, /admin/keys*
mero.admin /admin-api/* (REST)
mero.rpc POST /jsonrpc (JSON-RPC)
mero.events(contextIds:) GET /sse + POST /sse/subscription (SSE stream)