# lightswitch-js

[![npm version](https://badge.fury.io/js/lightswitch-js.svg)](https://badge.fury.io/js/lightswitch-js)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A minimal SDK for subscription management, entitlements, and paywalls.

## 📦 Installation

```bash
npm install lightswitch-js
```

```bash
yarn add lightswitch-js
```

```bash
pnpm add lightswitch-js
```

## 📁 Project Structure

```
lightswitch-sdk-js/
├── index.js                    # Main entry point
├── README.md                   # This file
│
├── components/                 # React Components
│   ├── LightswitchProvider.jsx # Main provider component
│   └── ProtectedRoute.jsx      # Route protection component
│
├── hooks/                      # React Hooks
│   ├── useLightswitch.js       # Main SDK hook
│   ├── useAuth.js              # Authentication hook
│   └── useEntitlement.js       # Entitlement checking hook
│
├── core/                       # Core Vanilla JS
│   ├── index.js                # Core SDK entry
│   ├── api.js                  # API communication
│   ├── auth.js                 # Authentication logic
│   ├── config.js               # Configuration
│   ├── entitlement.js          # Entitlement checking
│   ├── paywall.js              # Paywall rendering
│   └── tracking.js             # Analytics
│
└── examples/                   # Usage Examples
    ├── basic-setup.js          # Minimal setup
    ├── advanced-usage.js       # Advanced features
    └── test-without-supabase.js # Core testing
```

## 🚀 Quick Start

### 1. Basic Setup (Recommended)

```jsx
import React from 'react';
import { LightswitchProvider, ProtectedRoute } from 'lightswitch-js';
import { supabase } from './your-supabase-client';

const App = () => (
  <LightswitchProvider 
    publishableKey="pk_your-app_your-key" 
    appSlug="your-app"
    supabaseClient={supabase}
    autoShowPaywall={true}
  >
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Landing />} />
        <Route path="/app" element={
          <ProtectedRoute>
            <Dashboard />
          </ProtectedRoute>
        } />
      </Routes>
    </BrowserRouter>
  </LightswitchProvider>
);
```

### 2. Advanced Usage

```jsx
import { useLightswitch, useEntitlement } from 'lightswitch-js';

const MyComponent = () => {
  const { showPaywall, redirectToLogin } = useLightswitch();
  const { entitled, loading } = useEntitlement('has_access');
  
  if (!entitled) {
    return <button onClick={showPaywall}>Upgrade</button>;
  }
  
  return <div>Premium content!</div>;
};
```

## 📚 API Reference

### Components

#### `LightswitchProvider`
Main provider that wraps your app and handles SDK initialization.

**Props:**
- `publishableKey` (string) - Your app's publishable key
- `appSlug` (string) - Your app slug
- `supabaseClient` (optional) - Supabase client for auth integration
- `autoShowPaywall` (boolean) - Auto-show paywall when not entitled

#### `ProtectedRoute`
Component that protects routes based on entitlements.

**Props:**
- `children` (ReactNode) - Content to show when entitled
- `feature` (string) - Feature to check (defaults to "has_access")

### Hooks

#### `useLightswitch()`
Main hook for SDK functionality.

**Returns:**
- `showPaywall()` - Show paywall modal
- `redirectToLogin()` - Redirect to login
- `redirectToSignup()` - Redirect to signup
- `isInitialized` - SDK initialization status

#### `useEntitlement(feature, options)`
Hook for checking entitlements.

**Parameters:**
- `feature` (string) - Feature to check
- `options.checkOnMount` (boolean) - Check on component mount

**Returns:**
- `entitled` (boolean) - Whether user is entitled
- `loading` (boolean) - Loading state
- `error` (string) - Error message if any

#### `useLightswitchAuth()`
Hook for authentication state.

**Returns:**
- `isAuthenticated` (boolean) - Auth status
- `user` (object) - User info
- `logout()` - Logout function
- `setSupabaseSession(token)` - Set Supabase session from external token

## 🔧 Core Features

### ✅ 7 Key Functionalities:
1. **Redirecting for sign up** - `useLightswitch().redirectToSignup()`
2. **Redirecting to Login** - `useLightswitch().redirectToLogin()`
3. **Auth token sets supabase session** - Automatic via `useAuth.js`
4. **Initialization** - Via `LightswitchProvider`
5. **Check for entitlement** - Via `useEntitlement` hook
6. **Rendering Paywall** - Via `showPaywall()` function
7. **Analytics** - Via `trackEvent()` function

## 📖 Examples

See the `/examples` folder for complete usage examples:
- `basic-setup.js` - Minimal integration
- `advanced-usage.js` - Using hooks for control
- `external-auth-flow.js` - Handle external auth flows (funnels)
- `test-without-supabase.js` - Core functionality testing

## 🔗 External Auth Integration

### ✨ **Automatic (Recommended)**

The SDK automatically handles external auth tokens (like from funnels) with **zero additional code**:

```javascript
// That's it! The SDK handles everything automatically
<LightswitchProvider 
  publishableKey="pk_your-key" 
  appSlug="your-app"
  supabaseClient={supabaseClient}
  autoExternalAuth={true} // 👈 Default: true
>
  <YourApp />
</LightswitchProvider>
```

**What happens automatically:**
1. User returns from funnel with `?token=SUPABASE_TOKEN`
2. SDK detects token during initialization
3. Sets Supabase session and updates auth state
4. Cleans up URL parameters
5. User sees authenticated app immediately

### 🛠️ **Manual (If Needed)**

If you need custom control:

```javascript
// Method 1: Using the hook
const { setSupabaseSession } = useLightswitch();
await setSupabaseSession(token);

// Method 2: Direct import
import { setSupabaseSession } from 'lightswitch-js';
await setSupabaseSession(token);

// Method 3: Complete control
import { handleExternalAuthReturn } from 'lightswitch-js';
await handleExternalAuthReturn({ redirectPath: '/dashboard' });
```

## 💳 Customer Portal (Billing Management)

Allow users to manage their subscriptions, update payment methods, and view billing history through Stripe's customer portal.

### Automatic DOM Binding (Easiest)

The SDK automatically finds and binds to elements with the `data-lightswitch-customer-portal` attribute:

```html
<!-- Simple portal button -->
<button data-lightswitch-customer-portal>Manage Billing</button>

<!-- With custom return URL -->
<button data-lightswitch-customer-portal="/dashboard">Account Settings</button>

<!-- Works on any clickable element -->
<a href="#" data-lightswitch-customer-portal="/account">Billing Portal</a>
```

### React Hook

```javascript
import { useCustomerPortal } from 'lightswitch-js';

function AccountSettings() {
  const { handleCustomerPortal, canAccessPortal } = useCustomerPortal();

  if (!canAccessPortal) {
    return <div>Please log in to manage billing.</div>;
  }

  return (
    <button onClick={() => handleCustomerPortal('/dashboard')}>
      Manage Billing
    </button>
  );
}
```

### Vanilla JavaScript

```javascript
import Lightswitch from 'lightswitch-js';

// Redirect to customer portal
await Lightswitch.redirectToCustomerPortal('/dashboard');

// Or get portal URL for custom handling
const portalUrl = await Lightswitch.createCustomerPortal('/account');
window.open(portalUrl, '_blank');
```

### Error Handling

The customer portal requires:
- Authenticated user (401 → redirect to login)
- User with payment history (400 → redirect to pricing)

```javascript
try {
  await handleCustomerPortal('/dashboard');
} catch (error) {
  if (error.message.includes('401')) {
    // Redirect to login
  } else if (error.message.includes('400')) {
    // User needs to make a purchase first
  }
}
```

## 🏗️ Architecture

The SDK is organized into three layers:

1. **Components** - React components for easy integration
2. **Hooks** - React hooks for advanced control
3. **Core** - Vanilla JS functionality that works anywhere

This structure makes it easy to understand, maintain, and extend the SDK while keeping the integration footprint minimal.