Skip to main content
The repository includes native protocol baselines for teams building a full Crosslink client outside JavaScript. They implement canonical JSON, CLX1 length-prefixed framing, incremental decoding, protocol version checks, and shared positive/negative fixtures — verified against the same corpus described in Protocol conformance. All three run in CI on every push, in a dedicated native-protocol job separate from the TypeScript test job (see .github/workflows/ci.yml).

What each baseline implements

Each SDK exposes the same small surface, matching the TypeScript ProtocolAdapter used by conformance:
  • Canonical JSON — deterministic serialization with sorted object keys and no insignificant whitespace, so two implementations produce byte-identical output for the same logical value.
  • CLX1 framing — a 4-byte big-endian length prefix followed by the canonical JSON payload (sdks/rust/src/lib.rs::encode_frame, CrosslinkProtocol.encodeFrame in Kotlin/Swift).
  • Incremental frame decoding — a decoder that can be fed partial byte chunks (as they arrive off a socket) and yields complete messages once a full frame is buffered, enforcing the max-frame-size limit before allocating.
  • Protocol version checks — rejecting a frame whose v field isn’t the supported CLX1 version.
  • Shared fixtures — the same messages-v1.json and invalid-v1.json corpus every language SDK is checked against.
Each language represents JSON values idiomatically rather than sharing a type across the FFI boundary — Kotlin uses a sealed CrosslinkValue hierarchy, Swift walks Any/NSNumber/NSNull, Rust uses serde_json::Value. Only the serialized bytes need to match, not the in-memory representation.

What they deliberately do not implement yet

These packages are protocol foundations, not feature-parity clients. They do not currently include:
  • Transport selection — no WebSocket/WebRTC client, no LAN vs. relay candidate racing (see Networking)
  • The CLX1 handshake — no X25519/Ed25519 key exchange, no hybrid PQ support (see Encryption and Hybrid post-quantum exchange)
  • Pairing UI — no QR/code entry flow, no SAS verification
  • Persistent identity — no keychain/keystore-backed device identity across restarts
  • Reconnect policy — no backoff, no session resumption
A native SDK that only implements this layer can serialize and parse frames correctly, but cannot yet establish a session with a Crosslink host.

Adding a language

  1. Implement canonical JSON and the 4-byte big-endian frame length prefix.
  2. Enforce frame-size and protocol-version limits before allocating memory for the payload — the negative fixtures include an oversized-frame case specifically to catch implementations that decode first and check second.
  3. Port every fixture from packages/protocol/fixtures/messages-v1.json and packages/conformance/fixtures/invalid-v1.json without changing them — fixtures are generated from (and only ever edited alongside) the TypeScript reference in packages/protocol.
  4. Assert the exact stable error code (parse_error, version_unsupported, invalid_message, …) for every negative fixture, not just “an error was thrown.”
  5. Add the SDK’s test command to .github/workflows/ci.yml’s native-protocol job before implementing transports or crypto, so conformance regressions are caught from the first commit.
See Protocol conformance for the full adapter contract and how the report is scored.