gitlab.com/westyx/nexus/sdk/go. All read methods are non-blocking - they hit the in-memory cache. Only NewClient and Sync make network calls.
Construction
NewClient(ctx context.Context, cfg Config) (*Client, error)
Creates a client and runs a blocking initial sync. Returns the populated client, or an error wrapping ErrSyncFailed.
ctx controls the timeout / cancellation of the initial sync. Use context.WithTimeout if you want a hard deadline.
Configs
(c *Client) GetConfig(key string) (any, bool)
Returns the resolved config value as any (the wire-level decoded JSON) and a found flag.
string, json.Number, bool, []any, map[string]any, or nil. Numbers are json.Number rather than float64 - see Config values for why, and prefer GetConfigAs for typed reads. Object and array values are deep-copied on return, so you may freely mutate the result without affecting the cache.
(c *Client) GetAllConfigs() map[string]any
Snapshot copy of every config key-value pair currently in the cache. The returned map - including nested object/array values - is deep-copied and fully independent of the SDK’s internal storage; mutating it (at any depth) has no effect on the cache.
Public-key (wxp_) clients receive the configs the service exposes to public keys; there is no separate visibility flag to check.
Feature flags
(c *Client) GetFlag(key string, defaultValue bool) bool
Returns the is_active state of a flag, or defaultValue when the key is absent.
is_active (combining is_enabled, starts_at, ends_at); the SDK never makes that call itself.
(c *Client) GetAllFlags() map[string]bool
Snapshot copy of every flag key-is_active pair in the cache.
AB Testing
(c *Client) EvaluateAB(ctx context.Context, keys []string, userID string, attributes map[string]any) (map[string]bool, error)
Batch-evaluates feature flags through the AB Testing add-on against the supplied user context. Issues a single POST /v1/flags/evaluate-ab and returns the inner results map - flag key to evaluated boolean. Unlike GetFlag, this method always performs a network call and does not consult the local cache.
false by the server. Both keys and attributes are serialised as empty (not null) when passed as nil, so the backend never rejects the payload.
Secrets (secret key only)
Secrets are typed: each entry has aType field of either SecretTypeText (the default - a plain string returned via GetSecret) or SecretTypeFile (file content the SDK additionally writes to a temp file on every sync, whose path is exposed via GetSecretFilePath).
type are treated as "text" for backwards compatibility.
(c *Client) GetSecret(key string) (string, error)
Returns the plaintext value of a secret. Works for both text and file secrets - for file secrets it returns the raw file contents as a string.
(c *Client) GetSecretFilePath(key string) (string, bool)
Returns the temp-file path that holds the value of a file-type secret, together with a found flag. The SDK materialises every SecretTypeFile entry to disk on every sync at:
0700 on the first file-type secret (a client with none leaves nothing on disk), with a random suffix that keeps clients apart across processes. Both name components are SHA-256 prefixes, so neither the key name nor the value appears in the path. The value hash means the path changes whenever the value changes, and stale files are removed automatically. Files are written with mode 0o600, applied at creation rather than by a chmod afterwards. On Windows, where no 0600 equivalent exists, the files inherit the directory’s ACL - user-scoped for the standard per-user temp location.
false when:
- the key does not exist in the cache
- the secret’s
Typeis"text"(or empty / non-"file") - the client uses a public key - secrets are not delivered
- the service
kindis"frontend"- secrets are not allowed there
(c *Client) Close() error
Releases resources held by the client. After Close, the client must not be used.
Close cancels the background work (SSE stream, TTL refresh, WIF session refresh) and waits for it, removes the private directory holding materialised file-type secrets, releases the connections the SDK opened, and marks the client as closed so subsequent calls are no-ops.
Close is the only cleanup point for materialised file-type secrets: Go runs nothing on os.Exit, finalizers are not guaranteed to run before termination, and the SDK deliberately installs no signal handler - that would change how the whole application responds to Ctrl-C. Files left behind by a process that exits without Close are 0600 inside a 0700 directory, so they remain unreadable by other local users. Always defer client.Close().
Close is safe to call multiple times and always returns nil today.
Write API (secret key only)
The write API lets you create, update, and delete secrets programmatically. All three methods check the key type before making any network call - public keys returnErrPublicKeyRestricted immediately.
(c *Client) SetSecret(ctx context.Context, key, value string) error
Creates or updates a secret (POST /v1/secrets, type: "text").
(c *Client) DeleteSecret(ctx context.Context, key string) error
Deletes all versions of a secret (DELETE /v1/secrets/:key). Key is URL-encoded automatically.
(c *Client) DeleteSecretVersion(ctx context.Context, key string, version int) error
Deletes a specific version of a secret (DELETE /v1/secrets/:key?version=N).
Metadata
(c *Client) KeyType() string
"sk" or "pk". Returns "" when authentication is exclusively via Workload Identity Federation (no static APIKey set).
The answer is "pk" if either signal says so: the key’s wxp_ prefix, or the
key_type the backend reported on the last sync. Every secret operation is gated on the
same rule, and because the gate’s answer is a refusal, either signal is sufficient on
its own and neither has to be trusted alone.
(c *Client) Kind() string
The service kind reported by the backend: "frontend", "backend", or "" if not yet determined. Available after the first successful sync (or token exchange when WIF is enabled).
(c *Client) SyncedAt() time.Time
Timestamp of the last successful sync. Useful for “last refreshed” UIs and health checks.
nexus.GetConfigAs[T](client *Client, key string) (T, error)
New in v0.11.0.
Decodes the config value for key into T, from the exact bytes the backend sent.
Because it decodes from the raw bytes, your
json tags and custom UnmarshalJSON
apply, and nothing is lost to float64 on the way through. See
Config values.
(c *Client) SnapshotRevision() uint64
How many times a sync has replaced the cache’s contents. A 304, a stream reconnect, a
fall-back to polling and a failed attempt all leave it unchanged, so it answers “did the
configuration change” for anything holding a value derived from the cache.
(c *Client) Subscribe(fn func()) (cancel func())
Registers fn to run after a sync has replaced the cache’s contents, and returns a
function that cancels the registration.
fn runs on the goroutine that applied the sync, after the new snapshot is visible -
so a read inside it returns the new values. It must return promptly; send to a channel
and do the work elsewhere if it cannot. A panic is contained and reported rather than
allowed to reach the SDK’s own goroutine. Cancelling is idempotent and safe from inside
fn; Close drops every subscription.
This is what StreamObserver.OnEvent cannot do: that fires when an event arrives, before
the sync it triggers, so a read there returns the previous values.
(c *Client) StreamConnected() bool
New in v0.11.0.
Reports whether the SSE stream currently has a live connection. false means live
updates are not arriving and the cache is being kept fresh by TTL polling alone - the
stream has not connected yet, is between reconnect attempts, or the client is closed.
A point-in-time answer; use a StreamObserver to react to the
transitions.
(c *Client) BillingOverdue() bool
Reports true if the most recent sync attempt returned 402 Payment Required. While the flag is set, the SDK suspends the background refresh loop and serves the last cached snapshot. The flag clears when a subsequent sync succeeds.
Sync / lifecycle
(c *Client) Sync(ctx context.Context) error
Forces a sync now, bypassing the TTL. Atomically replaces the cache. ETag / If-None-Match is used automatically; a 304 resets the TTL without downloading data. Rarely needed - the SDK syncs automatically.
(c *Client) RunStream(ctx context.Context)
Opens the SSE live-update connection and blocks until either:
- The context is cancelled
- 3 consecutive transport errors occur (the SDK falls back to TTL polling and returns)
NewClient starts this automatically. You only need to call it manually to re-launch the stream after a MAX_ERRORS fallback:
Sentinel errors
errors.Is(err, nexus.ErrX) rather than equality or string matching.
Logging
Config.Logger is a *slog.Logger. Records carry structured attributes plus a
component field naming the subsystem (client / stream / wif); a nil logger
discards everything. See Logging.
StreamObserver interface
Config.Observer for structured SSE-lifecycle callbacks. Default is NoopStreamObserver. See Stream observer for full semantics and examples.
Workload Identity Federation types
Config.WIF to swap the static X-Nexus-API-Key header for a session-JWT bearer flow. See Workload identity.
TokenSource overrides Provider and supplies an OIDC token. ExchangePayload overrides both and supplies the entire token-exchange request body, for a credential that is not an OIDC token at all. Added in v0.11.0, and it is how aws_iam is selected - build one with wifaws.ExchangePayload:
