The SPL (solstone private link) client library for Apple platforms, as a Swift package. Module name: SPLTunnel.
SPL is the encrypted connection between a solstone observer app and the owner's journal: mutual TLS with a pairing-minted client certificate, carried over a direct LAN connection or a WebSocket relay when no direct path exists. This package implements the client side end to end: pair-link parsing and the pairing ceremony, candidate racing, inner mTLS, stream multiplexing with flow control, device-token refresh, keychain-stored pairing state, and the local loopback proxy that carries application HTTP over the tunnel.
The wire protocol is specified in the proto/ directory of solpbc/spl. Those documents are the source of truth for all wire behavior here. Conformance tests cite the exact proto line ranges they pin, including direct pair-link local-address refusal, and the remaining client-surface gaps are documented explicitly: the undocumented 0x05 multi-candidate pair-link form and RESET receiver payload-length tolerance where the framing doc is silent.
Alpha. This package is the shared successor to the tunnel implementations previously vendored inside solstone-macos and solstone-swift; app migration is operator-driven and version-tagged.
- Swift 6.2 toolchain
- macOS 15+ / iOS 26+
- Only dependency: swift-crypto
make install # resolve dependencies
make test # unit tests (macOS destination)
make ci # hygiene gates + build + tests on macOS and iOS SimulatorTests use Swift Testing. Local integration suites are disabled unless SPL_INTEGRATION=1 is set. Live interop is disabled unless SPL_LIVE=1 is set and both SPL_PAIR_URL and SPL_RELAY_ENDPOINT are supplied explicitly; there is no baked relay default.
Platform differences are configuration, not conditionals. Consuming apps supply:
KeychainPolicythroughSPLKeychainStore(policy:), includingservice,account, optionalaccessGroup,useDataProtectionKeychain, andaccessibility.SessionPolicy, composed fromRacePolicyandKeepalivePolicy, whenTunnelSessionorTunnelSupervisorneeds non-default timing.- Apps that own their own reconnect loop drive
ReconnectBackoffandProbeWatchdogdirectly; protocol timing remains in the proto docs and conformance tests. SPLClientInfo, whoseuserAgentprovides the client app identifier for inner direct communication with the home server.
The library reports connection progress through TunnelState and stateUpdates on TunnelSession and TunnelSupervisor; it does not ship app-window state. A connect-window terminal signal is an adapter-layer pattern: the app observes those state transitions, decides which failures are terminal for its UI, and keeps that policy outside SPLTunnel. For supervisors that manage reconnect across generations, attemptState and attemptStateUpdates() provide the current high-level attempt state (idle, attempting, unavailable, connected, terminal); apps should not combine stateUpdates with reconnectUpdates to reconstruct this.
LoopbackProxy(opener:) accepts any MuxStreamOpening implementation, so apps can hand it a TunnelSession for a single connection lifecycle or a TunnelSupervisor when reconnect behavior should preserve the loopback port.
This library contains no telemetry, analytics, or crash reporting, and never will. It talks only to the owner's own journal and the relay endpoint the owner's pairing names.
AGPL-3.0-only - see LICENSE.