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

# Vue SDK - Stream Observer

> Opt-in structured callbacks for SSE lifecycle events in the Vue 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-vue';

interface NexusStreamObserver {
  onConnected?(): void;
  onDisconnected?(cause: unknown | null): void;
  onEvent?(name: string): void;
  onReconnectAttempt?(attempt: number): void;
  onFallback?(reason: string): void;
  /** Fires when the server returns 429 with {"error":"quarantined"} body. (v0.4.0) */
  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 and stops the stream                                                               | `FALLBACK_REASON_MAX_ERRORS` or `FALLBACK_REASON_RATE_LIMITED`             |
| `onQuarantined(reason, expiresAt)` *(v0.4.0)* | Server returns 429 with `{"error":"quarantined"}` body on sync or SSE pre-flight                                               | `reason` string (server-supplied quarantine kind), `expiresAt` Date        |

### `onFallback` reasons

```ts theme={null}
import { FALLBACK_REASON_MAX_ERRORS, FALLBACK_REASON_RATE_LIMITED } from '@westyx-nexus/sdk-vue';
```

| 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+) |

<Note>
  A `429` response with `{"error":"quarantined"}` body does NOT fire `onFallback`. It fires `onQuarantined` instead (v0.4.0). The stream failure counter is not incremented for quarantine reconnects.
</Note>

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

```ts theme={null}
const observer: NexusStreamObserver = {
  onEvent: (name) => queueMicrotask(() => doExpensiveWork(name)),
};
```

## Counter pattern

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

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); },
};

const app = createApp(App);
await provideNexus(app, {
  baseUrl:        'https://...',
  apiKey:         'wxp_...',
  streamObserver: observer,
});
app.mount('#app');
```

## Active-connection state pattern

Vue's reactive primitives make this clean - wire the observer to a `ref` defined outside any component setup function:

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

export const streamConnected = ref(false);

export const observer: NexusStreamObserver = {
  onConnected:    () => { streamConnected.value = true;  },
  onDisconnected: () => { streamConnected.value = false; },
  onFallback:     () => { streamConnected.value = false; },
};
```

In a component:

```vue theme={null}
<template>
  <span :class="streamConnected ? 'on' : 'off'">
    {{ streamConnected ? 'Live' : 'Polling' }}
  </span>
</template>

<script setup lang="ts">
import { streamConnected } from './observer';
</script>
```

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