Skip to content

feat(sync): add NexusKit.Modules.Sync, the client half of the sync stack - #35

Merged
nxships merged 2 commits into
mainfrom
feat/modules-sync
Aug 11, 2026
Merged

feat(sync): add NexusKit.Modules.Sync, the client half of the sync stack#35
nxships merged 2 commits into
mainfrom
feat/modules-sync

Conversation

@nxships

@nxships nxships commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

The client side of NexusKit.Sync: REST transport, API-key handling, connection registration.

Requires NexusKit.Sync, published in NexusKit v0.5.1.

What is here

Type Purpose
RestSyncProtocol ISyncProtocol over HttpClient. Stateless beyond its configuration.
SyncConnectionOptions One connection. Validates eagerly and names itself in failures.
SyncServiceCollectionExtensions Keyed registration, plus an unkeyed overload.
ContractResolution Server's contract document, or the local one as fallback.
ProblemDetailsReader (internal) Failure responses, parsed defensively.

Three decisions worth the review

Registration is keyed. Talking to several servers is the normal case: every author runs their own, so a plugin consuming somebody's published client bindings talks to that author's server and to its own. Retrofitting that later means partitioning the outbox, the cursors, the settings section and the key storage after the fact.

The server's contract wins, where the key may read it. A local file that has drifted then stops being something to diagnose. Where the key may not, the server publishes nothing and the client falls back on what it ships — the mode that scope exists to gate.

Plain HTTP is refused, not upgraded. An API key is a bearer credential; over plain HTTP everyone on the path has it. Silently rewriting the address would hide a misconfiguration that matters. AllowInsecureTransport exists for a container on localhost and nothing else.

Deliberately not here

No outbox, no downlink mirror, no cursor persistence, no background drainer — the parts that turn PushAsync into fire-and-forget and GetAsync into an offline read. Until then a caller holds ISyncProtocol and drives it. Stated in the README rather than implied by absence.

Verification

Builds clean, 0 warnings. 13 tests against a stubbed handler, plus a full end-to-end run against a live server: handshake, push, idempotency, validation refusals, direction and scope violations, all green.

Same caveat as NexusKit: those tests live in localTools/ and no CI runs them.

Documentation

PlayerNexusTracker is out of the modules' API docs, for the reason it left NexusKit's — these are meant to be usable without knowing that plugin exists.

The REST transport against any server speaking NexusKit.Sync: RestSyncProtocol,
API-key handling, keyed connection registration, and defensive Problem Details
parsing.

Registration is keyed rather than singular because talking to several servers
is the normal case, not an exception: every author runs their own, so a plugin
consuming somebody's published client bindings talks to that author's server
and to its own. Retrofitting that later would mean partitioning the outbox,
the cursors, the settings section and the key storage after the fact.

ContractResolution decides which document a client works from. Where the key
carries the built-in contract-reading scope the server's copy wins — a local
file that has drifted then stops being a problem to diagnose. Where it does
not, the server publishes nothing and the client falls back on what it ships.

Plain HTTP is refused rather than upgraded. An API key is a bearer credential,
and silently rewriting an address hides a misconfiguration that matters.

No Dalamud reference: the transport has nothing to do with the game, and the
same assembly is what a headless test harness uses.

Also removes PlayerNexusTracker from the modules' API documentation, for the
same reason as NexusKit: these are meant to be usable without knowing that
plugin exists.
@nxships
nxships enabled auto-merge (squash) August 11, 2026 11:37
A floor of 0.5.0 restores 0.5.1 and raises NU1603 for the substitution, which
TreatWarningsAsErrors turns into a failed build. The library did not exist in
0.5.0, so that was never a version anyone could resolve.
@nxships
nxships merged commit c8be266 into main Aug 11, 2026
2 checks passed
@nxships
nxships deleted the feat/modules-sync branch August 11, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant