Source: https://www.hype-stack.dev/docs/frontend/websockets

# Working with WebSockets

WebSocket events are consumed through the `socketSdk` from `@/api/sdk`. Like the HTTP SDK, all events and payloads are
typed from the backend definitions.

## Setup

The socket SDK is created in `src/api/sdk.ts`:

```ts
import { createSocketSdk } from "@hyper-fetch/sockets";
import type { WsSocketSdk } from "@hype-stack/backend";

import { socket } from "./client";

export const socketSdk = createSocketSdk<typeof socket, WsSocketSdk>(socket);
```

## Listening for events

Use `useListener` from `@hyper-fetch/react` to subscribe to server-pushed events:

```tsx
import { useListener } from "@hyper-fetch/react";
import { socketSdk } from "@/api/sdk";

function NotificationBell() {
  const listener = useListener(socketSdk.notification.new.$listener);

  listener.onEvent(({ data: notification }) => {
    toast.info(notification.title);
  });

  return <BellIcon />;
}
```

## Emitting events

Use `useEmitter` for client-to-server events:

```tsx
import { useEmitter } from "@hyper-fetch/react";
import { socketSdk } from "@/api/sdk";

function MarkRead({ notificationId }: { notificationId: string }) {
  const { emit } = useEmitter(socketSdk.notification["mark-read"].$emitter);

  return <button onClick={() => emit({ data: { notificationId } })}>Mark as read</button>;
}
```

## Important rules

- **Always use `socketSdk` directly.** Don't create intermediate re-export files or alias variables for socket events.
- **Import payload types from `@hype-stack/backend`** when you need them explicitly (e.g., `WsNotificationPayload`).
- **Never use raw `useEffect` + `.listen()`** for socket subscriptions. The `useListener` hook handles cleanup and
  re-subscription automatically.
- New backend socket events appear on `socketSdk` automatically through the type bridge.
