What this module does not do¶
It does not run a broker on the network¶
At v0.1.0 an embedded server is refused unless it is in-process. Host, Port, Routes,
ClusterName and ClusterPort are rejected rather than ignored.
There is no TLS or authentication configuration in this module, so a listening server would accept any connection that could reach it, with no credential and nothing encrypted — and a token supplied by a client would be neither required by the server nor protected in transit. Refusing means the unsafe surface does not exist rather than existing with a warning beside it.
Connecting a client to a cluster somebody else operates and secures is unaffected, and is what most services should do.
It does not read configuration¶
No go/config import, and there will not be one. Toolkit modules take typed settings; the calling
application maps its own configuration onto them.
That is what lets one application configure from YAML and another from flags, and it is what keeps a configuration library out of every module's dependency graph. The struct tags exist so the mapping is a decode rather than an assignment.
It does not compose a credential ladder¶
CredentialSource is a function you supply. Precedence — environment variable name, keychain,
literal, well-known variable — is the application's decision, and a library that decides it is a
second statement of something the estate already states once, which is how two statements drift.
It does not offer TLS, NKeys, JWT or mTLS on the client¶
The client supports a bearer token and nothing else. Custom root certificates, NKey or JWT
credentials and mutual TLS are not configurable through these settings, and reaching them through
Client.Raw() is too late — the connection is already made.
A tls:// URL works with the system root pool, and a credential over any other scheme is refused.
That is a floor, not an estate-grade authentication surface.
It does not wrap JetStream's verbs¶
It owns construction and nothing else. Stream, KeyValue and ObjectStore apply the house
limits and hand back upstream's interfaces unwrapped; JetStream() gives you the context for
everything past that.
Wrapping the verbs would be forty-odd methods across seven interfaces — KeyValue alone is sixteen,
plus seven for bucket lifecycle, plus ObjectStore's seventeen. Each is a place to fall behind an
actively developed upstream, and a consumer wanting a new capability would wait on a release here to
reach it. Get and Put need no opinion from this module. Creation does, because every JetStream
limit defaults to unlimited and NATS' own documentation warns that exhausts the disk.
It does not retry, back off or circuit-break¶
go/transit does that. Reconnection is NATS' own and is configured, not implemented here.
It does not put every capability behind a method¶
Client.Raw() returns the underlying connection, and JetStream's verbs, custom subscribe options
and anything else this package has no opinion about go through it.
What is funnelled is the part worth funnelling: Publish, PublishMsg and Request exist so
there is one place header propagation, latency and error metrics, deadlines and subject policy can
live. Raw is named as an escape hatch so that reaching for it reads as a decision, and a second
caller reaching for the same thing is a request for it to become a method here.
The honest caveat: Raw also exposes NATS' own Subscribe, which does not bound its queue. Nothing
stops a determined caller going round the one guarantee this module makes.
It does not give you a Len()¶
Deliberately, and this generalises past this module.
Queue depth is a local read in-process and a network round trip against a broker. A method that
looks free and is not becomes a per-decision round trip on somebody's hot path, discovered under
load. If depth is exposed later it will carry a context.Context and an error, so the cost is
visible in the signature.
Sharp edges it cannot file off¶
A message delivered but not yet acknowledged cannot be purged. If you have a deletion promise to a person — a forget-me — a subject-filtered purge reaches everything except what is currently in flight. No wrapper changes this; it is a property of the store.
File-store deletion is not secure erasure. JetStream removes the message; it does not overwrite the blocks. Encryption at rest is the answer to that question, not deletion.
Two shed points exist and only one is yours. Client-side pending limits are set by this module
and counted per subscription. The server also detects slow consumers and may disconnect a client
outright, and Dropped()'s own documentation notes its count may not be valid when that happens.
Queue groups are not a durable work queue. A queue subscription delivers to at most one currently connected member. With no subscriber, a disconnect, a startup race or a slow consumer, delivery is zero. Redelivery and durability are JetStream properties, not core NATS ones, and calling a queue group a work queue invites the opposite assumption.
Subject ownership is undefined. Two services can independently choose events.created and
silently exchange traffic once they share a cluster. This module has no namespace convention, and a
prefix would be organisation rather than a boundary in any case — NATS accounts and credential
permissions are the boundary.
Identity: prefer NKeys or JWT over mTLS DN mapping. CVE-2026-33248 was an authentication bypass
in verify_and_map's Subject DN matching — fixed in 2.11.15 and 2.12.6, requiring an already-trusted
certificate, rated 4.2 — whose only offered workaround was "review your CA issuing practices". DN
parsing is a fiddly surface to rest a tenancy boundary on. NKeys have no DN to mis-parse.