# SafePassage SDK v3.0.0 - Redirect Implementation

A lightweight SDK for integrating SafePassage age verification using a simple redirect flow.

## Features

- **Ultra-lightweight**: Only 4.9KB minified (1.9KB gzipped)
- **Simple integration**: Just 10 lines of code
- **Two modes**: Same-tab redirect or new-tab popup
- **TypeScript support**: Full type definitions included
- **Auto-environment detection**: Works seamlessly in development
- **Secure**: Merchant-generated session IDs prevent attacks
- **Compliant**: Enforces minimum age of 25

## Installation

```bash
npm install @safepassage/sdk
```

## Quick Start

```javascript
// Initialize SDK
const safePassage = new SafePassage({
  apiKey: 'sk_live_xxxxx',         // Your API key
  returnUrl: 'https://yoursite.com/verified',
  cancelUrl: 'https://yoursite.com/cancelled'
});

// Generate a session ID (must be UUID v4)
const sessionId = crypto.randomUUID();

// Trigger verification
safePassage.verify({ 
  sessionId: sessionId,             // Required: merchant-generated UUID
  challengeAge: 25,                 // Optional: minimum age (25 or higher)
  verificationMode: 'L1'            // Optional: 'L1' or 'L2'
});
```

## Configuration

| Option | Type | Required | Description |
|--------|------|----------|-------------|
| apiKey | string | Yes | Your API key (sk_live_xxx or sk_test_xxx) |
| returnUrl | string | Yes | URL to redirect after successful verification |
| cancelUrl | string | Yes | URL to redirect if user cancels |
| environment | string | No | 'production', 'staging', or 'development' (auto-detected) |
| mode | string | No | 'redirect' (default) or 'new-tab' |
| onComplete | function | No | Callback for new-tab mode completion |
| onCancel | function | No | Callback for new-tab mode cancellation |
| onError | function | No | Error handler |

## Verification Options

```javascript
safePassage.verify({
  sessionId: 'uuid-v4',        // Required: merchant-generated UUID
  challengeAge: 30,            // Optional: min 25 (overrides dashboard setting)
  verificationMode: 'L2'       // Optional: 'L1' or 'L2' (overrides dashboard setting)
});
```

### Configuration Override Behavior

When you pass `challengeAge` or `verificationMode` to the `verify()` method, these values take precedence over your dashboard configuration for that specific verification session:

- **No overrides**: Uses your current dashboard settings
- **With overrides**: SDK values are used instead of dashboard settings
- **Challenge age**: Must be 25 or higher (lower values will be rejected)
- **Verification mode**: 
  - `'L1'`: Age estimation with computer vision
  - `'L2'`: Always requires ID verification

Example use cases:
```javascript
// Use dashboard defaults
safePassage.verify({ sessionId: crypto.randomUUID() });

// Override just challenge age
safePassage.verify({ 
  sessionId: crypto.randomUUID(),
  challengeAge: 30  // Require age 30+ for this session
});

// Override just verification mode
safePassage.verify({ 
  sessionId: crypto.randomUUID(),
  verificationMode: 'L2'  // Force ID check for this session
});

// Override both
safePassage.verify({ 
  sessionId: crypto.randomUUID(),
  challengeAge: 30,
  verificationMode: 'L2'  // ID required for 30+ verification
});
```

## Modes

### Same-Tab Redirect (Default)
User is redirected to SafePassage, then back to your site:

```javascript
const safePassage = new SafePassage({
  apiKey: 'sk_live_xxxxx',
  returnUrl: '/age-verified',
  cancelUrl: '/age-gate'
});

safePassage.verify({ sessionId: crypto.randomUUID() });
```

### New-Tab Mode
Verification opens in a popup window:

```javascript
const safePassage = new SafePassage({
  apiKey: 'sk_live_xxxxx',
  returnUrl: '/age-verified',
  cancelUrl: '/age-gate',
  mode: 'new-tab',
  onComplete: (result) => {
    console.log('Verified:', result.sessionId);
    // Validate on your server!
  },
  onCancel: () => {
    console.log('User cancelled');
  }
});

safePassage.verify({ sessionId: crypto.randomUUID() });
```

## Server-Side Validation (Required!)

Always validate the session on your server:

```javascript
// Node.js example
const response = await fetch('https://api.safepassageapp.com/v1/sessions/validate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_xxxxx', // Secret key
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ sessionId })
});

const result = await response.json();
if (result.verified && result.estimatedAge >= result.challengeAge) {
  // Grant access
}
```

## UUID Generation

You must generate session IDs on your end. Use the built-in crypto.randomUUID() when available:

```javascript
// Modern browsers and Node.js 16+
const sessionId = crypto.randomUUID();

// Fallback for older environments
function generateUUID() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}
```

## Complete Example

```html
<!DOCTYPE html>
<html>
<head>
  <!-- Install via NPM: npm install @safepassage/sdk -->
  <script src="node_modules/@safepassage/sdk/dist/safepassage.min.js"></script>
</head>
<body>
  <button onclick="verifyAge()">Verify Your Age</button>

  <script>
    const safePassage = new SafePassage({
      apiKey: 'sk_live_xxxxx',
      returnUrl: window.location.href + '?verified=true',
      cancelUrl: window.location.href
    });

    function verifyAge() {
      // Use crypto.randomUUID() if available, otherwise fallback
      const sessionId = typeof crypto.randomUUID === 'function' 
        ? crypto.randomUUID()
        : 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            const r = Math.random() * 16 | 0;
            const v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
          });
      
      sessionStorage.setItem('pendingVerification', sessionId);
      safePassage.verify({ sessionId });
    }

    // Check if returning from verification
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.get('verified') === 'true') {
      const sessionId = sessionStorage.getItem('pendingVerification');
      // Validate session server-side here
      console.log('Validate session:', sessionId);
    }
  </script>
</body>
</html>
```

## TypeScript

Full TypeScript support included:

```typescript
import { SafePassage, SafePassageConfig } from '@safepassage/sdk';

const config: SafePassageConfig = {
  apiKey: process.env.SAFEPASSAGE_PUBLIC_KEY!,
  returnUrl: '/verified',
  cancelUrl: '/cancelled'
};

const safePassage = new SafePassage(config);
```

## Migration from v2 (iframe)

Old iframe approach (1000+ lines):
```javascript
// Complex iframe setup...
```

New redirect approach (10 lines):
```javascript
const safePassage = new SafePassage({
  apiKey: 'sk_live_xxxxx',
  returnUrl: '/verified',
  cancelUrl: '/cancelled'
});
safePassage.verify({ sessionId: crypto.randomUUID() });
```

## Browser Support

- Chrome 60+
- Firefox 60+
- Safari 12+
- Edge 79+
- Mobile browsers

## Security Notes

1. Always generate session IDs on the merchant side
2. Validate sessions server-side before granting access
3. Pre-register callback URLs in your dashboard
4. Never expose your secret key (sk_live_xxx)