# 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
  appearance: 'auto' // 'light' | 'dark' | 'auto'
});

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

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

> **Set `language` to match your site.** Supported: `'en'`, `'de'`, `'fr'`. If omitted, the snippet UI defaults to `'en'`.
>
> **Set `appearance` to match your site's theme.** If omitted, the snippet uses `'light'`. See [Appearance](#appearance).

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',
  appearance: 'light',
  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`      | `'en' \| 'de' \| 'fr'`             | `'en'`       | Language for the snippet UI. Case-insensitive. Set this to match your site; unsupported values fall back to `'en'` with a console warning. |
| `tone`          | `'formal' \| 'informal'`           | `'informal'` | UI tone/style. Case-insensitive.                                                                                                           |
| `appearance`    | `'light' \| 'dark' \| 'auto'`      | `'light'`    | Color theme for the snippet UI. `'auto'` follows the visitor's OS setting. See [Appearance](#appearance).                                  |
| `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.                                                                                                                          |

---

## Appearance

The snippet ships with a light and a dark theme. Pick one at init, or let it follow the visitor's OS setting:

```typescript
tiun.init({ snippetId: 'your-snippet-id', appearance: 'auto' });
```

| Value     | Behavior                                                                                      |
| --------- | --------------------------------------------------------------------------------------------- |
| `'light'` | Light theme. **Default.**                                                                     |
| `'dark'`  | Dark theme.                                                                                   |
| `'auto'`  | Follows the visitor's OS setting (`prefers-color-scheme`) and re-themes live when it changes. |

Values are case-insensitive. An unsupported value logs a console warning and is ignored.

### `tiun.setAppearance(appearance)`

Switch the theme at runtime without a reload, e.g. when your site's theme toggle flips:

```typescript
// From your theme toggle:
tiun.setAppearance(isDark ? 'dark' : 'light');

// Or hand control back to the OS setting:
tiun.setAppearance('auto');
```

- Safe to call before `init()` or before the snippet is ready. A value set before `init()` is kept unless `init()` passes its own `appearance`.

---

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

### 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.setAppearance(appearance)`  | Switch the snippet to `'light'`, `'dark'` or `'auto'`. See [Appearance](#appearance). |
| `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'`.  |

---

## TypeScript

Types are bundled with the package — no extra install needed:

```typescript
import {
  tiun,
  type Appearance,
  type TiunConfig,
  type UserInfo
} from '@tiun/sdk';
```

Also exported: `CheckoutOptions`, `ContentOptions`, `ContentType`, `MediaType`, `SupportedLanguage`, `TiunError`, `PaywallShowEvent`, `PaywallHideEvent`, `UserChangeEvent`, `LoginEvent`, `GetUserResponse`, `TiunEventType`, `TiunSDK`.

---

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

No bundler? Load the ES module build from a CDN:

```html
<button id="subscribe">Subscribe</button>

<script type="module">
  import { tiun } from 'https://cdn.jsdelivr.net/npm/@tiun/sdk@0/tiun.js';

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

  document.getElementById('subscribe').addEventListener('click', () => {
    tiun.checkout({ productId: 'prod_monthly' });
  });
</script>
```
