> ## 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 - SSE Live Updates

> How SSE live propagation works in the React SDK, including 429 handling and SSR.

The SDK opens a persistent `fetch`-based SSE connection to `GET <baseUrl>/v1/stream` after the initial sync completes. The API key is sent as the `X-Nexus-API-Key` request header - the same header used by all other endpoints. Whenever the Nexus backend emits a change event (`config.updated`, `flag.toggled`, `resync`, ...), the SDK triggers an immediate full re-sync - so the in-memory cache is updated within milliseconds of a change. Components subscribed via hooks re-render automatically.

## Authentication

The React SDK sends the API key as the `X-Nexus-API-Key` header on the stream connection. Unlike the browser `EventSource` API - which cannot set custom request headers - the `fetch` API supports headers on streaming responses, so no `?key=` query-parameter workaround is needed. The key never appears in the URL, server access logs, or browser history.

<Info>
  Secret keys (`wxs_…`) are rejected at `NexusClient.create()` time. Only public keys (`wxp_…`) may be used with browser SDKs.
</Info>

## React rendering integration

Stream events are processed in the `fetch` reader loop, outside React's render cycle - but because the SDK's hooks use `useSyncExternalStore`, this is invisible to your components. When an SSE event triggers a sync, the SDK swaps the snapshot atomically and notifies subscribed hooks; React's reconciler then re-renders the affected components in a single batched pass.

You don't need to do anything special - just use the hooks normally.

## Reconnection

The SDK manages reconnection itself - it does not rely on the browser `EventSource` auto-reconnect (there is no `EventSource`). After a transport failure the SDK schedules a reconnect with exponential backoff (1 s → 30 s capped). Any `retry:` field sent by the server is ignored.

On every (re)connect the server emits a `resync` event, which causes the SDK to call `sync()` once and align with the current state. There is no event history; missed events are not replayed.

After **3 consecutive transport errors** the SDK closes the stream and falls back to TTL polling, emitting `FALLBACK_REASON_MAX_ERRORS`. The SDK then automatically schedules an SSE reconnect using the `sseReconnectCooldown` schedule (default: 5 → 10 → 20 → 40 → 60 min). When the timer fires, the failure counter resets and `connectStream()` is called automatically. *(v0.6.0)*

```
nexus: SSE transport error (attempt 1/3)
nexus: SSE transport error (attempt 2/3)
nexus: SSE 3 consecutive errors - falling back to polling
nexus: SSE reconnect scheduled in 5 min
```

Use `useNexusStreamStatus()` to surface this to users:

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

## `429 Too Many Requests`

Every project tier has a per-service stream connection limit:

| Tier   | Connections |
| ------ | ----------- |
| `free` | 5           |
| `xs`   | 10          |
| `s`    | 25          |
| `m`    | 50          |
| `l`    | 150         |
| `xl`   | 500         |

### Detection

Because the SDK opens the stream with `fetch`, it sees the HTTP status directly on the response. When the stream connection returns 429 the SDK:

1. Emits `FALLBACK_REASON_RATE_LIMITED` on the stream observer.
2. Checks for a `Retry-After` header (delta-seconds, clamped to `[5 s, 300 s]`):
   * **Present:** schedules a `connectStream()` re-entry after the indicated delay.
   * **Absent:** falls back to TTL polling and schedules reconnect via the `sseReconnectCooldown` schedule. *(v0.6.0)*
3. Does NOT reopen the stream until the delay elapses.

A 429 whose body is `{"error":"quarantined"}` instead fires `onQuarantined(reason, expiresAt)` and reconnects after the quarantine window.

## Disabling SSE

The SDK calls `connectStream()` automatically. To opt out at runtime via the imperative client:

```tsx theme={null}
import { useNexus } from '@westyx-nexus/sdk-react';

function OfflineToggle() {
  const nexus = useNexus();
  return <button onClick={() => nexus.disconnectStream()}>Go offline</button>;
}
```

## What events trigger a sync

| Event                                                 | Received by public keys |
| ----------------------------------------------------- | ----------------------- |
| `resync`                                              | yes                     |
| `config.created` / `.updated` / `.deleted`            | yes                     |
| `flag.created` / `.updated` / `.toggled` / `.deleted` | yes                     |
| `secret.*`                                            | filtered server-side    |

## Lifecycle

Stream connection is automatic on `NexusProvider` mount and teardown is automatic on unmount. Manual `connectStream()` / `disconnectStream()` via `useNexus()` is available but rarely needed.

## SSR / Next.js

The fetch-based stream is browser-only and the SDK skips it during server-side rendering. If you're using Next.js App Router, mark the file containing `NexusProvider` as a client component:

```tsx theme={null}
// app/providers.tsx
'use client';

import { NexusProvider } from '@westyx-nexus/sdk-react';
// ...
```

The provider only opens the SSE connection on mount, so server-rendered HTML is unaffected.
