Files
Rendezvous/docs/architecture/0007-caller-owned-dotnet-client-sdk.md
KyuubiYoru 06c3973ce7
quality-gate / quality (push) Successful in 1m6s
feat: add publisher and browser client SDK (#9)
Closes #9
2026-07-16 06:27:44 +02:00

2.9 KiB

ADR 0007: caller-owned .NET publisher and browser SDK

  • Status: Accepted
  • Date: 2026-07-16
  • Tracking: #9

Decision

The .NET client package exposes separate publisher and browser interfaces plus concrete clients over a caller-supplied HttpClient. The caller owns that client, its handler, base address, connection pool, proxy, and lifetime. SDK operations dispose every request, response, and response body they create, but never dispose the supplied client. The package targets netstandard2.1, depends only on the wire-contract package and LiteNetLib, and contains no Godot types, global client, service URL, publisher secret, or embedded game credential.

Every operation returns RendezvousClientResult<T> with a stable error code, message, and optional retry guidance. Cancellation remains exceptional through the caller's CancellationToken; transport failures become ServiceUnavailable. Response bodies are streamed under the contract's 256 KiB browser ceiling before deserialization. Invalid or oversized success bodies become InternalError and never escape as partially trusted contract objects.

The SDK retries only operations whose duplicate execution is safe: scoped reads, idempotency-keyed registration, lease renewal with the same lease token, complete resource update, and lease-token deregistration. It honors bounded server retry guidance and otherwise uses capped exponential backoff with jitter. Each retry creates a fresh HTTP request while preserving the caller's registration idempotency key. Configuration is copied on construction so later option mutation cannot change an in-flight client's behavior.

PublishedSession holds the server-issued lease and presence capabilities needed by the host. Its string representation always redacts them. Update requests are copied before the lease token is attached, so the SDK never mutates caller-owned DTOs. The browser exposes one-page calls and bounded cursor traversal; cursor values remain opaque and caller requests remain unchanged.

Lease maintenance is explicit. Creating a SessionLeaseMaintainer starts no task; the game chooses when to call RunAsync, owns cancellation, and awaits DisposeAsync. The loop uses the latest server-provided renewal interval and returns a distinct cancelled, disposed, lost-lease, or failed result. Terminal authorization, expiry, and missing-lease responses also raise LeaseLost so the host can stop advertising or re-register deliberately.

Consequences

  • SpaceGame and Unscouted can inject the publisher/browser interfaces in tests without an engine runtime or real network.
  • Games must configure an absolute HttpClient.BaseAddress (or equivalent handler routing), obtain publisher credentials from their deployment boundary, and explicitly run and dispose lease maintenance.
  • The versioned client public-API snapshot and live-server integration tests fail together when SDK and HTTP contracts drift.