> ## 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.

# React SDK - API Reference

> Every hook and imperative method exported by the React SDK.

Every public symbol exported by `@westyx-nexus/sdk-react`. Hooks are the primary surface; the imperative `NexusClient` is exposed via `useNexus()` for advanced use cases.

## Provider

### `<NexusProvider config={...}>`

Top-level provider that creates the `NexusClient` instance, performs the blocking initial sync, and connects the SSE stream.

```tsx theme={null}
<NexusProvider config={config}>
  <App />
</NexusProvider>
```

| Prop              | Type                          | Description                                                                                                      |
| ----------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `config`          | `NexusConfig`                 | Required. See [Configuration](configuration).                                                                    |
| `children`        | `ReactNode`                   | Rendered after the initial sync resolves.                                                                        |
| `loadingFallback` | `ReactNode`                   | Optional. Rendered while the initial sync is in flight. Defaults to `null`.                                      |
| `onError`         | `(error: Error) => ReactNode` | Optional. Called when the initial sync fails. If omitted, the error is thrown so an Error Boundary can catch it. |

## Hooks

### `useConfig<T>(key: string): T | undefined`

Read a config value. Returns the resolved value as `T` (the wire-decoded JSON), or `undefined` when the key is absent.

```tsx theme={null}
const port    = useConfig<number>('server.port');
const banner  = useConfig<string>('public.banner');
const tags    = useConfig<string[]>('app.tags');
```

public-key clients only see configs that are public (filtering is server-side).

### `useFlag(key: string, defaultValue?: boolean): boolean`

Read a flag value. Returns `defaultValue` (default `false`) when the key is absent.

```tsx theme={null}
const isOn = useFlag('checkout.v2');           // false if missing
const isOn = useFlag('checkout.v2', true);     // true if missing
```

### `useEvaluateAB(): (keys, userId, attributes?) => Promise<Record<string, boolean>>`

Returns a stable callback that evaluates one or more feature flags through the AB Testing endpoint (`POST /v1/flags/evaluate-ab`). The callback identity is stable across renders unless the underlying client changes.

Unlike `useFlag`, every invocation hits the network - results are **not** cached, because targeting rules and rollout buckets depend on the supplied `userId` / `attributes`.

```tsx theme={null}
import { useEffect, useState } from 'react';
import { useEvaluateAB, NexusAbAddonNotAvailableError } from '@westyx-nexus/sdk-react';

function CheckoutGate({ user }: { user: { id: string; plan: string } }) {
  const evaluateAB = useEvaluateAB();
  const [showV2, setShowV2] = useState(false);

  useEffect(() => {
    evaluateAB(['checkout.v2'], user.id, { plan: user.plan })
      .then((results) => setShowV2(results['checkout.v2'] === true))
      .catch((err) => {
        if (err instanceof NexusAbAddonNotAvailableError) {
          setShowV2(false);   // add-on disabled - fall back to control
        }
      });
  }, [evaluateAB, user]);

  return showV2 ? <CheckoutV2 /> : <Checkout />;
}
```

Rejected promise errors:

| Error                           | When                                                           |
| ------------------------------- | -------------------------------------------------------------- |
| `NexusAbAddonNotAvailableError` | HTTP 403 - the AB Testing add-on is not active for the tenant. |
| `NexusUnauthorizedError`        | HTTP 401 - invalid API key or slug/key mismatch.               |
| `NexusBillingError`             | HTTP 402 - tenant has overdue invoices.                        |
| `NexusNotFoundError`            | HTTP 404 - unknown subdomain or missing endpoint.              |

### `useSecret(key: string): string | undefined`

Read a secret value. **Returns `undefined`** if the client uses a public key, or if the key is missing - it never throws (this is the React-friendly variant of the imperative `getSecret`).

```tsx theme={null}
const stripeKey = useSecret('stripe.key');
```

In browser apps you'll typically be using a public key, so `useSecret` always returns `undefined`.

### `useNexusSyncedAt(): Date`

Last successful sync timestamp. Useful for "last refreshed N seconds ago" UIs.

```tsx theme={null}
const syncedAt = useNexusSyncedAt();
return <small>Last refreshed: {syncedAt.toLocaleTimeString()}</small>;
```

### `useNexusSync(): () => Promise<void>`

Returns a stable function that triggers a manual sync. Use sparingly - the SDK syncs automatically.

```tsx theme={null}
const sync = useNexusSync();

return <button onClick={() => sync()}>Refresh config</button>;
```

### `useNexusStreamStatus(): { connected: boolean }`

Reactive SSE state. Useful for surfacing a "live" / "polling" indicator.

```tsx theme={null}
const { connected } = useNexusStreamStatus();
return <span>{connected ? 'Live' : 'Polling'}</span>;
```

### `useNexus(): NexusClient`

Escape hatch - returns the underlying `NexusClient` instance for advanced use. Reads via this client are not reactive (don't subscribe to the cache). Use the typed hooks above unless you have a specific reason.

## Imperative `NexusClient` (rarely needed)

```ts theme={null}
const nexus = useNexus();

// Read API (non-reactive - for one-shot lookups)
nexus.getConfig<T>(key)        // T | undefined
nexus.getFlag(key, default?)   // boolean
nexus.getSecret(key)           // throws NexusPublicKeyError or NexusSecretNotFoundError
nexus.getAllConfigs()          // Map<string, unknown>
nexus.getAllFlags()            // Map<string, boolean>

// AB Testing (v0.3.0) - always hits the network, never cached
await nexus.evaluateAB(keys, userId, attributes?);  // Promise<Record<string, boolean>>

// Lifecycle
await nexus.sync();            // force a sync now, bypassing the TTL
nexus.connectStream();         // start SSE (idempotent)
nexus.disconnectStream();      // stop SSE
nexus.subscribe(listener);     // listener called on every snapshot replacement

// Metadata
nexus.keyType;                 // 'sk' | 'pk' - always 'pk' in browsers
nexus.syncedAt;                // Date
nexus.streamConnected;         // boolean
nexus.billingOverdue;          // boolean - true after the server returned HTTP 402
```

## Error types

```ts theme={null}
import {
  NexusError,                       // base class
  NexusInitError,                   // initial sync failure (cause carries detail)
  NexusUnauthorizedError,           // HTTP 401
  NexusBillingError,                // HTTP 402 - tenant has overdue invoices
  NexusAbAddonNotAvailableError,    // HTTP 403 from evaluateAB - add-on disabled
  NexusQuarantinedError,            // HTTP 429 quarantine - reason + expiresAt (v0.4.0)
  NexusNotFoundError,               // HTTP 404
  NexusPublicKeyError,              // imperative getSecret with public key
  NexusServiceKindMismatchError,    // imperative getSecret on kind=frontend service
  NexusSecretNotFoundError,         // imperative getSecret with unknown key
} from '@westyx-nexus/sdk-react';
```

`NexusInitError` is the only one fired during the provider's normal flow. The hook `useSecret` is non-throwing (returns `undefined`); the imperative `getSecret` throws.

## Type helpers

```ts theme={null}
import {
  PublicApiKey,        // branded string type - narrows public keys at compile time
  assertPublicKey,     // runtime guard - throws if key is not wxp_
} from '@westyx-nexus/sdk-react';
```

```ts theme={null}
const raw: string = import.meta.env.VITE_NEXUS_API_KEY;
assertPublicKey(raw);  // raw is now PublicApiKey

<NexusProvider config={{ baseUrl: '...', apiKey: raw }}>
```
