@baxcloud/baxstream
v1.0.5
Published
BaxStream SDK for Node.js — video conversion, HLS output, and AI categorization/moderation
Maintainers
Readme
@baxcloud/baxstream
Official BaxStream SDK for Node.js — video conversion to adaptive HLS, AI categorization, and content moderation.
For BaxStream webhook verification (and other BaxCloud product webhooks), use @baxcloud/baxcloud-server-sdk alongside this package.
Product-specific SDKs:
- @baxcloud/baxstream — docs — video conversion + AI
- @baxcloud/baxmail — docs — transactional email
- @baxcloud/baxverify — docs — SMS OTP verification
- @baxcloud/baxlinks — docs — deep linking & attribution
Installation
npm install @baxcloud/baxstreamQuick Start
import { BaxCloudStreamClient } from '@baxcloud/baxstream';
const stream = new BaxCloudStreamClient({
projectId: process.env.BAXCLOUD_PROJECT_ID!,
apiKey: process.env.BAXCLOUD_API_KEY!,
});
const job = await stream.createVideoConversionJob({
inputUrl: 'https://example.com/video.mp4',
outputFormats: ['720p', '1080p'],
s3Config: {
bucket: 'my-bucket',
accessKey: process.env.S3_ACCESS_KEY!,
secretKey: process.env.S3_SECRET_KEY!,
cdnUrl: 'https://cdn.example.com',
},
});
const status = await stream.getVideoConversionJob(job.id);
console.log(status.status, status.outputUrl);Requires Node.js 18+. Only projectId and apiKey are required — the client connects to BaxCloud automatically.
Sync vs async (important)
BaxStream has two execution models. Do not assume everything is webhook-only.
| Flow | Endpoints / methods | How you get results |
|------|---------------------|---------------------|
| Standalone AI (sync) | createCategorizationJob, createModerationJob, uploadImageForModeration, createModerationBatchJob, uploadImagesForModeration | await the HTTP call — response has status: "COMPLETED" with full results (safe, violations, categories, batchItems, etc.). Webhooks are optional. |
| HLS conversion (async) | createVideoConversionJob, uploadVideoForConversion | Job stays PENDING / PROCESSING — poll getVideoConversionJob() or use video.conversion.* webhooks. Inline categorize / moderate results arrive on video.conversion.completed. |
Single-image moderation example — block until done, read result.safe directly:
const result = await stream.createModerationJob({
inputUrl: 'https://example.com/photo.jpg',
inputType: 'image',
threshold: 0.30,
});
if (!result.safe) {
console.log('Blocked:', result.violations);
}
// No webhook and no getModerationJob() required for standalone calls.Use getModerationJob() / listModerationJobs() only to re-fetch stored jobs later (dashboard, audits, retries).
Usage Examples
Convert a video URL to adaptive HLS
Point BaxStream at a publicly reachable MP4/MOV. Output is written to your S3 bucket as HLS segments plus a master playlist.
const job = await stream.createVideoConversionJob({
inputUrl: 'https://cdn.example.com/uploads/clip.mp4',
outputFormats: ['360p', '720p', '1080p'],
ffmpegPreset: 'fast',
hlsTime: 6,
s3Config: {
bucket: 'my-videos',
region: 'us-east-1',
prefix: 'hls/my-app/',
accessKey: process.env.S3_ACCESS_KEY!,
secretKey: process.env.S3_SECRET_KEY!,
cdnUrl: 'https://videos.example.com',
},
metadata: { userId: 'user_123', uploadId: 'up_456' },
});
console.log(job.id, job.status); // PENDINGWhen the job completes, outputUrl is the HLS master playlist URL and renditionUrls maps each resolution.
Upload a local file
Use uploadVideoForConversion when the source file is on your server (Express, NestJS, etc.) instead of a public URL.
import fs from 'node:fs';
const file = fs.createReadStream('./uploads/recording.mp4');
const job = await stream.uploadVideoForConversion(file, 'recording.mp4', {
outputFormats: ['720p', '1080p'],
s3Config: {
bucket: 'my-videos',
accessKey: process.env.S3_ACCESS_KEY!,
secretKey: process.env.S3_SECRET_KEY!,
cdnUrl: 'https://videos.example.com',
},
});Conversion + AI in one job
Run HLS conversion together with categorization and/or moderation on the same input:
const job = await stream.createVideoConversionJob({
inputUrl: 'https://example.com/feed-video.mp4',
outputFormats: ['720p'],
categorize: true,
moderate: true,
s3Config: { /* ... */ },
});
// Poll until done (or use BaxStream webhooks — see below)
let status = await stream.getVideoConversionJob(job.id);
while (status.status === 'PENDING' || status.status === 'PROCESSING') {
await new Promise((r) => setTimeout(r, 5000));
status = await stream.getVideoConversionJob(job.id);
}
if (status.status === 'COMPLETED') {
console.log('HLS:', status.outputUrl);
console.log('Thumbnail:', status.thumbnailUrl);
}Standalone AI categorization
Analyze a video or image without running a full conversion job. The call is synchronous — the returned job is already COMPLETED:
const result = await stream.createCategorizationJob({
inputUrl: 'https://example.com/thumbnail.jpg',
inputType: 'image',
topK: 5,
});
console.log(result.primaryCategory, result.categories);
// e.g. [{ category: 'sports', confidence: 0.92 }, ...]For video, omit inputType or set inputType: 'video'. Use maxFrames to cap frames analyzed on long clips.
Standalone image moderation (sync)
Moderate one image from a URL or upload. The HTTP response includes the verdict — no webhook required:
// Public URL
const result = await stream.createModerationJob({
inputUrl: 'https://example.com/photo.jpg',
inputType: 'image',
threshold: 0.30,
});
if (!result.safe) {
console.log(result.violations);
}Upload a local image
Use uploadImageForModeration when the file is on your server instead of a public URL. Also synchronous:
import fs from 'node:fs';
const result = await stream.uploadImageForModeration(
fs.createReadStream('./uploads/avatar.jpg'),
'avatar.jpg',
{ threshold: 0.30 },
);
console.log(result.safe, result.violations);Moderate multiple images (batch)
Moderate up to 20 images in one synchronous job. The HTTP response includes aggregate fields plus batchItems[] per image (webhooks also fire if configured):
const batch = await stream.createModerationBatchJob({
inputUrls: [
'https://example.com/a.jpg',
'https://example.com/b.jpg',
],
threshold: 0.30,
});
for (const item of batch.batchItems ?? []) {
console.log(item.index, item.inputUrl, item.safe, item.violations);
}
// Or upload local files:
const uploaded = await stream.uploadImagesForModeration([
{ stream: fs.createReadStream('./a.jpg'), filename: 'a.jpg' },
{ stream: fs.createReadStream('./b.jpg'), filename: 'b.jpg' },
], { threshold: 0.30 });Standalone video moderation (sync)
Same synchronous model for standalone video moderation:
const result = await stream.createModerationJob({
inputUrl: 'https://example.com/user-upload.mp4',
inputType: 'video',
threshold: 0.30,
maxFrames: 8,
});
if (!result.safe) {
console.log('Blocked:', result.violations);
// e.g. [{ category: 'violence', confidence: 0.91, severity: 'high' }]
console.log('Flagged frames:', result.flaggedFrames);
}List and cancel jobs
const { items, total } = await stream.listVideoConversionJobs({
status: 'PROCESSING',
page: 1,
pageSize: 20,
});
await stream.cancelVideoConversionJob(items[0].id);
const categorizationJobs = await stream.listCategorizationJobs({ status: 'COMPLETED' });
const moderationJobs = await stream.listModerationJobs({ pageSize: 50 });Error handling
API failures throw BaxStreamError with a stable code, HTTP statusCode, and optional details.helpUrl:
import { BaxCloudStreamClient, BaxStreamError } from '@baxcloud/baxstream';
try {
await stream.createVideoConversionJob({ inputUrl: 'https://example.com/v.mp4' });
} catch (err) {
if (err instanceof BaxStreamError) {
console.error(err.code, err.statusCode, err.message);
if (err.details?.helpUrl) console.error('Help:', err.details.helpUrl);
}
throw err;
}Webhooks
Webhooks are optional for standalone AI jobs — you already get results in the synchronous HTTP response. They are recommended for async HLS conversion and for backends that prefer event-driven architecture.
BaxStream emits lifecycle webhooks for conversion, categorization, and moderation:
| Event | When | Typical use |
|-------|------|-------------|
| video.conversion.started / completed / failed | HLS conversion pipeline (async) | Primary way to learn when HLS is ready |
| categorization.started / completed / failed | Standalone categorization (sync API also returns result) | Optional duplicate notification |
| moderation.started / completed / failed | Standalone moderation (sync API also returns result); batch jobs include items[] | Optional duplicate notification |
Verify them with the server SDK:
import express from 'express';
import { webhookMiddleware } from '@baxcloud/baxcloud-server-sdk';
const app = express();
app.post(
'/webhooks/baxcloud',
express.json({
verify: (req: any, _res, buf) => { req.rawBody = buf; },
}),
webhookMiddleware(process.env.BAXCLOUD_WEBHOOK_SECRET!),
(req: any, res) => {
const event = req.baxcloudEvent;
if (event.event === 'video.conversion.completed') {
console.log('HLS ready:', event.data?.outputUrl);
}
res.json({ received: true });
},
);See BaxStream docs for event payloads and Server SDK for the full webhook catalog.
Environment Variables
BAXCLOUD_PROJECT_ID=your_project_id
BAXCLOUD_API_KEY=your_api_key # BaxStream scope enabled
# Required when writing HLS output to your bucket
S3_ACCESS_KEY=...
S3_SECRET_KEY=...API
| Method | Description |
|--------|-------------|
| createVideoConversionJob() | Start HLS conversion (+ optional AI) |
| uploadVideoForConversion() | Multipart file upload |
| listVideoConversionJobs() | List conversion jobs |
| getVideoConversionJob() | Get job status |
| cancelVideoConversionJob() | Cancel pending job |
| createCategorizationJob() | Standalone AI categorization (sync — returns completed job) |
| listCategorizationJobs() | List categorization jobs |
| getCategorizationJob() | Re-fetch a stored categorization job |
| uploadImageForModeration() | Multipart single-image upload (sync) |
| createModerationJob() | Standalone moderation, one URL (sync) |
| createModerationBatchJob() | Standalone batch image moderation, 1–20 URLs (sync) |
| uploadImagesForModeration() | Multipart batch image upload (sync) |
| listModerationJobs() | List moderation jobs |
| getModerationJob() | Re-fetch a stored moderation job |
Related SDKs
- @baxcloud/baxcloud-server-sdk — docs — webhooks, rooms, streaming, PK Battle
- @baxcloud/baxmail — docs — transactional email
- @baxcloud/baxverify — docs — SMS OTP verification
- @baxcloud/baxlinks — docs — deep linking & attribution
License
MIT
Support
- Help: https://baxcloud.tech/dashboard/help
- Contact: https://baxcloud.tech/contact
- Documentation: https://baxcloud.tech/docs/baxstream/sdk/node
- Email: [email protected]
