Roadmap
State at 3b91de6, published to NuGet as 0.1.0. The SDK covers the full TCGdex REST surface, builds clean on
netstandard2.0, net8.0 and net10.0, and is verified under Native AOT.
| Tests | 480 unit × 3 frameworks + 149 integration |
| Mutation score | 88.19%, break threshold 85 |
| Line coverage | 99.80%, gated at 99.5 |
| Branch coverage | 96.53%, gated at 95 |
| Warnings | zero — compiler, analyzers, DocFX, CI annotations |
| Docs | published to GitHub Pages on every push to main |
| Package | published, 0.1.0, 462 KB, three target frameworks |
Published 2026-08-08 via Trusted Publishing — no API key was ever created.
Before 1.0
1. Publish to NuGet — done
0.1.0 shipped 2026-08-08 via Trusted Publishing, from a workflow_dispatch
run of release.yml.
No API key was ever created — a laptop cannot mint a GitHub OIDC token, but a
button press runs inside Actions, which can.
Two facts that do not stop being true now it is done: a published version can be
unlisted but never deleted, and TcgDex.CSharpSdk is claimed permanently.
2. Get listed on tcgdex.dev/sdks — the only remaining item
TCGdex lists official SDKs for Java, JavaScript, Kotlin, PHP, TypeScript and Python. Checked 2026-08-07: still no C#/.NET one, and the Community SDKs section is empty, so this would be the first entry in it.
The route is Discord, not a pull request. The site says "Contact us on
Discord to have your SDK added here"; an earlier version of this page said to
open a PR against tcgdex/documentation, which is not what they ask for.
This is the step that makes publishing worth having done. A package with no distribution is a repository with extra steps; a link on the API's own documentation is the one place a person looking for a .NET client actually passes through.
Done
Recorded because the reasoning behind each is worth keeping, and because a roadmap that only lists future work hides what the project already decided.
- Full REST surface — cards, sets, series, random, and all 13 enumeration endpoints.
- Typed query builder over every operator the API actually has, translating
expression trees without ever calling
Expression.Compile(). - Opt-in GraphQL search for full card detail in one request instead of one call per card.
- Response caching with ETag revalidation, so a stale entry costs a
304and zero bytes rather than a re-download — plus a second layer that retains the deserialized model against its ETag, taking a warm hit from 25.71 µs to 1.40 µs. Seecaching.md. - Auto-pagination via
StreamAsync, which handles the short-page end signal the missing total count forces on every consumer. - Typed image URLs, including the asymmetry that card artwork takes a quality segment and set assets do not.
HttpClientownership made explicit, withTcgDexClient.Create()for callers outside a container.- Logging and tracing through
ILoggerandActivitySource, with no dependency on any telemetry vendor. Seeobservability.md. - Coverage gated in CI on both line and branch, verified to fail as well as pass.
- Documentation site generated from XML docs, so the reference cannot drift from the code.
- Fuzzed and API-gated — every path that consumes input the SDK did not produce is driven with corrupted fixtures on every push, and by coverage-guided fuzzing across seven modes weekly (1.8M executions, no crashes). The public surface is pinned by an approval test, so a breaking change cannot merge without someone accepting the diff. Tested on Linux, Windows and macOS.
- Fixture drift detection — the recorded responses every offline test relies on are re-fetched weekly and compared by shape, so an API change fails with a precise message instead of silently invalidating the offline suite.
- Benchmarked at the sizes and states that actually occur — the 2.3 MB
unpaginated card list, and a response cache sitting at its bound. Both found
something the small-payload benchmarks could not: a capacity hint previously
written off as useless saves 2.24 MB per request there, and
ConcurrentDictionary.Countwas costing a cache store up to 17× the operation it was guarding. Seemeasuring.md.
Possible later
Not committed to. Each would need a reason beyond "it would be neat".
SearchDetailedAsyncfor sets and series. Only cards have it. Worth it only if the same N+1 shape shows up in practice for the others.- A distributed cache implementation.
ITcgDexResponseCacheis already pluggable and documented; shipping a Redis one would mean taking that dependency for everyone. - Response compression tuning.
Create()enables automatic decompression; whether it is worth exposing knobs depends on evidence it matters. - Metrics.
System.Diagnostics.Metricscounters for cache hit rate and request duration would complement the existing tracing. The tracing already carries duration, so this only pays off for aggregate dashboards.
Explicitly not doing
IQueryable<Card>. The API has ten operators; anIQueryablewould have to throw for most of LINQ — a partial implementation failing at runtime rather than at the call site. Seearchitecture.md.- GraphQL as the primary transport. It cannot serve 17 of the 18 languages, any range filter, or any pricing data.
- Built-in retry or circuit breaking.
AddTcgDexreturnsIHttpClientBuilder, so.AddStandardResilienceHandler()already works. Shipping a retry policy nobody asked for is how an SDK ends up hammering a free public API. - A telemetry vendor dependency. The SDK writes to
ILoggerandActivitySource; choosing the backend belongs to the application. A library that reported to its author's account from a consumer's process would be exfiltrating their data. - Write operations. The API is read-only —
GETonly, no authentication.