npm package: @liveai-test/liveai
Description: LiveAI JavaScript SDK (minimal starter)
Author: Your Name
Latest version: 0.3.0

# liveai — JavaScript SDK

A minimal, publish-ready JavaScript/TypeScript SDK skeleton inspired by the simplicity of LiveKit's JS SDK surface. Works in **browsers** (native `WebSocket`) and **Node** (optional `ws`). Ships **ESM + CJS + types**.

```bash
npm i @liveai-test/liveai
# Node only (provides WebSocket impl):
npm i ws
```

> **Note:** If `liveai` (unscoped) becomes available later, you can publish as `liveai` and install with `npm i liveai`.

---

## Quick start (dev)

```bash
npm install
npm run dev
```

## Build

```bash
npm run build
```

Outputs ESM and CJS bundles to `dist/` with types (`.d.ts`).

> Node consumers should install the optional `ws` peer dependency to provide a WebSocket implementation.

---

## Usage (Browser)

```ts
import { LiveAIClient } from '@liveai-test/liveai'; // or 'liveai' if you publish unscoped later

const client = new LiveAIClient({ appId: 'my-app', logLevel: 'info' });

await client.connect({
  url: 'wss://example.com/realtime?token=YOUR_TOKEN',

  // Reliability (defaults shown; override as needed)
  reconnect: {
    enabled: true,
    maxRetries: Infinity,
    minDelayMs: 250,
    maxDelayMs: 8000,
    factor: 2,
    jitter: 0.2
  },
  heartbeat: {
    pingIntervalMs: 15000,
    watchdogMs: 30000
  }
});

client.on('open',    () => console.log('connected'));
client.on('message', (data) => console.log('data:', data));
client.on('error',   (err) => console.error(err));

client.send({ type: 'ping' });

// later…
await client.close(1000, 'normal');
```

### Usage (Node ESM)

```bash
npm i @liveai-test/liveai ws
```

```js
import { LiveAIClient } from '@liveai-test/liveai';

const client = new LiveAIClient({ logLevel: 'info' });

await client.connect({
  url: 'wss://example.com/realtime?token=YOUR_TOKEN'
});

client.on('message', (m) => console.log('msg', m));
client.send({ type: 'ping' });

setTimeout(() => client.close(1000, 'normal'), 1500);
```

---

## API surface

### `class LiveAIClient(options?)`
```ts
type LiveAIClientOptions = {
  appId?: string;
  logLevel?: 'silent' | 'error' | 'warn' | 'info' | 'debug';
};
```

#### Events
`'open' | 'message' | 'error' | 'close'`
```ts
client.on('open' | 'message' | 'error' | 'close', handler);
client.off('open' | 'message' | 'error' | 'close', handler);
```

#### `connect(options): Promise<void>`
```ts
type ConnectOptions = {
  url: string;              // e.g. wss://host/realtime?token=XYZ
  protocols?: string[];
  timeoutMs?: number;       // default 10_000

  reconnect?: Partial<{
    enabled: boolean;       // default true
    maxRetries: number;     // default Infinity
    minDelayMs: number;     // default 250
    maxDelayMs: number;     // default 8000
    factor: number;         // default 2
    jitter: number;         // default 0.2
  }>;

  heartbeat?: Partial<{
    pingIntervalMs: number; // default 15000
    watchdogMs: number;     // default 30000
  }>;
};
```
- Exponential **auto-reconnect** with jitter  
- **Heartbeat** ping + **watchdog** (forces reconnect if idle too long)  
- **Offline send queue** buffers `.send()` until connected  
- **Timeout-guarded** `connect()`  

#### `send(payload: unknown): void`
- Strings go as-is; non-strings are JSON-encoded.
- Queued while disconnected (bounded).

#### `close(code?: number, reason?: string): Promise<void>`

---

## What goes on the backend?

* **Do not** put secrets in the SDK. The SDK runs in the browser / untrusted clients.
* Provide backend endpoints for things like **token minting** and any privileged operations (DB, billing, admin tasks).
* The SDK should call your public APIs; the server verifies/authorizes requests.

---

## Troubleshooting

- **Node:** “No WebSocket available.” → `npm i ws`  
- **Closed before open:** close happened during handshake; delay `close()` until `'open'`.  
- **Blocked connection:** corporate proxy/VPN/extension may block WS; try a local echo or another network.  
- **React dev shows duplicate init logs:** React 18 Strict Mode mounts effects twice; guard with a ref or remove `<React.StrictMode>` during testing.

---

## Publish to npm

1. Update `package.json` → `"name"` to the exact package you want (e.g., `@liveai-test/liveai` or later `liveai`).
2. Log in: `npm login`
3. Build: `npm run build`
4. Publish: `npm publish --access public`
   * For scoped packages (`@your-scope/liveai`), the `--access public` flag is required.

---

## Roadmap ideas

* ✅ Auto‑reconnect & heartbeats
* 🔜 Auth helper (fetch token from your server)
* 🔜 Room/session abstraction
* 🔜 Typed events & payload schemas
* 🔜 React/Vue bindings as separate packages
* 🔜 E2E tests against a mock server / local echo

---

## License

MIT © 2025 LiveAI