
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@subscribe.dev/client
Advanced tools
JavaScript/TypeScript client for SubscribeDev API - A drop-in for AI generation across 100+ models with built-in billing and rate limiting
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.
pub_
) from the project overviewnpm install @subscribe.dev/client
# or
yarn add @subscribe.dev/client
# or
bun add @subscribe.dev/client
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)
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
}
run(model, options)
The main method for running predictions. Returns completed results.
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).
const prediction = await client.createPrediction('model-name', {
input: { prompt: 'test' }
})
getBalance()
Get current project and user credit balances.
const balance = await client.getBalance()
console.log('Project credits:', balance.project.remainingCredits)
console.log('User credits:', balance.user?.remainingCredits)
Returns: Promise<BalanceInfo>
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.
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>
getRateLimits()
Get current rate limit status.
const limits = await client.getRateLimits()
console.log('Concurrent requests:', limits.concurrent.currentRequests)
console.log('Hourly limit reached:', !limits.hour?.allowed)
getStorage(options?)
Retrieve user session data.
const storage = await client.getStorage({ appVersion: 'v1.0' })
console.log('Session data:', storage.sessionData)
setStorage(sessionData, options?)
Update user session data.
await client.setStorage(
{ preferences: { theme: 'dark' }, gameState: { level: 5 } },
{ appVersion: 'v1.0' }
)
deleteStorage(options?)
Clear user session data.
await client.deleteStorage({ appVersion: 'v1.0' })
persistSessionData(options?)
Sync session data to localStorage (browser only).
// Automatically saves to localStorage and server
const storage = await client.persistSessionData()
getSessionData(options?)
Get session data with localStorage caching.
// Always fetches from server, updates localStorage cache
const sessionData = await client.getSessionData()
getSubscriptionStatus()
Get user subscription information (requires userKey).
// 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)
}
Subscribe.dev uses a dual authentication system:
pub_[base64_jwt_token]
const client = new SubscribeDevClient({
apiKey: 'pub_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})
const client = new SubscribeDevClient({
apiKey: 'pub_your_project_key',
userKey: 'user_specific_token'
})
The client provides specific error types for different scenarios:
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)
}
}
SubscribeDevError
- Base error classInsufficientBalanceError
- 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)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
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)
}
}
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()
}
// 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)
// 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')
}
# 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
The client is written in TypeScript and provides full type definitions:
import type {
SubscribeDevClientConfig,
Prediction,
BalanceInfo,
TransactionHistory,
UserStorage,
SubscriptionStatus
} from '@subscribe.dev/client'
The Subscribe.dev client offers seamless migration:
// 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: {} })
The client works in browser environments with CORS support:
<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>
MIT License - see LICENSE for details.
FAQs
JavaScript/TypeScript client for SubscribeDev API - A drop-in for AI generation across 100+ models with built-in billing and rate limiting
The npm package @subscribe.dev/client receives a total of 12,339 weekly downloads. As such, @subscribe.dev/client popularity was classified as popular.
We found that @subscribe.dev/client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.