Skip to content

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.

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"))

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 SwiftUI
import 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 LiveQuerysubscribe(_:) fires immediately and on every change, a 1:1 port of packages/runtime/src/live-query.ts.

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 + signature
try await conn.subscribe(room: docId)
conn.startStreaming()

XNetKit is a SwiftPM package that lives in the repository (not yet on a public index). Platforms: macOS 14, iOS 17, visionOS 1.

  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
    ]
  2. Build and run the bundled demos:

    Terminal window
    cd swift/XNetKit
    swift run xnet-demo # schema → signed writes → query → reactive loop
    swift test # 18 tests incl. golden vectors, wire codec, persistence