@subscribe.dev/client
Version:
JavaScript/TypeScript client for SubscribeDev API - A drop-in for AI generation across 100+ models with built-in billing and rate limiting
533 lines (408 loc) • 14.4 kB
Markdown
# @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' })
```
### 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>
```
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Submit a pull request
## Support
- 📖 **Documentation**: [docs.subscribe.dev](https://docs.subscribe.dev)
- 🐛 **Issues**: [GitHub Issues](https://github.com/subscribe-dev/subscribe-dev/issues)
- 💬 **Discord**: [Join our community](https://discord.gg/subscribe-dev)
- 📧 **Email**: [support@subscribe.dev](mailto:support@subscribe.dev)
## License
MIT License - see [LICENSE](../../LICENSE) for details.