> ## Documentation Index
> Fetch the complete documentation index at: https://docs.westyx.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Spring Boot SDK - API Reference

> Every public method, getter, and bean in the Spring Boot SDK.

Every public symbol exported by `dev.westyx.nexus.*`. The auto-configuration creates the `NexusClient` bean and starts the SSE stream - for most users, the read methods (`getConfig`, `getFlag`, `getSecret`) are the entire API surface.

## Construction

### `NexusClient.create(NexusConfig config)`

Creates a client and runs a **blocking** initial sync. Used internally by the auto-configuration; rarely called directly.

```java theme={null}
NexusClient client = NexusClient.create(NexusConfig.builder()
        .baseUrl("...")
        .apiKey("...")
        .build());
```

| Throws                     | When                                                                                   |
| -------------------------- | -------------------------------------------------------------------------------------- |
| `NexusInitException`       | Initial sync failed for any reason. The `getCause()` returns the underlying exception. |
| `IllegalArgumentException` | `baseUrl` or `apiKey` missing or invalid.                                              |

## Configs

### `Optional<JsonNode> getConfig(String key)`

Returns the resolved config value as a Jackson `JsonNode` (the wire-decoded JSON), or `Optional.empty()` when the key is absent.

```java theme={null}
String dbUrl = client.getConfig("database.url")
                     .orElseThrow()
                     .asText();
```

### `<T> Optional<T> getConfigAs(String key, Class<T> type)`

Returns the config value coerced to the given type, using Jackson's `treeToValue`.

```java theme={null}
Optional<Integer>  port = client.getConfigAs("server.port", Integer.class);
Optional<String[]> tags = client.getConfigAs("app.tags", String[].class);
```

### `Map<String, JsonNode> getAllConfigs()`

Snapshot copy of every config key-value pair currently in the cache.

public-key clients see only `is_public: true` entries.

## Feature flags

### `boolean getFlag(String key)` / `boolean getFlag(String key, boolean defaultValue)`

Returns the `is_active` state of a flag, or `defaultValue` (default `false`) when the key is absent.

```java theme={null}
boolean isOn = client.getFlag("checkout.v2");           // false if missing
boolean isOn = client.getFlag("checkout.v2", true);     // true if missing
```

### `Map<String, Boolean> getAllFlags()`

Snapshot copy of every flag key-is\_active pair in the cache.

## AB Testing *(v0.3.0)*

### `Map<String, Boolean> evaluateAB(List<String> keys, String userId, Map<String, Object> attributes)`

Batch-evaluates feature flags with AB Testing semantics. Posts to `POST /v1/flags/evaluate-ab` and returns the server's `results` map verbatim.

Unlike `getFlag`, this method **always makes a network call**. The call is **blocking**; run it off the request thread if your handler is latency-sensitive.

```java theme={null}
Map<String, Boolean> results = client.evaluateAB(
        List.of("checkout.v2", "new-pricing-banner"),
        "user-42",
        Map.of("country", "DE", "plan", "pro"));

boolean newCheckout = results.getOrDefault("checkout.v2", false);
```

Requires the **AB Testing add-on** to be active on the project; otherwise the server returns HTTP 403.

| Throws                              | When                                                                     |
| ----------------------------------- | ------------------------------------------------------------------------ |
| `NexusAbAddonNotAvailableException` | Server returned HTTP 403 - AB Testing add-on not active for the project. |
| `NexusUnauthorizedException`        | Server returned HTTP 401.                                                |
| `NexusBillingException`             | Server returned HTTP 402 - tenant billing overdue.                       |
| `NexusException`                    | Any other transport, protocol, or JSON-decoding error.                   |

## Secrets (secret key only)

### `String getSecret(String key)`

Returns the plaintext value of a secret.

```java theme={null}
String dbPass = client.getSecret("DB_PASSWORD");
```

| Throws                         | When                         |
| ------------------------------ | ---------------------------- |
| `NexusPublicKeyException`      | The client uses a public key |
| `NexusSecretNotFoundException` | The key is not in the cache  |

### `Optional<String> getSecretFilePath(String key)` *(v0.3.0)*

Returns the absolute path to the on-disk file where the SDK has materialised a `type="file"` secret, or `Optional.empty()` when the key is unknown or the secret is of `type="text"`.

```java theme={null}
String credsPath = client.getSecretFilePath("gcp.service-account.json")
                         .orElseThrow(() -> new IllegalStateException("missing GCP creds"));

GoogleCredentials creds = GoogleCredentials.fromStream(new FileInputStream(credsPath));
```

## Write API *(v0.5.0)*

The write API allows programmatic secret creation and deletion. **Available for secret keys only**. Using a public key throws `NexusPublicKeyException` immediately, before the network call.

### `void setSecret(String key, String value)`

Creates or updates a secret with the given key and plaintext value. The secret defaults to `type="text"`.

```java theme={null}
try {
    client.setSecret("stripe_secret_key", "sk_test_1234...");
} catch (NexusRateLimitedException e) {
    log.error("Rate limit hit on setSecret - retry after {}", e.getRetryAfter());
}
```

| Throws                       | When                                                      |
| ---------------------------- | --------------------------------------------------------- |
| `NexusPublicKeyException`    | The client uses a public key                              |
| `NexusRateLimitedException`  | Server returned HTTP 429 (rate limited on write endpoint) |
| `NexusUnauthorizedException` | Server returned HTTP 401                                  |
| `NexusBillingException`      | Server returned HTTP 402 - billing overdue                |
| `NexusException`             | Any other transport, protocol, or JSON-decoding error     |

### `void deleteSecret(String key)`

Deletes a secret and all its versions.

```java theme={null}
try {
    client.deleteSecret("old_api_key");
} catch (NexusRateLimitedException e) {
    log.error("Rate limit hit on deleteSecret - retry after {}", e.getRetryAfter());
}
```

| Throws                       | When                                                      |
| ---------------------------- | --------------------------------------------------------- |
| `NexusPublicKeyException`    | The client uses a public key                              |
| `NexusRateLimitedException`  | Server returned HTTP 429 (rate limited on write endpoint) |
| `NexusUnauthorizedException` | Server returned HTTP 401                                  |
| `NexusBillingException`      | Server returned HTTP 402 - billing overdue                |
| `NexusException`             | Any other transport, protocol, or JSON-decoding error     |

### `void deleteSecretVersion(String key, int version)`

Deletes a specific version of a secret.

```java theme={null}
try {
    client.deleteSecretVersion("stripe_secret_key", 3);
} catch (NexusRateLimitedException e) {
    log.error("Rate limit hit on deleteSecretVersion - retry after {}", e.getRetryAfter());
}
```

| Throws                       | When                                                      |
| ---------------------------- | --------------------------------------------------------- |
| `NexusPublicKeyException`    | The client uses a public key                              |
| `NexusRateLimitedException`  | Server returned HTTP 429 (rate limited on write endpoint) |
| `NexusUnauthorizedException` | Server returned HTTP 401                                  |
| `NexusBillingException`      | Server returned HTTP 402 - billing overdue                |
| `NexusException`             | Any other transport, protocol, or JSON-decoding error     |

## Metadata

| Method                | Return type | Description                                                 |
| --------------------- | ----------- | ----------------------------------------------------------- |
| `getKeyType()`        | `String`    | `"sk"` or `"pk"` - derived from the configured `apiKey`     |
| `getSyncedAt()`       | `Instant`   | Timestamp of the last successful sync                       |
| `isStreamConnected()` | `boolean`   | `true` while the SSE stream is connected and pushing events |

## Sync / lifecycle

### `void sync()`

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.

### `void connectStream()` / `void disconnectStream()`

Start/stop the SSE thread. The auto-configuration calls `connectStream()` automatically (unless `nexus.stream=false`). Idempotent.

### `void close()`

Stops the SSE thread, **removes any temp files created for `type="file"` secrets**, and releases the SDK-owned HTTP clients. The auto-configuration registers this as the bean's destroy method (`destroyMethod = "close"`), so it fires automatically on Spring context shutdown.

`NexusClient` implements `AutoCloseable`, so try-with-resources also works:

```java theme={null}
try (NexusClient client = NexusClient.create(config)) {
    // use client
}
```

## Exception hierarchy

```java theme={null}
import dev.westyx.nexus.NexusException;                  // abstract base
import dev.westyx.nexus.NexusInitException;              // initial sync failure
import dev.westyx.nexus.NexusUnauthorizedException;      // HTTP 401
import dev.westyx.nexus.NexusNotFoundException;          // HTTP 404
import dev.westyx.nexus.NexusPublicKeyException;         // getSecret with public key
import dev.westyx.nexus.NexusSecretNotFoundException;    // unknown secret key
import dev.westyx.nexus.NexusAbAddonNotAvailableException; // evaluateAB HTTP 403 (v0.3.0)
import dev.westyx.nexus.NexusQuarantinedException;         // sync 429 quarantine (v0.4.0)
```

All concrete exceptions extend `NexusException`. See [Error handling](error-handling) for full semantics.

## Logger SPI

```java theme={null}
public interface NexusLogger {
    void debug(String message);
    void info(String message);
    void error(String message, Throwable cause);
}
```

The auto-configuration installs an SLF4J-backed adapter writing to the logger named `dev.westyx.nexus.NexusClient`. To override, register your own `NexusLogger` bean.
