# tiun SDK

The tiun SDK provides a simple API for integrating payments, subscriptions, and authentication into any website or app.

---

## Installation

```bash
npm install @tiun/sdk
```

---

## Quick Start

```typescript
import { tiun } from '@tiun/sdk';

tiun.init({
  snippetId: 'your-snippet-id',
  language: 'en', // set to your site's language
});

// Subscription checkout for a specific product
tiun.checkout({ productId: 'prod_monthly' });

// Time-based connect flow
tiun.start();
```

> **Set `language` to match your site.** If omitted, the snippet UI defaults to `'en'`. See all supported codes in the [Init options](#init-options) table below.

The snippet is loaded automatically from the backend when you call `tiun.init()` with a `snippetId`. No script tags or extra HTML are required.

---

## Configuration

### `tiun.init(config)`

Initialize the SDK. Call once at app startup.

```typescript
tiun.init({
  snippetId: 'your-snippet-id',
  language: 'en', // set to your site's language
  tone: 'formal',
  debug: false,
  sandbox: false,

  // Lifecycle callbacks
  onReady: () => {},
  onPaywallShow: (data) => {},
  onPaywallHide: (data) => {},
  onError: (error) => {},

  // Auth callbacks
  onUserChange: (event) => {},
  onLogin: (event) => {},
  onLogout: () => {}
});
```

### Init options

| Option          | Type                               | Default    | Description                                                        |
| --------------- | ---------------------------------- | ---------- | ------------------------------------------------------------------ |
| `snippetId`     | `string`                           | —          | **Required.** Your unique tiun snippet ID from the dashboard.      |
| `language`      | `string`                           | `'en'`     | Language for the snippet UI (e.g. `'en'`, `'de'`, `'fr'`). Set this to match your site; falls back to `'en'` if omitted. |
| `tone`          | `'formal' \| 'informal'`           | `'formal'` | UI tone/style.                                                     |
| `debug`         | `boolean`                          | `false`    | Enable console logging.                                            |
| `sandbox`       | `boolean`                          | `false`    | Use sandbox base URL instead of production.                        |
| `onReady`       | `() => void`                       | —          | Called when snippet is ready.                                      |
| `onPaywallShow` | `(data: PaywallShowEvent) => void` | —          | Called when paywall should be shown.                               |
| `onPaywallHide` | `(data: PaywallHideEvent) => void` | —          | Called when user has access.                                       |
| `onUserChange`  | `(data: UserChangeEvent) => void`  | —          | Called on every user state change (init, login, logout, checkout). |
| `onLogin`       | `(data: LoginEvent) => void`       | —          | Called when user logs in.                                          |
| `onLogout`      | `() => void`                       | —          | Called when user logs out.                                         |
| `onError`       | `(error: TiunError) => void`       | —          | Called on errors.                                                  |

---

## Authentication

tiun provides built-in passwordless authentication (OTP via SMS/email). Users authenticate once during checkout, and their session persists across visits.

### `tiun.login()`

Open the login modal for returning subscribers.

```typescript
tiun.login();
```

### `tiun.logout()`

Log the user out and clear the session.

```typescript
tiun.logout();
```

### `tiun.getUser()`

Returns the cached user state synchronously.

```typescript
const { isAuthenticated, user } = tiun.getUser();

if (isAuthenticated) {
  console.log('Logged in as', user.email);
  console.log('Product access:', user.productAccess);
}
```

Returns `GetUserResponse`:

| Property          | Type               | Description                               |
| ----------------- | ------------------ | ----------------------------------------- |
| `isAuthenticated` | `boolean`          | Whether the user has an active session.   |
| `user`            | `UserInfo \| null` | User details, or `null` if not logged in. |

### `UserInfo`

| Property        | Type       | Description                                 |
| --------------- | ---------- | ------------------------------------------- |
| `userId`        | `string`   | Unique user identifier.                     |
| `email`         | `string`   | User's email address.                       |
| `productAccess` | `string[]` | List of product IDs the user has access to. |

### `tiun.getUserVerificationToken()`

Returns a secure token that can be used for server-to-server user verification. The token is valid for 5 minutes. Returns `null` if the user is not authenticated.

```typescript
const token = await tiun.getUserVerificationToken();
```

Your backend can verify the token using your tiun API key from the business dashboard.

---

## Start & Checkout

tiun supports two flows:

- **Subscription checkout** (`checkout`) -- Opens the checkout flow for a specific product. Requires a `productId`.
- **Time-based connect** (`start`) -- Opens the connect flow without a specific product. Used for time-based access models.

### `tiun.checkout(options)`

Open the subscription checkout flow for a specific product.

```typescript
tiun.checkout({ productId: 'prod_monthly' });
```

| Option      | Type     | Description                                           |
| ----------- | -------- | ----------------------------------------------------- |
| `productId` | `string` | The product ID to checkout. From your tiun dashboard. |

---

### `tiun.start()`

Open the time-based connect flow.

```typescript
tiun.start();
```

## Events

Subscribe with `tiun.on()`. Returns an unsubscribe function.

### `ready`

Fired when the snippet has initialized and is ready to use.

```typescript
tiun.on('ready', () => {
  console.log('tiun is ready');
});
```

### `userChange`

Fired on every user state change -- initialization, login, logout, and checkout. This is the single event to track all user state transitions.

```typescript
tiun.on('userChange', (event) => {
  console.log('Event:', event.event);
  console.log('Authenticated:', event.isAuthenticated);
  console.log('User:', event.user);
});
```

| Property          | Type               | Description                                                                              |
| ----------------- | ------------------ | ---------------------------------------------------------------------------------------- |
| `event`           | `string`           | What triggered the change: `'init'`, `'login'`, `'logout'`, `'checkout'`, or `'update'`. |
| `isAuthenticated` | `boolean`          | Whether the user is currently authenticated.                                             |
| `user`            | `UserInfo \| null` | User details, or `null`.                                                                 |

### `login`

Fired specifically when a user logs in. Convenience event -- the same data is also available via `userChange`.

```typescript
tiun.on('login', (event) => {
  console.log('Welcome back,', event.user.email);
});
```

| Property | Type       | Description   |
| -------- | ---------- | ------------- |
| `user`   | `UserInfo` | User details. |

### `logout`

Fired when the user logs out.

```typescript
tiun.on('logout', () => {
  console.log('User logged out');
});
```

### `error`

Fired when an error occurs.

```typescript
tiun.on('error', (error) => {
  console.error('tiun error:', error.code, error.message);
});
```

| Property  | Type      | Description               |
| --------- | --------- | ------------------------- |
| `code`    | `string`  | Error code.               |
| `message` | `string`  | Error message.            |
| `details` | `unknown` | Additional error details. |

### All events

| Event         | Description                                                                                         |
| ------------- | --------------------------------------------------------------------------------------------------- |
| `ready`       | Snippet has initialized and is ready.                                                               |
| `userChange`  | User state changed. Payload: `UserChangeEvent`.                                                     |
| `login`       | User logged in. Payload: `LoginEvent`.                                                              |
| `logout`      | User logged out. No payload.                                                                        |
| `paywallShow` | Paywall should be shown (user doesn't have access). Payload: `{ isConnected: boolean }`.            |
| `paywallHide` | Paywall should be hidden (user has access). Payload: `{ sessionId: string, isConnected: boolean }`. |
| `error`       | An error occurred. Payload: `TiunError`.                                                            |

### Paywall events (payloads)

**paywallShow:** `{ isConnected: boolean }`  
**paywallHide:** `{ sessionId: string, isConnected: boolean }`

### One-time and unsubscribe

```typescript
tiun.once('login', (event) => console.log('First login:', event.user.email));

const unsubscribe = tiun.on('userChange', () => {});
unsubscribe();
```

---

## Properties

| Property               | Type               | Description                                    |
| ---------------------- | ------------------ | ---------------------------------------------- |
| `tiun.version`         | `string`           | SDK version.                                   |
| `tiun.isInitialized`   | `boolean`          | Whether `init()` has been called.              |
| `tiun.isReady`         | `boolean`          | Whether the snippet is ready.                  |
| `tiun.isAuthenticated` | `boolean`          | Whether the user has a valid session.          |
| `tiun.user`            | `UserInfo \| null` | Current user info, or `null` if not logged in. |

---

## Methods

| Method                            | Description                                                 |
| --------------------------------- | ----------------------------------------------------------- |
| `tiun.init(config)`               | Initialize the SDK. Call once at startup.                   |
| `tiun.start()`                    | Open the time-based connect flow.                           |
| `tiun.checkout(options)`          | Open the subscription checkout flow for a specific product. |
| `tiun.login()`                    | Open the login modal for returning subscribers.             |
| `tiun.logout()`                   | Log the user out and clear the session.                     |
| `tiun.getUser()`                  | Get cached user state (synchronous).                        |
| `tiun.getUserVerificationToken()` | Get a secure token for server-to-server verification.       |
| `tiun.setContent(options)`        | Update the current content context.                         |
| `tiun.on(event, callback)`        | Subscribe to an event. Returns unsubscribe function.        |
| `tiun.once(event, callback)`      | Subscribe to an event once. Returns unsubscribe function.   |
| `tiun.destroy()`                  | Destroy the SDK and clean up listeners.                     |
| `tiun.waitForReady()`             | Wait for the SDK to be ready. Returns a Promise.            |

### `tiun.setContent(options)`

Tell tiun what content the user is viewing.

```typescript
tiun.setContent({
  type: 'active',
  contentId: 'episode-123',
  mediaType: 'audio'
});
```

| Option      | Type                                 | Description                        |
| ----------- | ------------------------------------ | ---------------------------------- |
| `type`      | `'active' \| 'inactive' \| 'paused'` | **Required.** Content state.       |
| `contentId` | `string`                             | Unique identifier for the content. |
| `mediaType` | `'text' \| 'audio' \| 'video'`       | Type of media. Default: `'text'`.  |

---

## Framework examples

### Vue

```vue
<script setup lang="ts">
import { tiun } from '@tiun/sdk';
import { onMounted, onUnmounted } from 'vue';

onMounted(() => {
  tiun.init({ snippetId: 'your-snippet-id', language: 'en' });
});

onUnmounted(() => {
  tiun.destroy();
});
</script>

<template>
  <button @click="tiun.checkout({ productId: 'prod_monthly' })">
    Subscribe
  </button>
</template>
```

### React

```tsx
import { tiun } from '@tiun/sdk';
import { useEffect } from 'react';

function App() {
  useEffect(() => {
    tiun.init({ snippetId: 'your-snippet-id', language: 'en' });
    return () => tiun.destroy();
  }, []);

  return (
    <div>
      <button onClick={() => tiun.checkout({ productId: 'prod_monthly' })}>
        Subscribe
      </button>
    </div>
  );
}
```

### Vanilla JS

```html
<script src="https://cdn.tiun.io/sdk.js"></script>
<script>
  tiun.init({ snippetId: 'your-snippet-id', language: 'en' });
</script>

<button onclick="tiun.checkout({ productId: 'prod_monthly' })">
  Subscribe
</button>
```
