@stephen_turtles/bluma-sdk
v1.2.0
Published
Official TypeScript/Node.js SDK for the Bluma API
Readme
@stephen_turtles/bluma-sdk
Official TypeScript/Node.js SDK for the Bluma API
Installation
npm install @stephen_turtles/bluma-sdk
# or
yarn add @stephen_turtles/bluma-sdk
# or
pnpm add @stephen_turtles/bluma-sdkQuick Start
import { Bluma } from '@stephen_turtles/bluma-sdk';
const bluma = new Bluma({
apiKey: process.env.BLUMA_API_KEY
});
// Generate a video
const video = await bluma.videos.create({
templateId: 'meme-dialogue',
context: {
prompt: 'Create a funny dialogue between a programmer and their computer'
}
});
console.log('Video ID:', video.id);
// Wait for completion
const completed = await bluma.videos.waitFor(video.id);
console.log('Video ready:', completed.url);Features
- ✅ Full TypeScript support with exported types
- ✅ Automatic retries with exponential backoff
- ✅ Webhook verification utilities
- ✅ Polling helpers for video completion
- ✅ Custom error classes for each status code
- ✅ ESM and CommonJS support
Configuration
const bluma = new Bluma({
apiKey: process.env.BLUMA_API_KEY,
baseUrl: 'https://api.bluma.app/api/v1', // optional
timeout: 30000, // 30 seconds
maxRetries: 3,
retryDelay: 1000, // 1 second
retryMultiplier: 2 // exponential backoff
});API Reference
Videos
// Create video
const video = await bluma.videos.create({
templateId: 'meme-dialogue',
context: { prompt: 'Create a funny video' },
webhookUrl: 'https://myapp.com/webhook', // optional
metadata: { userId: 'user_123' } // optional
});
// Get video status
const video = await bluma.videos.get('batch_abc123');
// Wait for completion with progress
const completed = await bluma.videos.waitFor('batch_abc123', {
pollInterval: 5000,
timeout: 600000,
onProgress: (progress) => console.log(`Progress: ${progress}%`)
});
// Download video
const download = await bluma.videos.download('batch_abc123');Templates
// List all templates
const templates = await bluma.templates.list();
// Get template details
const template = await bluma.templates.get('meme-dialogue');Credits
// Get balance
const balance = await bluma.credits.getBalance();
console.log(`${balance.credits} credits remaining`);
// Get history
const history = await bluma.credits.getHistory({ limit: 50 });Webhooks
// Create webhook
const webhook = await bluma.webhooks.create({
url: 'https://myapp.com/webhooks/bluma',
events: ['video.completed', 'video.failed']
});
console.log('Secret:', webhook.secret); // Save this!
// List webhooks
const webhooks = await bluma.webhooks.list();
// Delete webhook
await bluma.webhooks.delete('webhook_abc123');
// Get deliveries
const deliveries = await bluma.webhooks.getDeliveries('webhook_abc123');Webhook Verification
import { Bluma } from '@stephen_turtles/bluma-sdk';
import express from 'express';
const app = express();
app.post('/webhooks/bluma',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-bluma-signature'];
const payload = req.body.toString();
try {
const event = Bluma.webhooks.verify(
payload,
signature,
process.env.BLUMA_WEBHOOK_SECRET
);
console.log('Event:', event.type);
res.sendStatus(200);
} catch (error) {
console.error('Invalid signature');
res.status(401).send('Unauthorized');
}
}
);Error Handling
import {
ValidationError,
AuthenticationError,
InsufficientCreditsError,
RateLimitError,
NotFoundError,
APIError
} from '@stephen_turtles/bluma-sdk';
try {
const video = await bluma.videos.create({...});
} catch (error) {
if (error instanceof ValidationError) {
console.error('Invalid input:', error.message);
} else if (error instanceof InsufficientCreditsError) {
console.error('Out of credits!');
} else if (error instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${error.retryAfter}s`);
} else if (error instanceof APIError) {
console.error(`API error: ${error.status} - ${error.message}`);
}
}Type Guards
import { isVideoCompleted, isVideoFailed } from '@stephen_turtles/bluma-sdk';
const video = await bluma.videos.get('batch_abc123');
if (isVideoCompleted(video)) {
// TypeScript knows video.url is defined
console.log(video.url);
} else if (isVideoFailed(video)) {
// TypeScript knows video.error is defined
console.error(video.error.detail);
}TypeScript
Full TypeScript support with exported types:
import type { Video, VideoStatus, Template } from '@stephen_turtles/bluma-sdk';
function processVideo(video: Video) {
if (video.status === VideoStatus.Completed) {
console.log(video.url);
}
}License
MIT
Support
- Documentation: https://docs.bluma.app
- GitHub: https://github.com/bluma/bluma-typescript
- Email: [email protected]
