TypeScript Support Guide
@meeting-baas/sdk - Client API & Bridge / typescript-support
TypeScript Support Guide
The Meeting BaaS SDK is built with TypeScript and provides comprehensive type definitions for all APIs.
Overview
The SDK offers:
- Full type safety: All methods and parameters are fully typed
- Type inference: Automatic type inference based on API version
- Discriminated unions: Type-safe error handling
- Generated types: Types generated from OpenAPI specification
- Version-specific types: Different types for v1 and v2 APIs
Basic Type Safety
Importing Types
// Import the client factory
import { createBaasClient } from "@meeting-baas/sdk";
// Import common types
import type {
JoinRequest,
JoinResponse,
CreateCalendarParams
} from "@meeting-baas/sdk";
// Import v2-specific types
import type { V2 } from "@meeting-baas/sdk";Client Type Inference
TypeScript automatically infers the correct client type:
// v1 client type is inferred
const v1Client = createBaasClient({
api_key: "key",
api_version: "v1"
});
// TypeScript knows these methods are available:
v1Client.joinMeeting; // ✅
v1Client.leaveMeeting; // ✅
v1Client.getMeetingData; // ✅
v1Client.createBot; // ❌ Type error
// v2 client type is inferred
const v2Client = createBaasClient({
api_key: "key",
api_version: "v2"
});
// TypeScript knows these methods are available:
v2Client.createBot; // ✅
v2Client.stopBot; // ✅
v2Client.getBot; // ✅
v2Client.joinMeeting; // ❌ Type errorRequest Types
v1 Request Types
import type {
JoinRequest,
LeaveRequest,
GetMeetingDataParams,
DeleteBotDataParams
} from "@meeting-baas/sdk";
const joinParams: JoinRequest = {
meeting_url: "https://meet.google.com/abc-def-ghi",
bot_name: "My Bot",
reserved: true,
// Optional parameters
bot_image: "https://example.com/bot.jpg",
recording_mode: "speaker_view",
speech_to_text: {
provider: "Gladia"
}
};
const result = await client.joinMeeting(joinParams);v2 Request Types
import type { V2 } from "@meeting-baas/sdk";
const createBotParams: V2.CreateBotRequest = {
meeting_url: "https://meet.google.com/abc-def-ghi",
bot_name: "My Bot",
// Optional parameters
bot_image: "https://example.com/bot.jpg",
webhook_url: "https://example.com/webhook"
};
const result = await client.createBot(createBotParams);Response Types
Discriminated Unions
The SDK uses discriminated unions for type-safe error handling:
// v1 response
const result = await v1Client.joinMeeting({ ... });
if (result.success) {
// TypeScript knows result.data exists
const botId: string = result.data.bot_id;
// result.error is never
} else {
// TypeScript knows result.error exists
const error: ZodError | Error = result.error;
// result.data is never
}// v2 response
const result = await v2Client.createBot({ ... });
if (result.success) {
// TypeScript knows result.data exists
const botId: string = result.data.bot_id;
} else {
// TypeScript knows error fields exist
const errorMessage: string = result.error;
const errorCode: string = result.code;
const statusCode: number = result.statusCode;
}Response Type Definitions
// v1 response types
type ApiResponse\<T\> =
| { success: true; data: T; error?: never }
| { success: false; error: ZodError | Error; data?: never };
// v2 response types
type ApiResponseV2\<T\> =
| { success: true; data: T; error?: never }
| {
success: false;
error: string;
code: string;
statusCode: number;
details: unknown | null;
data?: never;
};Type Narrowing
Using Type Guards
import { ZodError } from "zod";
function isZodError(error: unknown): error is ZodError {
return error instanceof ZodError;
}
const result = await v1Client.joinMeeting({ ... });
if (!result.success) {
if (isZodError(result.error)) {
// TypeScript knows this is a ZodError
result.error.errors.forEach(err => {
console.log(err.path, err.message);
});
} else {
// TypeScript knows this is a regular Error
console.log(result.error.message);
}
}Custom Type Guards
import type { V2 } from "@meeting-baas/sdk";
function isBotCompleted(
bot: V2.GetBotResponse
): bot is V2.GetBotResponse & { status: "completed" } {
return bot.status === "completed";
}
const result = await v2Client.getBot({ bot_id: "123" });
if (result.success && isBotCompleted(result.data)) {
// TypeScript knows status is "completed"
console.log("Bot completed:", result.data.bot_id);
}Webhook Types
v2 Webhook Types
All webhook types are available in the V2 namespace:
import type { V2 } from "@meeting-baas/sdk";
// Bot webhooks
type BotCompleted = V2.BotWebhookCompleted;
type BotFailed = V2.BotWebhookFailed;
type BotStatusChange = V2.BotWebhookStatusChange;
// Calendar webhooks
type ConnectionCreated = V2.CalendarWebhookConnectionCreated;
type EventCreated = V2.CalendarWebhookEventCreated;
// Callback types
type CallbackCompleted = V2.CallbackCompleted;
type CallbackFailed = V2.CallbackFailed;Type-Safe Webhook Handler
import type { V2 } from "@meeting-baas/sdk";
type WebhookPayload =
| V2.BotWebhookCompleted
| V2.BotWebhookFailed
| V2.BotWebhookStatusChange
| V2.CalendarWebhookConnectionCreated
| V2.CalendarWebhookEventCreated;
function handleWebhook(payload: WebhookPayload) {
switch (payload.event) {
case "bot.completed":
// TypeScript infers the correct payload type
console.log("Bot completed:", payload.data.bot_id);
console.log("Recording:", payload.data.mp4_url);
break;
case "bot.failed":
// TypeScript knows the payload structure
console.error("Bot failed:", payload.data.error_message);
break;
case "bot.status_change":
console.log("Status changed:", payload.data.status);
break;
case "calendar.connection.created":
console.log("Calendar connected:", payload.data.calendar_id);
break;
case "calendar.event.created":
console.log("Event created:", payload.data.event_id);
break;
default:
// Exhaustive check
const _exhaustive: never = payload;
console.warn("Unknown event type");
}
}Generic Types
Working with Generic Response Types
async function fetchData\<T\>(
operation: () => Promise<{ success: boolean; data?: T; error?: any }>
): Promise\<T\> {
const result = await operation();
if (result.success) {
return result.data!;
}
throw new Error(result.error);
}
// Usage with type inference
const botId = await fetchData(() =>
v2Client.createBot({
meeting_url: "https://meet.google.com/abc",
bot_name: "Bot"
})
).then(data => data.bot_id);Utility Types
Extract Type from Response
import type { V2 } from "@meeting-baas/sdk";
// Extract the data type from a response
type CreateBotData = Extract<
Awaited<ReturnType<typeof v2Client.createBot>>,
{ success: true }
>["data"];
// Use the extracted type
const botData: CreateBotData = {
bot_id: "123",
status: "joining",
meeting_url: "https://meet.google.com/abc",
created_at: new Date().toISOString()
};Conditional Types
type UnwrapResponse\<T\> = T extends { success: true; data: infer U }
? U
: never;
// Extract data type from any response
type BotData = UnwrapResponse<
Awaited<ReturnType<typeof v2Client.createBot>>
>;Enum Types
Recording Modes
type RecordingMode =
| "speaker_view"
| "gallery_view"
| "audio_only";
const mode: RecordingMode = "speaker_view";
await v1Client.joinMeeting({
meeting_url: "...",
bot_name: "Bot",
reserved: true,
recording_mode: mode
});Calendar Platforms
type CalendarPlatform = "Google" | "Microsoft";
const platform: CalendarPlatform = "Google";
await client.createCalendar({
oauth_client_id: "...",
oauth_client_secret: "...",
oauth_refresh_token: "...",
platform: platform
});Advanced Patterns
Builder Pattern with Types
import type { V2 } from "@meeting-baas/sdk";
class BotBuilder {
private params: Partial<V2.CreateBotRequest> = {};
meetingUrl(url: string) {
this.params.meeting_url = url;
return this;
}
name(name: string) {
this.params.bot_name = name;
return this;
}
image(url: string) {
this.params.bot_image = url;
return this;
}
webhook(url: string) {
this.params.webhook_url = url;
return this;
}
async create() {
if (!this.params.meeting_url || !this.params.bot_name) {
throw new Error("meeting_url and bot_name are required");
}
return await v2Client.createBot(
this.params as V2.CreateBotRequest
);
}
}
// Usage
const result = await new BotBuilder()
.meetingUrl("https://meet.google.com/abc")
.name("My Bot")
.image("https://example.com/bot.jpg")
.webhook("https://example.com/webhook")
.create();Type-Safe Service Layer
import type { V2 } from "@meeting-baas/sdk";
interface BotService {
createBot(params: V2.CreateBotRequest): Promise<V2.CreateBotResponse>;
getBot(botId: string): Promise<V2.GetBotResponse>;
stopBot(botId: string): Promise<void>;
}
class MeetingBaasBotService implements BotService {
constructor(
private client: ReturnType<typeof createBaasClient<"v2">>
) {}
async createBot(params: V2.CreateBotRequest) {
const result = await this.client.createBot(params);
if (!result.success) {
throw new Error(result.error);
}
return result.data;
}
async getBot(botId: string) {
const result = await this.client.getBot({ bot_id: botId });
if (!result.success) {
throw new Error(result.error);
}
return result.data;
}
async stopBot(botId: string) {
const result = await this.client.stopBot({ bot_id: botId });
if (!result.success) {
throw new Error(result.error);
}
}
}Type Assertions
Safe Type Assertions
import type { V2 } from "@meeting-baas/sdk";
function isValidBot(data: unknown): data is V2.GetBotResponse {
return (
typeof data === "object" &&
data !== null &&
"bot_id" in data &&
"status" in data
);
}
// Usage
const data: unknown = await fetchBotData();
if (isValidBot(data)) {
console.log("Bot ID:", data.bot_id);
console.log("Status:", data.status);
}Best Practices
-
Use type inference: Let TypeScript infer types when possible
-
Import types separately: Use
import typefor type-only imports -
Leverage discriminated unions: Use the
successfield for type narrowing -
Create type guards: Build reusable type guard functions
-
Use const assertions: For literal type inference
const config = {
api_key: "key",
api_version: "v2" as const // Literal type instead of string
};-
Avoid
any: Useunknownand type guards instead -
Use strict mode: Enable
strict: truein tsconfig.json
Complete Example
import { createBaasClient } from "@meeting-baas/sdk";
import type { V2 } from "@meeting-baas/sdk";
// Type-safe configuration
interface BotConfig {
meetingUrl: string;
botName: string;
webhookUrl?: string;
}
// Type-safe service
class BotService {
private client: ReturnType<typeof createBaasClient<"v2">>;
constructor(apiKey: string) {
this.client = createBaasClient({
api_key: apiKey,
api_version: "v2"
});
}
async createBot(config: BotConfig): Promise<string> {
const params: V2.CreateBotRequest = {
meeting_url: config.meetingUrl,
bot_name: config.botName,
webhook_url: config.webhookUrl
};
const result = await this.client.createBot(params);
if (!result.success) {
throw new Error(`Failed to create bot: ${result.error}`);
}
return result.data.bot_id;
}
async waitForCompletion(botId: string): Promise<V2.GetBotResponse> {
while (true) {
const result = await this.client.getBot({ bot_id: botId });
if (!result.success) {
throw new Error(`Failed to get bot: ${result.error}`);
}
if (result.data.status === "completed" ||
result.data.status === "failed") {
return result.data;
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
}
// Usage with full type safety
const service = new BotService(process.env.API_KEY!);
const botId = await service.createBot({
meetingUrl: "https://meet.google.com/abc",
botName: "Meeting Recorder"
});
const bot = await service.waitForCompletion(botId);
console.log("Bot completed:", bot.bot_id);