The types REX and WSX both need, declared once — depend on this instead of on either framework.
corex is the shared contract module of the frameworkx family. It holds the
shapes that are not specific to one transport: middleware, RFC 9457 problem
details, the origin allowlist, the logger, the event bus, the dependency
injection contract, body schemas, and the security scheme accessors.
It exists because wsxtension is a
sibling of rextension, not a
dependent. Both need these shapes. Declaring them twice — structurally
identical, compatible only until one side gains a method — is a divergence that
is silent at compile time in whichever module did not change.
Interfaces and types only. Stdlib only, no third-party dependency, so its import list stays the floor of every extension's dependency graph in both frameworks.
go get github.com/kryovyx/corexYou usually do not need to. rextension re-exports everything here as type
aliases, so an extension written against rextension compiles unchanged and
never names this module.
| Package | Holds |
|---|---|
corex |
Middleware and the Priority* scale; Problem/FieldError (RFC 9457); OriginPolicy; Logger/LogLevel; the BodySchema family; the security scheme accessors and SchemeRegistry; ClientIP |
corex/di |
Resolver, Scope, Container — the DI contract, satisfied by dix |
corex/event |
Event, EventHandler, EventBus, DropCounter, BusLogger, BaseEvent |
corex/schema |
The reflection JSON Schema 2020-12 generator, shared by OpenAPI 3.1 and AsyncAPI 3.0 |
Anything specific to one transport. Route, RouteInfo, RouterConfig,
BodyLimitedRoute, Rex, Option, Extension, RouteValidator and the
router event types stay in rextension; their WebSocket analogues stay in
wsxtension.
The test for a new shape is whether both frameworks need it. If only one does, it belongs in that one's contract module — a shape moved here "because it might be shared" widens the surface every extension in both ecosystems depends on.
One error format for the whole stack. The type and instance prefixes are configured once, at startup, through options:
corex.ConfigureProblems(
corex.WithProblemTypeBase("https://api.example.com/problems/"),
corex.WithInstanceBase("https://api.example.com/requests/"),
)
corex.WriteProblem(w, r, http.StatusUnauthorized,
corex.ProblemUnauthorized, "credentials were not accepted")They used to be mutable package-level vars. That was process-wide mutable
configuration read on every construction and written by whatever ran first —
the defect D21 removed for the security scheme registry, and the one place a
type alias could not carry across the module boundary (W31).
ClientIP walks X-Forwarded-For right to left, stopping at the first
address no trusted proxy vouched for. It lives here so the rate limiter and the
WebSocket gateway's per-IP connection cap cannot diverge on a bug one of them
has already fixed (W26).
ip := corex.ClientIP(r, corex.PrivateNetworks())An empty trust list ignores the header entirely and uses RemoteAddr, which is
the safe default: an untrusted peer's forwarding claims are worth nothing.
New in the REX v0.3.0 release, at v0.1.0 — there is nothing to migrate from. MIGRATION.md says what this module is, what it costs to adopt, and links to the guide for every other module in that release.
Alpha. The API may change before v1.0.0. External contributions open at
v1.0.0 — see CONTRIBUTING.md.
MIT — see LICENSE.