> ## 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 - Stream Observer

> Opt-in structured callbacks for SSE lifecycle events in the React SDK.

Pass a `NexusStreamObserver` via `NexusConfig.streamObserver` to receive structured callbacks for every SSE lifecycle transition. The observer is the **canonical** way to wire SDK state into ops dashboards, custom telemetry, or load-test tooling - far more reliable than scraping `NexusLogger` output by substring match.

The observer is **opt-in**. When `streamObserver` is `undefined` the SDK uses `NOOP_STREAM_OBSERVER` at zero overhead.

## The interface

```ts theme={null}
import type { NexusStreamObserver } from '@westyx-nexus/sdk-react';

interface NexusStreamObserver {
  onConnected?(): void;
  onDisconnected?(cause: unknown | null): void;
  onEvent?(name: string): void;
  onReconnectAttempt?(attempt: number): void;
  onFallback?(reason: string): void;
  onQuarantined?(reason: string, expiresAt: Date): void;
}
```

Every method is **optional** - the SDK calls only the ones you set. You can write `{ onEvent: (n) => count(n) }` and ignore the rest.

## Hook semantics

| Hook                               | Fires when                                                                                                                     | Argument                                                                                     |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| `onConnected()`                    | The fetch stream connects and the server confirms the response body is readable (initial connect or an SDK reconnect succeeds) | none                                                                                         |
| `onDisconnected(cause)`            | The connection ends - `disconnectStream()`, transport error, or 3-strike fallback                                              | `null` for clean disconnect, the underlying `Error` for transport failures                   |
| `onEvent(name)`                    | A whitelisted SSE event arrives, **before** the SDK runs the event-triggered sync                                              | event name string (e.g. `"config.updated"`)                                                  |
| `onReconnectAttempt(n)`            | A transient stream transport error fires (the SDK will auto-reconnect with backoff)                                            | 1-based counter, max 3                                                                       |
| `onFallback(reason)`               | The SDK gives up after 3 consecutive errors, hits a non-quarantine 429 on stream pre-flight, or schedules a 5xx sync retry     | `FALLBACK_REASON_MAX_ERRORS`, `FALLBACK_REASON_RATE_LIMITED`, or `FALLBACK_REASON_TRANSPORT` |
| `onQuarantined(reason, expiresAt)` | The server returns 429 with `{"error":"quarantined"}` body (v0.4.0)                                                            | `reason: string`, `expiresAt: Date`                                                          |

### `onFallback` reasons

```ts theme={null}
import {
  FALLBACK_REASON_MAX_ERRORS,
  FALLBACK_REASON_RATE_LIMITED,
  FALLBACK_REASON_TRANSPORT, // v0.3.1+
} from '@westyx-nexus/sdk-react';
```

| Constant         | When                                                                                                                                                                                                         |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `'max-errors'`   | 3 consecutive stream transport errors - backoff exhausted                                                                                                                                                    |
| `'rate-limited'` | The SDK's `fetch` pre-flight to the stream URL returned `429 Too Many Requests` (non-quarantine). The SDK parses `Retry-After` and schedules a reconnect; the observer fires once per 429 episode. (v0.3.1+) |
| `'transport'`    | A 5xx response from `/v1/sync` triggered the exponential-backoff retry loop. The observer fires once per retry-scheduling; reset when the next sync succeeds. (v0.3.1+)                                      |

## Threading contract

<Warning>
  Observer methods MUST return promptly. The SDK calls them synchronously from the stream reader loop on the main thread. If your observer does anything substantial (network I/O, structured logging fan-out), copy the argument and dispatch the work to a future microtask.
</Warning>

```tsx theme={null}
onEvent: (name) => {
  queueMicrotask(() => doExpensiveWork(name));
}
```

## Counter pattern

```tsx theme={null}
import { NexusProvider, type NexusStreamObserver } from '@westyx-nexus/sdk-react';

const counters = { events: 0, reconnects: 0, fallbacks: 0 };
const observer: NexusStreamObserver = {
  onEvent:            ()  => counters.events++,
  onReconnectAttempt: ()  => counters.reconnects++,
  onFallback:         (r) => { counters.fallbacks++; console.warn('SSE fallback:', r); },
};

export function App() {
  return (
    <NexusProvider config={{
      baseUrl:        'https://...',
      apiKey:         'wxp_...',
      streamObserver: observer,
    }}>
      <RouterProvider router={router} />
    </NexusProvider>
  );
}
```

## Active-connection state pattern

Maintain a "live" indicator backed by state. The observer updates state from outside React's render cycle, so use a global store like Zustand / Jotai:

```tsx theme={null}
import { create } from 'zustand';
import type { NexusStreamObserver } from '@westyx-nexus/sdk-react';

const useStreamStore = create<{ connected: boolean; setConnected: (v: boolean) => void }>(
  (set) => ({ connected: false, setConnected: (v) => set({ connected: v }) })
);

const observer: NexusStreamObserver = {
  onConnected:    () => useStreamStore.getState().setConnected(true),
  onDisconnected: () => useStreamStore.getState().setConnected(false),
  onFallback:     () => useStreamStore.getState().setConnected(false),
};

function StatusIndicator() {
  const connected = useStreamStore((s) => s.connected);
  return <span className={connected ? 'on' : 'off'}>{connected ? 'Live' : 'Polling'}</span>;
}
```

For a built-in alternative without a state library, use the existing `useNexusStreamStatus()` hook - it returns the same `connected` boolean derived from the `streamConnected` getter.
