npm package: @genation/sdk-client
Description: OAuth 2.1 client for browser and SPA applications. Uses PKCE-only flow — no `client_secret` needed.
Latest version: 0.4.2

# @genation/sdk-client

OAuth 2.1 client for browser and SPA applications. Uses PKCE-only flow — no `client_secret` needed.

## Installation

```bash
npm install @genation/sdk-client
```

## Requirements

- Browser environment (vanilla JS, React, Vue, Svelte, Next.js, React Native...)
- OAuth 2.1 compatible authorization server

## Quick Start

```typescript
import { createPublicClient } from "@genation/sdk-client";

const client = createPublicClient({
    clientId: "your-client-id",
    redirectUri: "http://localhost:3000/callback",
});

// Listen to auth state changes
client.onAuthStateChange((event, session) => {
    if (event === "SIGNED_IN") {
        console.log("Welcome!", session?.user);
    }
});

// Start login — redirects to auth server
window.location.href = await client.signIn();
```

### Handle the callback

On your `/callback` page:

```typescript
await client.handleCallback(window.location.href);
// Redirects back to the page before login
```

### Check session

```typescript
const session = await client.getSession();
if (session) {
    console.log(session.user.email);
}
```

### Sign out

```typescript
await client.signOut();
```

## Configuration

```typescript
createPublicClient({
    clientId: string;        // Required — your OAuth client ID
    redirectUri: string;    // Required — callback URL
    scopes?: string[];      // Optional — default: []
    authUrl?: string;      // Optional — default: Genation Auth
    ffApiUrl?: string;      // Optional — for license/consumable API
    storage?: "localStorage" | "sessionStorage" | "memory"; // Default: "localStorage"
});
```

## API Reference

### `client.signIn()`

Starts OAuth login. Returns authorization URL to redirect to.

```typescript
window.location.href = await client.signIn();
```

### `client.handleCallback(url)`

Exchanges authorization code for tokens. Call on your callback page.

```typescript
await client.handleCallback(window.location.href);
```

### `client.getSession()`

Returns current session with auto-refresh.

```typescript
const session = await client.getSession();
```

### `client.signOut()`

Signs out and clears local tokens.

```typescript
await client.signOut();
```

### `client.onAuthStateChange(callback)`

Subscribes to authentication state changes.

```typescript
const { subscription } = client.onAuthStateChange((event, session) => {
    switch (event) {
        case "INITIAL_SESSION": break;
        case "SIGNED_IN":      break;
        case "SIGNED_OUT":     break;
        case "TOKEN_REFRESHED": break;
    }
});

// Cleanup
subscription.unsubscribe();
```

### `client.getLicenses()`

Fetches user's licenses.

```typescript
const licenses = await client.getLicenses();
```

### `client.getConsumables()`

Fetches user's consumables.

```typescript
const consumables = await client.getConsumables();
```

### `client.getConsumablePlans()`

Fetches available consumable plans.

```typescript
const plans = await client.getConsumablePlans();
```

## Session Object

```typescript
interface Session {
    accessToken: string;
    refreshToken?: string;
    expiresIn: number;
    expiresAt: number;
    user: User | null;
}
```

## Auth Events

| Event | Trigger |
|-------|---------|
| `INITIAL_SESSION` | First load |
| `SIGNED_IN` | Successful login |
| `SIGNED_OUT` | Sign out or expired session |
| `TOKEN_REFRESHED` | Access token auto-refreshed |

## Storage

Tokens are stored in `localStorage` by default. Choose a storage strategy:

| Storage | Use Case |
|---------|----------|
| `localStorage` | Persistent across browser sessions |
| `sessionStorage` | Cleared when tab closes |
| `memory` | No persistence (useful for tests) |

```typescript
const client = createPublicClient({
    clientId: "your-client-id",
    redirectUri: "...",
    storage: "sessionStorage",
});
```

## License

MIT