mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-22 05:09:05 +00:00
feat: implement frontend video platform configuration and abstraction
- Add NEXT_PUBLIC_VIDEO_PLATFORM environment variable support - Create video platform abstraction layer with factory pattern - Implement Whereby and Jitsi platform providers - Update room meeting page to use platform-agnostic component - Add platform display in room management (cards and table views) - Support single platform per deployment configuration - Maintain backward compatibility with existing Whereby integration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,9 @@ export const $CreateRoom = {
|
||||
type: "string",
|
||||
title: "Webhook Secret",
|
||||
},
|
||||
platform: {
|
||||
$ref: "#/components/schemas/VideoPlatform",
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: [
|
||||
@@ -113,6 +116,7 @@ export const $CreateRoom = {
|
||||
"is_shared",
|
||||
"webhook_url",
|
||||
"webhook_secret",
|
||||
"platform",
|
||||
],
|
||||
title: "CreateRoom",
|
||||
} as const;
|
||||
@@ -697,6 +701,58 @@ export const $HTTPValidationError = {
|
||||
title: "HTTPValidationError",
|
||||
} as const;
|
||||
|
||||
export const $JibriRecordingEvent = {
|
||||
properties: {
|
||||
room_name: {
|
||||
type: "string",
|
||||
title: "Room Name",
|
||||
},
|
||||
recording_file: {
|
||||
type: "string",
|
||||
title: "Recording File",
|
||||
},
|
||||
recording_status: {
|
||||
type: "string",
|
||||
title: "Recording Status",
|
||||
},
|
||||
timestamp: {
|
||||
type: "string",
|
||||
format: "date-time",
|
||||
title: "Timestamp",
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: ["room_name", "recording_file", "recording_status", "timestamp"],
|
||||
title: "JibriRecordingEvent",
|
||||
} as const;
|
||||
|
||||
export const $JitsiWebhookEvent = {
|
||||
properties: {
|
||||
event: {
|
||||
type: "string",
|
||||
title: "Event",
|
||||
},
|
||||
room: {
|
||||
type: "string",
|
||||
title: "Room",
|
||||
},
|
||||
timestamp: {
|
||||
type: "string",
|
||||
format: "date-time",
|
||||
title: "Timestamp",
|
||||
},
|
||||
data: {
|
||||
additionalProperties: true,
|
||||
type: "object",
|
||||
title: "Data",
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: ["event", "room", "timestamp"],
|
||||
title: "JitsiWebhookEvent",
|
||||
} as const;
|
||||
|
||||
export const $Meeting = {
|
||||
properties: {
|
||||
id: {
|
||||
@@ -960,6 +1016,10 @@ export const $Room = {
|
||||
type: "boolean",
|
||||
title: "Is Shared",
|
||||
},
|
||||
platform: {
|
||||
$ref: "#/components/schemas/VideoPlatform",
|
||||
default: "whereby",
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: [
|
||||
@@ -1030,12 +1090,30 @@ export const $RoomDetails = {
|
||||
type: "boolean",
|
||||
title: "Is Shared",
|
||||
},
|
||||
platform: {
|
||||
$ref: "#/components/schemas/VideoPlatform",
|
||||
default: "whereby",
|
||||
},
|
||||
webhook_url: {
|
||||
type: "string",
|
||||
anyOf: [
|
||||
{
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
type: "null",
|
||||
},
|
||||
],
|
||||
title: "Webhook Url",
|
||||
},
|
||||
webhook_secret: {
|
||||
type: "string",
|
||||
anyOf: [
|
||||
{
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
type: "null",
|
||||
},
|
||||
],
|
||||
title: "Webhook Secret",
|
||||
},
|
||||
},
|
||||
@@ -1091,10 +1169,17 @@ export const $SearchResponse = {
|
||||
description: "Total number of search results",
|
||||
},
|
||||
query: {
|
||||
type: "string",
|
||||
minLength: 0,
|
||||
anyOf: [
|
||||
{
|
||||
type: "string",
|
||||
minLength: 1,
|
||||
description: "Search query text",
|
||||
},
|
||||
{
|
||||
type: "null",
|
||||
},
|
||||
],
|
||||
title: "Query",
|
||||
description: "Search query text",
|
||||
},
|
||||
limit: {
|
||||
type: "integer",
|
||||
@@ -1111,7 +1196,7 @@ export const $SearchResponse = {
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: ["results", "total", "query", "limit", "offset"],
|
||||
required: ["results", "total", "limit", "offset"],
|
||||
title: "SearchResponse",
|
||||
} as const;
|
||||
|
||||
@@ -1449,6 +1534,9 @@ export const $UpdateRoom = {
|
||||
type: "string",
|
||||
title: "Webhook Secret",
|
||||
},
|
||||
platform: {
|
||||
$ref: "#/components/schemas/VideoPlatform",
|
||||
},
|
||||
},
|
||||
type: "object",
|
||||
required: [
|
||||
@@ -1463,6 +1551,7 @@ export const $UpdateRoom = {
|
||||
"is_shared",
|
||||
"webhook_url",
|
||||
"webhook_secret",
|
||||
"platform",
|
||||
],
|
||||
title: "UpdateRoom",
|
||||
} as const;
|
||||
@@ -1641,6 +1730,12 @@ export const $ValidationError = {
|
||||
title: "ValidationError",
|
||||
} as const;
|
||||
|
||||
export const $VideoPlatform = {
|
||||
type: "string",
|
||||
enum: ["whereby", "jitsi"],
|
||||
title: "VideoPlatform",
|
||||
} as const;
|
||||
|
||||
export const $WebhookTestResult = {
|
||||
properties: {
|
||||
success: {
|
||||
|
||||
@@ -74,6 +74,11 @@ import type {
|
||||
V1ZulipGetTopicsResponse,
|
||||
V1WherebyWebhookData,
|
||||
V1WherebyWebhookResponse,
|
||||
V1JitsiEventsWebhookData,
|
||||
V1JitsiEventsWebhookResponse,
|
||||
V1JibriRecordingCompleteData,
|
||||
V1JibriRecordingCompleteResponse,
|
||||
V1JitsiHealthCheckResponse,
|
||||
} from "./types.gen";
|
||||
|
||||
export class DefaultService {
|
||||
@@ -255,7 +260,6 @@ export class DefaultService {
|
||||
|
||||
/**
|
||||
* Rooms Test Webhook
|
||||
* Test webhook configuration by sending a sample payload.
|
||||
* @param data The data for the request.
|
||||
* @param data.roomId
|
||||
* @returns WebhookTestResult Successful Response
|
||||
@@ -939,4 +943,70 @@ export class DefaultService {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Jitsi Events Webhook
|
||||
* Handle Prosody event-sync webhooks from Jitsi Meet.
|
||||
*
|
||||
* Expected event types:
|
||||
* - muc-occupant-joined: participant joined the room
|
||||
* - muc-occupant-left: participant left the room
|
||||
* - jibri-recording-on: recording started
|
||||
* - jibri-recording-off: recording stopped
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public v1JitsiEventsWebhook(
|
||||
data: V1JitsiEventsWebhookData,
|
||||
): CancelablePromise<V1JitsiEventsWebhookResponse> {
|
||||
return this.httpRequest.request({
|
||||
method: "POST",
|
||||
url: "/v1/jitsi/events",
|
||||
body: data.requestBody,
|
||||
mediaType: "application/json",
|
||||
errors: {
|
||||
422: "Validation Error",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Jibri Recording Complete
|
||||
* Handle Jibri recording completion webhook.
|
||||
*
|
||||
* This endpoint is called by the Jibri finalize script when a recording
|
||||
* is completed and uploaded to storage.
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public v1JibriRecordingComplete(
|
||||
data: V1JibriRecordingCompleteData,
|
||||
): CancelablePromise<V1JibriRecordingCompleteResponse> {
|
||||
return this.httpRequest.request({
|
||||
method: "POST",
|
||||
url: "/v1/jibri/recording-complete",
|
||||
body: data.requestBody,
|
||||
mediaType: "application/json",
|
||||
errors: {
|
||||
422: "Validation Error",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Jitsi Health Check
|
||||
* Simple health check endpoint for Jitsi webhook configuration.
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public v1JitsiHealthCheck(): CancelablePromise<V1JitsiHealthCheckResponse> {
|
||||
return this.httpRequest.request({
|
||||
method: "GET",
|
||||
url: "/v1/jitsi/health",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ export type CreateRoom = {
|
||||
is_shared: boolean;
|
||||
webhook_url: string;
|
||||
webhook_secret: string;
|
||||
platform: VideoPlatform;
|
||||
};
|
||||
|
||||
export type CreateTranscript = {
|
||||
@@ -125,6 +126,22 @@ export type HTTPValidationError = {
|
||||
detail?: Array<ValidationError>;
|
||||
};
|
||||
|
||||
export type JibriRecordingEvent = {
|
||||
room_name: string;
|
||||
recording_file: string;
|
||||
recording_status: string;
|
||||
timestamp: string;
|
||||
};
|
||||
|
||||
export type JitsiWebhookEvent = {
|
||||
event: string;
|
||||
room: string;
|
||||
timestamp: string;
|
||||
data?: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
export type Meeting = {
|
||||
id: string;
|
||||
room_name: string;
|
||||
@@ -176,6 +193,7 @@ export type Room = {
|
||||
recording_type: string;
|
||||
recording_trigger: string;
|
||||
is_shared: boolean;
|
||||
platform?: VideoPlatform;
|
||||
};
|
||||
|
||||
export type RoomDetails = {
|
||||
@@ -191,8 +209,9 @@ export type RoomDetails = {
|
||||
recording_type: string;
|
||||
recording_trigger: string;
|
||||
is_shared: boolean;
|
||||
webhook_url: string;
|
||||
webhook_secret: string;
|
||||
platform?: VideoPlatform;
|
||||
webhook_url: string | null;
|
||||
webhook_secret: string | null;
|
||||
};
|
||||
|
||||
export type RtcOffer = {
|
||||
@@ -206,10 +225,7 @@ export type SearchResponse = {
|
||||
* Total number of search results
|
||||
*/
|
||||
total: number;
|
||||
/**
|
||||
* Search query text
|
||||
*/
|
||||
query: string;
|
||||
query?: string | null;
|
||||
/**
|
||||
* Results per page
|
||||
*/
|
||||
@@ -302,6 +318,7 @@ export type UpdateRoom = {
|
||||
is_shared: boolean;
|
||||
webhook_url: string;
|
||||
webhook_secret: string;
|
||||
platform: VideoPlatform;
|
||||
};
|
||||
|
||||
export type UpdateTranscript = {
|
||||
@@ -328,6 +345,8 @@ export type ValidationError = {
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type VideoPlatform = "whereby" | "jitsi";
|
||||
|
||||
export type WebhookTestResult = {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
@@ -621,6 +640,20 @@ export type V1WherebyWebhookData = {
|
||||
|
||||
export type V1WherebyWebhookResponse = unknown;
|
||||
|
||||
export type V1JitsiEventsWebhookData = {
|
||||
requestBody: JitsiWebhookEvent;
|
||||
};
|
||||
|
||||
export type V1JitsiEventsWebhookResponse = unknown;
|
||||
|
||||
export type V1JibriRecordingCompleteData = {
|
||||
requestBody: JibriRecordingEvent;
|
||||
};
|
||||
|
||||
export type V1JibriRecordingCompleteResponse = unknown;
|
||||
|
||||
export type V1JitsiHealthCheckResponse = unknown;
|
||||
|
||||
export type $OpenApiTs = {
|
||||
"/metrics": {
|
||||
get: {
|
||||
@@ -1142,4 +1175,44 @@ export type $OpenApiTs = {
|
||||
};
|
||||
};
|
||||
};
|
||||
"/v1/jitsi/events": {
|
||||
post: {
|
||||
req: V1JitsiEventsWebhookData;
|
||||
res: {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HTTPValidationError;
|
||||
};
|
||||
};
|
||||
};
|
||||
"/v1/jibri/recording-complete": {
|
||||
post: {
|
||||
req: V1JibriRecordingCompleteData;
|
||||
res: {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HTTPValidationError;
|
||||
};
|
||||
};
|
||||
};
|
||||
"/v1/jitsi/health": {
|
||||
get: {
|
||||
res: {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: unknown;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user