KtorClientLoom
Client-side Loom backed by Ktor WebSockets.
join connects directly to a WebSocketAdvertisement URL and returns a 2-peer WebSocketSeam — no intermediate contract Session adapter.
Pairing: KtorClientLoom ↔ KtorServerLoom/KtorRoomHost — a 2-peer relay with no in-band handshake. It is not the client for a us.tractat.kuilt.core.MuxServerLoom hub: that hub handshakes every spoke with an in-band MeshHello preamble a WebSocketSeam never sends, so pointing this loom at one silently never completes admit. Use KtorMeshClientLoom (hub-spoke mesh) for a MuxServerLoom hub.
PeerId discovery:
Client's own PeerId is fixed at construction as selfPeerId and appended as
?peer=<id>on every join so the server can read it.Server's PeerId comes from WebSocketAdvertisement.serverPeerId.
Stable identity across reconnects: supplying selfPeerId gives this loom a fixed fabric identity reused on every call to weave/join. This is required for cluster-client failover: the server derives a learner NodeId from the admitted PeerId; if a reconnect mints a new random id the server admits a different learner and Raft routing breaks. The default mints a fresh random identity per loom instance (mirroring the old per-join behaviour for callers that do not need stable identity). See #544.
Per-dial credentials: weft is invoked fresh inside every weave call — the first dial and every subsequent redial — so a caller can mint a single-use credential (e.g. a short-lived WS ticket) that survives kuilt's transparent reconnect instead of being baked once into a static WebSocketAdvertisement.url. See #1330.
HttpClient lifecycle: the httpClient is not closed by this loom. Callers are responsible for closing it when all connections are done.
Parameters
Scheduler for the per-connection seam's read/write loops; the loom confines it to a single thread via limitedParallelism(1). Production default is Dispatchers.Default; tests inject kotlinx.coroutines.test.UnconfinedTestDispatcher.
The fabric identity this loom presents on every join. Defaults to a random UUID minted once at construction; supply a deterministic value for stable cluster-client identity across reconnects.
Supplies a WebSocketDialContext fresh on every dial. Defaults to an empty context (no extra query params/headers).
Live device-reachability observer driving every woven Seam's Seam.capability (#1725). Defaults to UnobservedConnectivity — the identity element, under which a seam reports the honest FabricAvailability.Unknown floor exactly as before. Supply androidConnectivityObserver(context) on Android or browserConnectivityObserver() on wasmJs; the desktop JVM has no portable observer and is meant to be left unwired (see ConnectivityObserver).
Constructors
Functions
The pre-connect report, deliberately unchanged by #1725: it answers "can this fabric be attempted on this runtime" — a Ktor WebSocket client exists on every target — not "is the device's path up right now", which is the live per-session Seam.capability's job. Keeping the two apart is the #1712 distinction; connectivity therefore feeds the seam, not this.
Establishes a Seam: