npm package: @subscribe.dev/client
Description: JavaScript/TypeScript client for SubscribeDev API - A drop-in for AI generation across 100+ models with built-in billing and rate limiting
Latest version: 0.0.111

# @subscribe.dev/client

A JavaScript SDK for AI model inference with integrated billing, rate limiting, and user management. Subscribe.dev provides access to curated AI models with built-in cost tracking and analytics through a unified API.

## Features

- 🚀 **100+ AI Models** - Curated collection of state-of-the-art models for various use cases
- 💰 **Integrated Billing** - Transparent pricing with automatic cost tracking and detailed usage analytics
- 🔒 **Secure Authentication** - Dual-layer authentication with project and user-level access control
- ⚡ **Rate Limiting** - Built-in request queuing with configurable limits and retry logic
- 📊 **Usage Analytics** - Real-time tracking of requests, costs, and performance metrics
- 🔐 **User Storage** - Session data persistence and user preferences management
- 📱 **JavaScript Support** - Works in Node.js, browser, and JavaScript runtime environments
- 🛡️ **Error Handling** - Comprehensive error types with detailed context and retry mechanisms
- 🎯 **Easy Integration** - Compatible with existing JavaScript AI workflows

## Getting Started

### 1. Create a Subscribe.dev Account

1. Visit [Subscribe.dev](https://subscribe.dev) and create an account
2. Create a new project in your dashboard
3. Copy your project API key (starts with `pub_`) from the project overview
4. Leave defaults-- or configure your users' plans, features and limits

### 2. Installation

```bash
npm install @subscribe.dev/client
# or
yarn add @subscribe.dev/client
# or
bun add @subscribe.dev/client
```

### 3. Quick Start

```typescript
import { SubscribeDevClient } from '@subscribe.dev/client'

// Initialize the client with your [Subscribe.dev](https://subscribe.dev) credentials
const client = new SubscribeDevClient({
  apiKey: 'pub_your_project_api_key', // From your [Subscribe.dev](https://subscribe.dev) project dashboard
  userKey: 'your_user_token'          // From your [Subscribe.dev](https://subscribe.dev) account
})

// Run any AI model with a single API call
const result = await client.run('black-forest-labs/flux-schnell', {
  input: {
    prompt: 'A majestic mountain landscape at sunset',
    num_inference_steps: 4,
    guidance_scale: 3.5
  }
})

console.log('Generated image:', result.output)
```

## Configuration

### SubscribeDevClientConfig

```typescript
interface SubscribeDevClientConfig {
  /** Public API key (project bearer token) - required */
  apiKey: string
  
  /** User token for user-specific limits and features */
  userKey: string
  
  
  /** Request timeout in milliseconds (default: 300000 = 5 minutes) */
  timeout?: number
  
  /** Maximum retry attempts (default: 2) */
  maxRetries?: number
  
  /** Enable debug logging (default: false) */
  debug?: boolean
}
```

## API Reference

### Core Methods

#### `run(model, options)`
The main method for running predictions. Returns completed results.

```typescript
await client.run(
  'black-forest-labs/flux-schnell',
  {
    input: {
      prompt: 'A beautiful landscape',
      width: 1024,
      height: 1024
    },
    webhook?: 'https://your-site.com/webhook',
    webhook_events_filter?: ['completed', 'failed']
  }
)
```

**Returns:** `Promise<Prediction>` - Completed prediction with output

#### `createPrediction(model, options)`
Create a prediction and return immediately (legacy method).

```typescript
const prediction = await client.createPrediction('model-name', {
  input: { prompt: 'test' }
})
```

### Balance & Billing

#### `getBalance()`
Get current project and user credit balances.

```typescript
const balance = await client.getBalance()
console.log('Project credits:', balance.project.remainingCredits)
console.log('User credits:', balance.user?.remainingCredits)
```

**Returns:** `Promise<BalanceInfo>`

```typescript
interface BalanceInfo {
  project: ProjectBalance
  user?: UserBalance
}

interface ProjectBalance {
  projectId: string
  totalCredits: number
  usedCredits: number
  remainingCredits: number
  lastUpdated: Date
}
```

#### `getTransactions(options?)`
Retrieve transaction history with filtering.

```typescript
const history = await client.getTransactions({
  limit: 50,
  offset: 0,
  status: 'completed',
  model: 'black-forest-labs/flux-schnell',
  startDate: '2024-01-01',
  endDate: '2024-12-31'
})
```

**Returns:** `Promise<TransactionHistory>`

### Rate Limiting

#### `getRateLimits()`
Get current rate limit status.

```typescript
const limits = await client.getRateLimits()
console.log('Concurrent requests:', limits.concurrent.currentRequests)
console.log('Hourly limit reached:', !limits.hour?.allowed)
```

### User Storage

#### `getStorage(options?)`
Retrieve user session data.

```typescript
const storage = await client.getStorage({ appVersion: 'v1.0' })
console.log('Session data:', storage.sessionData)
```

#### `setStorage(sessionData, options?)`
Update user session data.

```typescript
await client.setStorage(
  { preferences: { theme: 'dark' }, gameState: { level: 5 } },
  { appVersion: 'v1.0' }
)
```

#### `deleteStorage(options?)`
Clear user session data.

```typescript
await client.deleteStorage({ appVersion: 'v1.0' })
```

### File Uploads

#### `uploadFile(file, options?)`
Upload user files and get back a public S3 URL.

```typescript
const imageUrl = await client.uploadFile(file)
// Returns: "https://bucket.s3.amazonaws.com/uploads/..."

// With user context
const imageUrl = await client.uploadFile(file, { userId: 'user-123' })
```

### Browser Convenience Methods

#### `persistSessionData(options?)`
Sync session data to localStorage (browser only).

```typescript
// Automatically saves to localStorage and server
const storage = await client.persistSessionData()
```

#### `getSessionData(options?)`
Get session data with localStorage caching.

```typescript
// Always fetches from server, updates localStorage cache
const sessionData = await client.getSessionData()
```

### Subscription Management

#### `getSubscriptionStatus()`
Get user subscription information (requires userKey).

```typescript
// Requires userKey in client configuration
const subscription = await client.getSubscriptionStatus()

if (subscription.hasActiveSubscription) {
  console.log('Plan:', subscription.plan?.name)
  console.log('Credits:', subscription.plan?.tokenLimit)
}
```

## Authentication

Subscribe.dev uses a dual authentication system:

### Project API Keys
- **Format:** `pub_[base64_jwt_token]`
- **Scope:** Project-level access and billing
- **Location:** Get from [Subscribe.dev](https://subscribe.dev) dashboard → Project → Overview tab
- **Usage:** Required for all requests

```typescript
const client = new SubscribeDevClient({
  apiKey: 'pub_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})
```

### User Tokens (Required)
- **Scope:** User-specific limits and storage
- **Usage:** Per-user rate limiting and session management

```typescript
const client = new SubscribeDevClient({
  apiKey: 'pub_your_project_key',
  userKey: 'user_specific_token'
})
```

## Error Handling

The client provides specific error types for different scenarios:

```typescript
import { 
  SubscribeDevClient, 
  InsufficientBalanceError, 
  RateLimitError,
  AuthenticationError,
  ValidationError
} from '@subscribe.dev/client'

try {
  const result = await client.run('model-name', { input: {} })
} catch (error) {
  if (error instanceof InsufficientBalanceError) {
    console.log('Remaining credits:', error.details?.remainingCredits)
    console.log('Required credits:', error.details?.requiredCredits)
    console.log('Pricing page:', client.pricingUrl)
  } else if (error instanceof RateLimitError) {
    console.log('Rate limited until:', error.resetTime)
    console.log('Retry after seconds:', error.retryAfter)
  } else if (error instanceof AuthenticationError) {
    console.log('Invalid API key or user token')
  } else if (error instanceof ValidationError) {
    console.log('Invalid request:', error.details)
  }
}
```

### Error Types

- **`SubscribeDevError`** - Base error class
- **`InsufficientBalanceError`** - Not enough credits (402)
- **`RateLimitError`** - Rate limit exceeded (429)
- **`AuthenticationError`** - Invalid credentials (401)
- **`AccessDeniedError`** - Permission denied (403)
- **`NotFoundError`** - Resource not found (404)
- **`ValidationError`** - Invalid request data (400)

## Usage Examples

### Basic Image Generation

```typescript
import { SubscribeDevClient } from '@subscribe.dev/client'

const client = new SubscribeDevClient({
  apiKey: process.env.SUBSCRIBE_DEV_API_KEY!
})

const result = await client.run('black-forest-labs/flux-schnell', {
  input: {
    prompt: 'A cyberpunk cityscape at night, neon lights, 4k',
    num_inference_steps: 4,
    guidance_scale: 3.5,
    width: 1024,
    height: 1024
  }
})

console.log('Generated images:', result.output) // Array of image URLs
```

### With User Token and Error Handling

```typescript
import { SubscribeDevClient, InsufficientBalanceError } from '@subscribe.dev/client'

const client = new SubscribeDevClient({
  apiKey: process.env.SUBSCRIBE_DEV_API_KEY!,
  userKey: process.env.USER_TOKEN!, // User-specific limits
  debug: true
})

try {
  // Check balance first
  const balance = await client.getBalance()
  console.log('Available credits:', balance.project.remainingCredits)

  if (balance.project.remainingCredits < 10) {
    console.log('Low credits! Consider upgrading:', client.pricingUrl)
  }

  // Run prediction
  const result = await client.run('stability-ai/sdxl', {
    input: {
      prompt: 'A majestic dragon in a fantasy landscape'
    }
  })

  console.log('Success!', result.output)

  // Check updated balance
  const newBalance = await client.getBalance()
  const used = balance.project.remainingCredits - newBalance.project.remainingCredits
  console.log('Credits used:', used)

} catch (error) {
  if (error instanceof InsufficientBalanceError) {
    console.error('Need more credits:', error.details)
  } else {
    console.error('Error:', error.message)
  }
}
```

### Session Storage Example

```typescript
const client = new SubscribeDevClient({
  apiKey: process.env.SUBSCRIBE_DEV_API_KEY!,
  userKey: process.env.USER_TOKEN! // Required for storage
})

// Load existing session data
const existingData = await client.getSessionData()
console.log('Previous session:', existingData)

// Update session with new data
await client.setStorage({
  ...existingData,
  lastModel: 'black-forest-labs/flux-schnell',
  generationCount: (existingData.generationCount || 0) + 1,
  preferences: {
    defaultSteps: 4,
    favoriteStyles: ['photorealistic', 'cinematic']
  }
})

// In browser environments, also sync to localStorage
if (typeof window !== 'undefined') {
  await client.persistSessionData()
}
```

### Transaction History and Analytics

```typescript
// Get recent completed transactions
const history = await client.getTransactions({
  limit: 20,
  status: 'completed'
})

console.log(`Found ${history.transactions.length} transactions`)

// Calculate total spending
const totalCost = history.transactions.reduce(
  (sum, tx) => sum + (tx.actualCost || tx.estimatedCost), 
  0
)
console.log('Total spent:', totalCost, 'credits')

// Find most used models
const modelUsage = history.transactions.reduce((acc, tx) => {
  acc[tx.modelName] = (acc[tx.modelName] || 0) + 1
  return acc
}, {} as Record<string, number>)

console.log('Model usage:', modelUsage)
```

### Rate Limit Monitoring

```typescript
// Check current rate limits
const limits = await client.getRateLimits()

console.log('Rate limit status:')
console.log(`Concurrent: ${limits.concurrent.currentRequests}/${limits.concurrent.maxRequests}`)

if (limits.minute) {
  console.log(`Per minute: ${limits.minute.currentRequests}/${limits.minute.maxRequests}`)
  console.log(`Resets at: ${limits.minute.resetTime}`)
}

if (limits.hour) {
  console.log(`Per hour: ${limits.hour.currentRequests}/${limits.hour.maxRequests}`)
}

// Check if we're approaching limits
if (limits.concurrent.currentRequests > limits.concurrent.maxRequests * 0.8) {
  console.warn('Approaching concurrent request limit')
}
```

## Environment Variables

```bash
# Required - Your Subscribe.dev project API key
SUBSCRIBE_DEV_API_KEY=pub_your_api_key_here

# Required - User token for user-specific features
SUBSCRIBE_DEV_USER_KEY=your_user_token_here

```

## TypeScript Support

The client is written in TypeScript and provides full type definitions:

```typescript
import type { 
  SubscribeDevClientConfig,
  Prediction,
  BalanceInfo,
  TransactionHistory,
  UserStorage,
  SubscriptionStatus
} from '@subscribe.dev/client'
```

## Migration from Other Platforms

The Subscribe.dev client offers seamless migration:

```typescript
// Before (Other platforms)
import OtherClient from 'other-ai-platform'
const client = new OtherClient({ auth: 'your-token' })

// After (Subscribe.dev - More models, better features)
import { SubscribeDevClient } from '@subscribe.dev/client'
const client = new SubscribeDevClient({ apiKey: 'pub_your-token' })

// Same API
const result = await client.run('model-name', { input: {} })
```

### Key Advantages

1. **Unified Access**: Single SDK for 100+ curated models across multiple AI providers
2. **Built-in Management**: Native billing, analytics, and user management for production applications
3. **Optimized Requests**: Intelligent routing with automatic retries and completion handling
4. **Extended Features**: User storage, subscription management, and detailed analytics
5. **Transparent Pricing**: Clear cost tracking with automatic optimization
6. **Reliable Operation**: Comprehensive error handling and monitoring capabilities

## Browser Usage

The client works in browser environments with CORS support:

```html
<script type="module">
import { SubscribeDevClient } from 'https://unpkg.com/@subscribe.dev/client@latest/dist/index.js'

const client = new SubscribeDevClient({
  apiKey: 'pub_your_public_api_key', // Safe to embed in frontend
  userKey: localStorage.getItem('user_token')! // User context
})

// Use normally
const result = await client.run('model', { input: {} })
</script>
```

## Support

- 📖 **Documentation**: [docs.subscribe.dev](https://docs.subscribe.dev)
- 📧 **Email**: [hello@subscribe.dev](mailto:hello@subscribe.dev)

## License

MIT License - see [LICENSE](../../LICENSE) for details.