npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@baxcloud/baxcloud-server-sdk

v1.0.3

Published

BaxCloud Server SDK for Node.js — webhooks, rooms, streaming, ingress, and PK Battle

Readme

@baxcloud/baxcloud-server-sdk

Official BaxCloud Server SDK for Node.js — webhook verification and API client for rooms, streaming, ingress, and PK Battle.

Product-specific SDKs:

Features

  • 🔐 Webhook Signature Verification - Secure HMAC-SHA256 signature verification with constant-time comparison
  • 🚀 Express/Connect Middleware - Drop-in middleware for webhook handling
  • 🛠️ API Client - Full-featured client for room and participant management
  • 📘 TypeScript Support - Complete type definitions included
  • Zero Dependencies - Uses only Node.js built-in modules

Installation

npm install @baxcloud/baxcloud-server-sdk

Quick Start

Webhook Verification

Basic Usage

import { verifyWebhookSignature } from '@baxcloud/baxcloud-server-sdk';

const isValid = verifyWebhookSignature({
  secret: process.env.BAXCLOUD_WEBHOOK_SECRET,
  payload: req.rawBody, // Raw request body as string
  signature: req.headers['x-baxcloud-signature']
});

if (!isValid) {
  return res.status(401).json({ error: 'Invalid signature' });
}

Using Express Middleware

import express from 'express';
import { webhookMiddleware } from '@baxcloud/baxcloud-server-sdk';

const app = express();

app.post('/webhooks/baxcloud',
  // IMPORTANT: Capture raw body for signature verification
  express.json({
    verify: (req, res, buf) => {
      req.rawBody = buf.toString('utf8');
    }
  }),
  // Verify signature and parse event
  webhookMiddleware(process.env.BAXCLOUD_WEBHOOK_SECRET),
  (req, res) => {
    // Event is automatically verified and parsed
    const event = req.baxcloudEvent;
    
    console.log('Event type:', event.event);
    console.log('Project ID:', event.projectId);
    console.log('Room name:', event.room?.name);
    console.log('Participant:', event.participant?.identity);
    
    // Handle the event
    switch (event.event) {
      case 'room.created':
        console.log('Room created:', event.room.name);
        break;
      case 'participant.joined':
        console.log('Participant joined:', event.participant.identity);
        break;
      case 'participant.left':
        console.log('Participant left:', event.participant.identity);
        break;
      // ... handle other events
    }
    
    res.json({ received: true });
  }
);

app.listen(3000);

Manual Parsing with Verification

import { parseWebhook } from '@baxcloud/baxcloud-server-sdk';

app.post('/webhooks/baxcloud',
  express.json({
    verify: (req, res, buf) => {
      req.rawBody = buf.toString('utf8');
    }
  }),
  async (req, res) => {
    try {
      const event = parseWebhook({
        secret: process.env.BAXCLOUD_WEBHOOK_SECRET,
        payload: req.rawBody,
        signature: req.headers['x-baxcloud-signature']
      });
      
      // Event is verified and parsed
      console.log('Received event:', event.event);
      
      res.json({ received: true });
    } catch (error) {
      console.error('Webhook error:', error.message);
      return res.status(401).json({ error: error.message });
    }
  }
);

API Client

Initialize Client

import { BaxCloudServerClient } from '@baxcloud/baxcloud-server-sdk';

const client = new BaxCloudServerClient({
  apiKey: process.env.BAXCLOUD_API_KEY,
  projectId: process.env.BAXCLOUD_PROJECT_ID!,
  // Optional: request timeout in ms (default: 30000)
  timeout: 30000
});

Create a Room

const room = await client.createRoom({
  name: 'my-meeting-room',
  maxParticipants: 50,
  enableRecording: true,
  emptyTimeout: 300, // Close room after 5 minutes when empty
  metadata: JSON.stringify({ type: 'meeting', host: 'user-123' })
});

console.log('Room created:', room);

Generate Access Token

const token = await client.generateToken({
  roomName: 'my-meeting-room',
  participantIdentity: 'user-123',
  participantName: 'John Doe',
  participantMetadata: JSON.stringify({ role: 'host' }),
  ttl: 3600, // 1 hour
  grants: {
    canPublish: true,
    canSubscribe: true,
    canPublishData: true,
    canUpdateOwnMetadata: true
  }
});

// Send token to client
res.json({ token });

Room Management

// Get room details
const room = await client.getRoom('my-meeting-room');

// List all rooms
const rooms = await client.listRooms();

// Update room metadata
await client.updateRoomMetadata('my-meeting-room', 
  JSON.stringify({ status: 'in-progress' })
);

// Delete room
await client.deleteRoom('my-meeting-room');

Participant Management

// List participants in a room
const participants = await client.listParticipants('my-meeting-room');

// Update participant metadata
await client.updateParticipantMetadata(
  'my-meeting-room',
  'user-123',
  JSON.stringify({ role: 'presenter' })
);

// Remove participant from room
await client.removeParticipant('my-meeting-room', 'user-123');

BaxStream — use @baxcloud/baxstream

Video conversion (HLS), AI categorization, and content moderation live in the dedicated BaxStream SDK. Install it alongside this package when you need those APIs:

npm install @baxcloud/baxstream
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: ['360p', '720p'],
  s3Config: { bucket: '...', accessKey: '...', secretKey: '...' },
});

BaxStream webhooks (video.conversion.*, categorization.*, moderation.*) are verified with this server SDK — see the BaxStream Webhook Events section below.

Complete Example: Express Server

import express from 'express';
import { BaxCloudServerClient, webhookMiddleware } from '@baxcloud/baxcloud-server-sdk';

const app = express();
const client = new BaxCloudServerClient({
  apiKey: process.env.BAXCLOUD_API_KEY
});

// Endpoint to create room and generate token
app.post('/api/join-room', express.json(), async (req, res) => {
  try {
    const { roomName, userId, userName } = req.body;
    
    // Create room if it doesn't exist
    try {
      await client.createRoom({
        name: roomName,
        maxParticipants: 10
      });
    } catch (error) {
      // Room might already exist, that's okay
    }
    
    // Generate access token
    const token = await client.generateToken({
      roomName,
      participantIdentity: userId,
      participantName: userName,
      ttl: 3600,
      grants: {
        canPublish: true,
        canSubscribe: true,
        canPublishData: true
      }
    });
    
    res.json({ token });
  } catch (error) {
    console.error('Error:', error);
    res.status(500).json({ error: error.message });
  }
});

// Webhook endpoint
app.post('/webhooks/baxcloud',
  express.json({
    verify: (req, res, buf) => {
      req.rawBody = buf.toString('utf8');
    }
  }),
  webhookMiddleware(process.env.BAXCLOUD_WEBHOOK_SECRET),
  async (req, res) => {
    const event = req.baxcloudEvent;
    
    console.log(`[Webhook] ${event.event}`, {
      projectId: event.projectId,
      room: event.room?.name,
      participant: event.participant?.identity
    });
    
    // Handle events
    switch (event.event) {
      case 'room.created':
        // Log room creation
        console.log('Room created:', event.room.name);
        break;
        
      case 'participant.joined':
        // Track participant join
        console.log(`${event.participant.identity} joined ${event.room.name}`);
        break;
        
      case 'participant.left':
        // Track participant leave
        console.log(`${event.participant.identity} left ${event.room.name}`);
        break;
        
      case 'room.ended':
        // Clean up after room ends
        console.log('Room ended:', event.room?.name);
        break;
    }
    
    res.json({ received: true });
  }
);

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Webhook Events

Import event name constants for type-safe switch handling:

import { BAXCLOUD_WEBHOOK_EVENTS, type BaxCloudWebhookEventType } from '@baxcloud/baxcloud-server-sdk';

switch (event.event) {
  case BAXCLOUD_WEBHOOK_EVENTS.ROOM_CREATED:
    break;
  case BAXCLOUD_WEBHOOK_EVENTS.VIDEO_CONVERSION_COMPLETED:
    break;
  case BAXCLOUD_WEBHOOK_EVENTS.BAXMAIL_DELIVERED:
    break;
}

BAXCLOUD_WEBHOOK_EVENT_NAMES lists every supported event. WEBHOOK_EVENT_CATEGORIES groups them for UI or docs.

Realtime (rooms, media, egress, ingress, PK)

| Event | Description | |-------|-------------| | room.created | Room created and active | | room.ended | Room session ended | | participant.joined | Participant joined | | participant.left | Participant left | | track.published | Audio/video track published | | track.unpublished | Track unpublished | | recording.started | Recording started | | recording.updated | Recording status updated | | recording.completed | Recording finished; file ready | | recording.failed | Recording failed | | stream.started | RTMP stream out started | | stream.updated | Stream out status updated | | stream.completed | Stream out completed | | stream.failed | Stream out failed | | live.started | Ingress (OBS/FFmpeg) started | | live.updated | Ingress status updated | | live.ended | Ingress ended | | live.failed | Ingress failed | | pk.started | PK battle started | | pk.score_update | PK score updated | | pk.ended | PK battle ended | | pk.cancelled | PK battle cancelled |

BaxVerify

| Event | Description | |-------|-------------| | baxauth.otp.sent | SMS OTP sent | | baxauth.otp.verified | SMS OTP verified | | baxauth.otp.failed | SMS OTP failed |

BaxMail

| Event | Description | |-------|-------------| | baxmail.sent | Email accepted by provider | | baxmail.delivered | Email delivered | | baxmail.failed | Email send/delivery failed | | baxmail.bounced | Email bounced or marked spam | | baxmail.deferred | Delivery temporarily deferred |

BaxLinks

| Event | Description | |-------|-------------| | link.click | Short link clicked | | link.install.attributed | Install attributed to a link | | link.event.install | SDK install event | | link.event.open | SDK app open event | | link.event.reinstall | SDK reinstall event | | link.event.signup | SDK signup event | | link.event.purchase | SDK purchase event | | link.event.custom | SDK custom event |

BaxStream

| Event | Description | |-------|-------------| | video.conversion.started | HLS conversion started | | video.conversion.completed | HLS conversion completed | | video.conversion.failed | HLS conversion failed | | categorization.started | Standalone AI categorization job began | | categorization.completed | AI categorization completed | | categorization.failed | AI categorization failed | | moderation.started | Standalone AI moderation job began | | moderation.completed | AI moderation completed | | moderation.failed | AI moderation failed |

BaxStream Webhook Envelope

Every BaxStream webhook delivery uses the following envelope. The user metadata you attached to the originating job is hoisted to the top level for fast routing, and also preserved inside data. eventId is a unique id you can use to dedupe at-least- once deliveries.

{
  "event":     "video.conversion.completed",
  "eventId":   "cm9a8w1xyz...",
  "timestamp": "2026-04-17T10:00:00.000Z",
  "projectId": "cl_proj_abc123",
  "metadata":  { "userId": "u_42", "uploadId": "u_42_v17" },
  "data": {
    "jobId": "cm_job_xyz789",
    "projectId": "cl_proj_abc123",
    "status": "COMPLETED",
    "inputUrl": "https://source.example.com/video.mp4",
    "outputUrl": "https://cdn.example.com/videos/master.m3u8",
    "thumbnailUrl": "https://cdn.example.com/videos/thumbnail.jpg",
    "outputFormats": ["360p", "480p", "720p"],
    "renditionUrls": {
      "360p": "https://cdn.example.com/videos/360p/playlist.m3u8",
      "480p": "https://cdn.example.com/videos/480p/playlist.m3u8",
      "720p": "https://cdn.example.com/videos/720p/playlist.m3u8"
    },
    "durationSec": 125,
    "costCents": 13,
    "metadata": { "userId": "u_42", "uploadId": "u_42_v17" },
    "createdAt":   "2026-04-17T09:58:12.000Z",
    "completedAt": "2026-04-17T10:00:00.000Z",

    // Present when categorize=true was passed on the job
    "categorization": {
      "primaryCategory": "Sports",
      "confidence": 0.4523,
      "categories": [
        { "name": "Sports",        "confidence": 0.4523, "primary": true  },
        { "name": "Entertainment", "confidence": 0.0812, "primary": false }
      ],
      "tags": ["football", "stadium"],
      "scores": { "Sports": 0.4523, "Entertainment": 0.0812 /* ... */ }
    },

    // Present when moderate=true was passed on the job
    "moderation": {
      "safe": false,
      "violations": [
        { "category": "nudity_explicit",    "confidence": 0.5210, "severity": "critical" },
        { "category": "suggestive_nudity",  "confidence": 0.3104, "severity": "high" },
        { "category": "lingerie_underwear", "confidence": 0.2850, "severity": "medium" }
      ],
      "scores": { /* full 13-category probability map */ },
      "flaggedFrames": [
        { "frameIndex": 2, "violations": [ /* ... */ ] }
      ]
    }
  }
}

Request headers delivered with every webhook:

| Header | Value | |--------|-------| | Content-Type | application/json | | User-Agent | BaxCloud-VideoConverter/1.0 | | X-BaxCloud-Event | The event type, e.g. video.conversion.completed | | X-BaxCloud-Signature | sha256=<hex> — HMAC-SHA256 of the raw body with your webhook secret |

Delivery semantics:

  • At-least-once delivery — dedupe on eventId.
  • 10 second timeout on every request. Respond with any 2xx to ack; push heavy work to a queue.
  • Failures (non-2xx, timeouts, network errors) are logged in Dashboard → Webhooks → Deliveries.

Receiving BaxStream Webhooks

import express from 'express';
import { webhookMiddleware } from '@baxcloud/baxcloud-server-sdk';

const app = express();

app.post(
  '/webhooks/baxstream',
  // Important: raw body is required for signature verification
  express.raw({ type: 'application/json' }),
  webhookMiddleware(process.env.BAXCLOUD_WEBHOOK_SECRET!),
  async (req, res) => {
    const ev = req.baxcloudEvent; // verified + parsed

    if (await alreadyProcessed(ev.eventId)) return res.status(200).end();

    switch (ev.event) {
      case 'video.conversion.completed':
        await onVideoReady({
          jobId:          ev.data.jobId,
          outputUrl:      ev.data.outputUrl,
          userId:         ev.metadata?.userId,
          categorization: ev.data.categorization,
          moderation:     ev.data.moderation,
        });
        break;

      case 'moderation.completed':
        if (!ev.data.safe) await flagForReview(ev.data);
        break;

      case 'video.conversion.failed':
        await onVideoFailed(ev.data.jobId, ev.data.errorMessage);
        break;
    }

    res.status(200).json({ ok: true });
  },
);

app.listen(3000);

Event Structure

interface BaxCloudWebhookEvent {
  event: string;           // Event type
  projectId: string;       // Your project ID
  timestamp: string;       // ISO 8601 timestamp
  
  room?: {
    name: string;
    sid?: string;
    createdAt?: string;
    metadata?: string;
  };
  
  participant?: {
    identity: string;
    sid?: string;
    name?: string;
    metadata?: string;
  };
  
  track?: {
    sid?: string;
    type?: string;
    source?: string;
  };
}

Security Best Practices

  1. Always verify webhook signatures - Never process webhooks without verification
  2. Use HTTPS - Ensure your webhook endpoint uses HTTPS in production
  3. Keep secrets secure - Store webhook secrets in environment variables
  4. Validate event data - Always validate event data before processing
  5. Return 200 quickly - Acknowledge webhooks quickly, process async if needed

TypeScript Support

This SDK is written in TypeScript and includes complete type definitions:

import type {
  BaxCloudServerClient,
  BaxCloudWebhookEvent,
  BaxCloudWebhookEventType,
  CreateRoomOptions,
  GenerateTokenOptions,
  WebhookVerificationOptions,
} from '@baxcloud/baxcloud-server-sdk';

Error Handling

try {
  const room = await client.createRoom({ name: 'my-room' });
} catch (error) {
  if (error.message.includes('timeout')) {
    console.error('Request timed out');
  } else if (error.message.includes('API error')) {
    console.error('API returned an error:', error.message);
  } else {
    console.error('Unexpected error:', error);
  }
}

Environment Variables

# Required for API client
BAXCLOUD_API_KEY=your_api_key_here

# Required for webhook verification
BAXCLOUD_WEBHOOK_SECRET=your_webhook_secret_here

Related SDKs

License

MIT

Support

  • Help: https://baxcloud.tech/dashboard/help
  • Contact: https://baxcloud.tech/contact
  • Documentation: https://baxcloud.tech/docs/sdk/server
  • Email: [email protected]