Swift — XNetKit
Native SDK · betapasses the golden vectors
XNetKit is a native Swift SDK for xNet’s local-first graph database. Define schemas in Swift, write and query the database in Swift, and bind results into a SwiftUI re-rendering loop — no JavaScript, no React. It’s built directly on the conformance-pinned protocol kernel, so it interoperates with the TypeScript reference byte-for-byte where it matters: identity, canonical change hashes, and LWW convergence.
Quick look
Section titled “Quick look”import XNetKit
// Identity — an Ed25519 did:key (would live in the Keychain in a real app).let me = Identity()
// Define a schema in Swift (the analogue of TS `defineSchema`).let Task = Schema(name: "Task", namespace: "xnet://xnet.fyi/", authorization: .spaceCascade(relation: "space")) { text("title", required: true, maxLength: 200) select("status", options: ["todo", "doing", "done"], default: "todo") relation("space", target: "xnet://xnet.fyi/Space@1.0.0") money("bounty", currency: "USD")}Task.id // "xnet://xnet.fyi/Task@1.0.0"
// A local store owned by `me`. Every write signs a Change and folds it via LWW.// Pass a SQLiteChangeLog to persist — state replays from it on next launch.let store = NodeStore(identity: me, persistence: SQLiteChangeLog(path: dbPath))let task = store.create(Task, ["title": "Ship the Swift SDK", "status": "todo"])store.update(task.id, ["status": "doing"])
// Query the database in Swift.let todo = store.query(Query(Task, where: .equals("status", "todo")).ordered(by: "title"))The native re-render loop (SwiftUI)
Section titled “The native re-render loop (SwiftUI)”LiveQueryModel is an @Observable analogue of React’s useQuery: a SwiftUI
view reads model.rows and re-renders automatically whenever the result
changes — no hooks, no manual subscriptions.
import SwiftUIimport XNetKit
struct TaskListView: View { @State private var model: LiveQueryModel
init(store: NodeStore, schema: Schema) { _model = State(initialValue: LiveQueryModel( store, Query(schema, where: .equals("status", "todo")).ordered(by: "title"))) }
var body: some View { List(model.rows) { node in Text(node["title"]?.stringValue ?? "") } }}Headless, the same reactivity is the framework-agnostic LiveQuery —
subscribe(_:) fires immediately and on every change, a 1:1 port of
packages/runtime/src/live-query.ts.
Live sync with an xNet hub
Section titled “Live sync with an xNet hub”HubConnection speaks the L2 replication wire protocol
over a WebSocket — and it’s proven against the real TypeScript hub. The
xnet-sync-demo target has a Swift client sign a change, publish it to the hub
(which verifies the hash + Ed25519 signature), a second Swift client catch up and
materialize the node, then receive a live relayed update the moment the
writer publishes — a true cross-language, real-time round-trip.
let conn = HubConnection(url: URL(string: "wss://hub.xnet.app")!, did: identity.did)try await conn.connect()store.onLocalChange = { change in Task { try await conn.publish(change, room: docId) } }conn.onRemoteChange = { change in store.apply(change) } // verifies hash + signaturetry await conn.subscribe(room: docId)conn.startStreaming()Install
Section titled “Install”XNetKit is a SwiftPM package that lives in the repository (not yet on a public index). Platforms: macOS 14, iOS 17, visionOS 1.
-
Add it as a local or git package dependency in your
Package.swift:dependencies: [.package(url: "https://github.com/crs48/xNet.git", branch: "main")// then reference the "XNetKit" product from swift/XNetKit] -
Build and run the bundled demos:
Terminal window cd swift/XNetKitswift run xnet-demo # schema → signed writes → query → reactive loopswift test # 18 tests incl. golden vectors, wire codec, persistence