Compare commits

...

234 Commits

Author SHA1 Message Date
juancarmore
029802787a Reapply "Revert commits 6c7bfd4 5638025 da7759d ba374ce cf84de4 39a9b7d e990c19"
This reverts commit 450aa85b887e2ce56052c8abe75fbe4722a2ef69.
2026-03-06 17:00:20 +01:00
GitHub Actions
ad413d2791 Bump version to 3.6.0 2026-03-06 11:37:26 +00:00
CSantosM
d025a35e15 frontend: update participant role notification handling in MeetingEventHandlerService 2026-03-04 16:05:13 +01:00
CSantosM
1761517afc backend: update '@livekit/track-processors' to version 0.7.2 2026-03-04 13:59:18 +01:00
juancarmore
9278260837 frontend: improve recording action buttons with consistent attributes and structure 2026-03-04 13:52:35 +01:00
CSantosM
53f62708ce backend(test): increase sleep duration for webhook processing in expired rooms GC test 2026-03-04 12:56:42 +01:00
CSantosM
ba0d0b10c4 backend: Enhances LiveKit agent robustness
LiveKit agent service calls now gracefully handle errors instead of throwing exceptions.

`listAgents` and `getAgent` return sensible defaults (empty array, undefined) on failure, preventing disruption to calling services. `stopAgent` now logs errors during deletion without halting the process.

An early exit condition is also added in the AI assistant service to prevent unnecessary processing if no agents are found, further improving resilience.
2026-03-04 12:33:36 +01:00
CSantosM
8953e9891c backend(test): Extends test sleep for webhook processing
Increases the sleep duration in room deletion test helpers from 1 second to 5 seconds. This ensures that webhooks triggered by room deletion have enough time to process before test execution continues, addressing intermittent test failures caused by premature assertions. This is a temporary measure to improve test stability.
2026-03-04 12:28:35 +01:00
CSantosM
02703b1f83 frontend: enhance captions button functionality and integrate AI assistant for live captions 2026-03-03 19:13:42 +01:00
CSantosM
c808e98820 backend(ai-assistant): implement AI assistant creation and management
- Add OpenAPI components for creating and responding to AI assistant requests.
- Implement AI assistant service for managing live captions capability.
- Create routes and controllers for AI assistant operations (create and cancel).
- Introduce request validation middleware for AI assistant requests.
- Update Redis helper to manage AI assistant locks.
- Integrate AI assistant cleanup in webhook service.
- Enhance LiveKit service to manage agent dispatch for AI assistants.
- Update token service to remove unnecessary parameters related to captions.
- Add typings for AI assistant requests and responses.
2026-03-03 18:43:35 +01:00
CSantosM
56d5126acb frontend: update @livekit/track-processors dependency to version 0.7.2 2026-03-02 17:15:29 +01:00
juancarmore
ac3a728591 Revert "frontend: Refactor user management components and update routes"
This reverts commit f677b18879bb13acf063de6a3366059a3a49d3ed.
2026-02-17 17:40:50 +01:00
juancarmore
90a1c6fde9 backend: refactor migration transforms to return updated document instances and improve MigrationService to execute all transforms sequantilly for each document 2026-02-17 16:03:05 +01:00
juancarmore
7378a8f53e backend: create schema migrations for room and recording from v1 to v2 version 2026-02-17 12:47:31 +01:00
juancarmore
3142f9fe79 backend: update migration README to clarify schema versioning and MIGRATION_REV timestamp requirements 2026-02-17 12:46:38 +01:00
juancarmore
2a1575768f backend: use collection names in schema migration name generation 2026-02-17 12:32:01 +01:00
juancarmore
396c23aa3c backend: remove unused repository injections from MigrationService 2026-02-17 12:30:26 +01:00
juancarmore
96e441726c refactor(migrations): overhaul migration system to use schema transformation maps
- Removed the BaseSchemaMigration class and replaced it with a more flexible schema migration approach using transformation functions.
- Updated global-config, recording, room, and user migrations to utilize the new schema migration map structure.
- Introduced runtime migration registry for better management of migration execution.
- Enhanced migration service to handle schema migrations more efficiently, including improved error handling and logging.
- Added utility functions for generating and validating schema migration names.
- Updated migration repository methods to streamline migration status tracking.
2026-02-17 11:32:34 +01:00
cruizba
a853aa02a2 backend: apply dynamic base path to OpenAPI docs server URLs
When deployed under a base path (e.g. /meet), the Stoplight "Try It"
requests were hitting /api/v1 instead of /meet/api/v1. This applies
the base path to the embedded OpenAPI spec's servers array at serve time,
following the same pattern used for the frontend index.html.

Also renames html-injection.utils to html-dynamic-base-path.utils and
updates function names for better wording.
2026-02-11 19:18:30 +01:00
cruizba
366632741c fix: strip basePath prefix in redirectTo method
Strip basePath prefix if present, since Angular router operates relative to <base href>
2026-02-05 19:40:00 +01:00
CSantosM
1046b5a0dd backend: enhance build script to generate API documentation after compilation 2026-02-05 12:40:49 +01:00
CSantosM
59d722f882 backend: enhance recording start process sending FAILED event to client when an error occurs 2026-02-04 15:21:25 +01:00
cruizba
b08bb10f63 backend: fix URL path extraction to remove basePath prefix 2026-02-03 01:56:58 +01:00
cruizba
177648e6d5 tests: Use getFullPath for constructing recording URLs in assertions 2026-02-02 21:09:34 +01:00
cruizba
b059b88be4 fix tests: Update API path construction with new path 2026-02-02 20:51:03 +01:00
cruizba
4e634dac54 Move LiveKit Webhook route to app level 2026-02-02 19:58:38 +01:00
cruizba
b0c7dcbc9a Introduce base path configuration and update related services 2026-02-02 19:47:18 +01:00
CSantosM
ba7600bfc5 test: Fix default captions config enabled state to false 2026-02-02 17:01:41 +01:00
CSantosM
accb35c7e1 Adds recording encoding options to room config and start recording
Adds configuration options for recording encoding, including presets and advanced settings, allowing users to customize video and audio quality.

This enhancement introduces new schemas for recording encoding presets and advanced options, enabling users to select from predefined encoding profiles or fine-tune specific video and audio parameters.

A conversion helper is implemented to translate between the internal encoding configurations and the format required by the LiveKit SDK.

backend: Adds recording encoding configuration options

Allows users to specify custom audio and video encoding settings for recordings, overriding room defaults.

This enhancement provides greater flexibility in controlling recording quality and file size. It introduces new schema definitions for encoding options and validates these configurations through Zod schemas.

Enforces complete video/audio encoding options

Requires both video and audio configurations with all their properties
when using advanced encoding options for recordings. This change ensures
complete encoding setups and prevents potential recording failures due to
missing encoding parameters. It also corrects a typo of keyframeInterval.

Add video depth option to recording encoding settings
2026-02-02 17:00:01 +01:00
CSantosM
1add921ce0 backend: Allows overriding recording layout
Enables users to override the default recording layout for a room
when starting a recording. This allows customization of the recording
appearance on a per-recording basis, instead of being tied solely to the
room's configuration.
2026-01-28 18:14:29 +01:00
CSantosM
2fe720c90b test: Remove moderatorToken from start and stop recording tests 2026-01-28 18:07:00 +01:00
CSantosM
3f91e281b3 frontend: Controls captions button based on admin config
Updates the captions button to respect the global admin configuration.

The button now displays a disabled state and tooltip when captions are disabled globally, preventing users from toggling them.

The UI is updated to show disabled state and a specific subtitle off icon,
reflecting whether captions are enabled at the system level.
2026-01-28 16:27:30 +01:00
CSantosM
4ac182c244 backend: Update captions agent name and improve environment checks in TokenService 2026-01-28 16:25:43 +01:00
CSantosM
43f7ff5001 backend: Exposes captions config via internal API
Adds an internal API endpoint to retrieve the captions configuration,
allowing the frontend to determine whether captions are enabled.
The configuration is read from the MEET_CAPTIONS_ENABLED environment variable.
2026-01-28 15:21:00 +01:00
CSantosM
30bd4b5a41 Enable captions by default in room configurations and related tests 2026-01-28 14:50:32 +01:00
CSantosM
00433c75a4 Updated pnpm-lock.yaml 2026-01-26 17:21:30 +01:00
CSantosM
becf3070b0 test: Enhance E2EE UI tests by improving chat panel visibility checks and adding wait for animations 2026-01-26 16:46:16 +01:00
CSantosM
21e939e09c Update Jest configuration for integration tests and improve command line options 2026-01-26 14:10:53 +01:00
CSantosM
659cdcaf73 webcomponent: Updates dependencies and improves end-to-end tests
Upgrades Playwright dependency to the latest version.

Removes unnecessary test cleanup functions and simplifies test structure.
Improves test stability by properly handling browser resources.
2026-01-26 13:59:40 +01:00
CSantosM
dbcc9bbb25 test: Improve room closure check with retry logic in delete room tests 2026-01-26 11:09:00 +01:00
CSantosM
215b11e93f Moves recording API to public endpoint
This commit refactors the recording API endpoints from the internal API to the public API.

This change allows users to start and stop recordings using API keys, enabling more secure and flexible access control for recording functionality. It also centralizes recording-related logic in the public API, simplifying the codebase and improving maintainability.
2026-01-23 17:32:18 +01:00
CSantosM
55aab084b0 backend: Add captions configuration to room tests 2026-01-23 16:38:50 +01:00
CSantosM
96b5cd249e testapp: Add captions configuration to room settings and UI 2026-01-23 14:28:30 +01:00
CSantosM
4751e7e989 dockerignore: Remove audio file extensions from ignore list 2026-01-23 10:23:49 +01:00
CSantosM
0a56a74433 frontend: Enables user-controlled live captions
Allows users to toggle live captions on or off.
Introduces a room configuration setting to enable/disable the captions feature.
The captions button visibility is now controlled by the 'showCaptions' feature flag.
2026-01-22 19:28:18 +01:00
CSantosM
cb12d9a8fe backend: Add captions configuration test 2026-01-22 18:35:35 +01:00
CSantosM
9ae27bf32a backend: Adds live captions functionality to rooms
Adds support for live captions in meet rooms.
This includes schema definitions, API configurations,
and LiveKit integration for dispatching captions agents.
Captions are disabled by default and can be enabled per room.
2026-01-22 18:24:50 +01:00
CSantosM
f677b18879 frontend: Refactor user management components and update routes 2026-01-21 18:22:09 +01:00
CSantosM
f95b02e42b frontend: Comment out handleRoomConfigUpdated method for future reference 2026-01-21 17:31:51 +01:00
CSantosM
5f8af67ac6 frontend: Enhances user experience on role updates
Adds a notification and sound effect to inform users when their role is updated.

This provides immediate feedback to the user and improves the overall user experience.
2026-01-21 17:31:34 +01:00
CSantosM
1ef813e509 frontend: Moves sound effects to dedicated service
Refactors sound effect logic into a dedicated `SoundService`.

This change centralizes audio playback functionality, promoting
better code organization and reusability. Removes sound effect logic
from the meeting service.
2026-01-21 17:30:30 +01:00
CSantosM
011e44b4f9 frontend: Removed allowSignalWrites flag because of it is deprecated 2026-01-21 17:28:52 +01:00
CSantosM
ed057612a0 frontend: Update moderation tooltips and move display properties interface 2026-01-21 17:01:23 +01:00
CSantosM
5cdc49d90c frontend: Adds live captions component
Introduces a live captions feature using LiveKit's transcription service.

This adds a new component that displays real-time transcriptions of the meeting audio in. It manages caption lifecycles, handles both interim and final transcriptions, and
provides reactive signals for UI updates.
2026-01-21 12:47:09 +01:00
CSantosM
073f0dc640 backend: Adds speech processing agent support
Enables the capability to integrate speech processing agents by adding room configuration to the token when the agent processing name is set in the environment.
This allows to specify the agent to be dispatched on room creation.
2026-01-21 12:37:06 +01:00
CSantosM
bbd4d5fbaf frontend: Remove unused DestroyRef injection in MeetingContextService 2026-01-21 09:02:20 +01:00
CSantosM
5f722c36e7 frontend: Add sound notification for participant joining the meeting 2026-01-19 17:08:21 +01:00
CSantosM
b5ccd7c087 frontend: Enhance meeting component to manage participant left events and update state 2026-01-18 16:38:55 +01:00
Carlos Santos
13a339eb87 backend: Add main entry point and organize module exports 2026-01-15 16:57:18 +01:00
Carlos Santos
1d5cd9be26 backend: Fix import order and improve path resolution logic 2026-01-15 16:57:01 +01:00
Carlos Santos
68a10ff901 frontend: Refactors selection logic in lists
Ensures the selected items in lists are correctly updated
when the underlying data changes by using `untracked` to avoid circular dependencies.

Introduces a utility function to compare sets for equality,
preventing unnecessary updates and improving performance.
2026-01-15 16:56:19 +01:00
Carlos Santos
eabb559a82 frontend: Reset nextPageToken before refreshing recordings and rooms 2026-01-15 15:36:58 +01:00
Carlos Santos
e70dc6619f frontend: Refactors rooms lists component to use Angular signals
Migrates the rooms lists component to leverage Angular's signal-based inputs.
This improves change detection and simplifies data flow within the component.

Updates the component's template to reflect the use of signal accessors.
Ensures initial filters are correctly applied.
2026-01-15 14:55:43 +01:00
Carlos Santos
520816b983 frontend: Refactors recording list component to use signals
Migrates the recording list component to use Angular signals for input properties and data binding.
This improves performance and simplifies the component's change detection.

- Converts input properties to input signals.
- Uses computed signals for derived values.
- Introduces effect for side effects related to recordings changes.
- Moves recording list model interfaces to shared location.
2026-01-15 14:43:19 +01:00
Carlos Santos
b24992ad24 frontend: Improves HTTP error handling
Refactors error handling to allow handlers to directly return a response.

Updates the error handler service to return null when no handler can process an error.
2026-01-15 13:11:18 +01:00
Carlos Santos
d9e064e971 frontend: Rename initializeTheme method to init for consistency 2026-01-15 12:12:15 +01:00
Carlos Santos
8af00ab6ee frontend: Refactor app component and meeting component to use inline templates and remove unused files 2026-01-15 12:06:49 +01:00
Carlos Santos
2ec42f701d frontend: Enhance E2EE UI tests by adding visibility checks for panel close button and more options menu 2026-01-15 10:59:16 +01:00
Carlos Santos
f77630d1e0 Revert "frontend: Improve E2EE UI tests by enhancing panel close interactions and timeout handling"
This reverts commit 3cb163deee6c306b52ce0bb6d96d4151a1aa8e6e.
2026-01-15 10:26:39 +01:00
Carlos Santos
3cb163deee frontend: Improve E2EE UI tests by enhancing panel close interactions and timeout handling 2026-01-14 19:37:53 +01:00
Carlos Santos
4ecd086f21 backend: Adds layout property to recording info
Adds the 'layout' property to recording information.

This allows tracking the layout used during a recording, enhancing recording metadata.

Updates recording schema and adds layout information to API responses.
2026-01-14 18:46:38 +01:00
Carlos Santos
a1acc9ba22 frontend: Refactor webhook event storage to use sessionStorage and enhance webhook handling in E2E tests 2026-01-14 18:27:33 +01:00
Carlos Santos
0368ab83e6 frontend: Enhance unit tests for WebComponent attributes, commands, events, and lifecycle handling 2026-01-14 17:22:02 +01:00
Carlos Santos
082aa8480c frontend: Configures the application routing
Sets up domain-based routing for different app features.

This change introduces a structured approach to managing application routes,
making it easier to add, modify, and maintain different sections of the application.
It configures routes for authentication, meetings, rooms, recordings, and the console.
2026-01-14 13:57:03 +01:00
Carlos Santos
ca2d41b05e frontend: Remove unused service dependencies from RecordingService 2026-01-14 12:57:26 +01:00
Carlos Santos
db62cf0e1c frontend: Provides adapter interfaces for shared guards
Creates adapter interfaces for meeting context and room member operations.

This allows shared guards to interact with meeting context and room member context without directly depending on domain services, improving modularity and testability.

Adds providers to supply the adapters using existing services, enabling the use of the adapter interface within the guards.
2026-01-14 11:37:33 +01:00
Carlos Santos
3eb06e41e2 frontend: Add confirm dialog component with customizable actions and styles 2026-01-13 18:28:04 +01:00
Carlos Santos
56e025d23d frontend: Moves delete room dialog to rooms domain
Relocates the delete room dialog component to the rooms domain for better organization and separation of concerns.

Updates imports and references to reflect the new location of the component.
2026-01-13 18:21:07 +01:00
Carlos Santos
6c730a6dbc frontend: Remove unused README files for Auth and Rooms interceptor handlers 2026-01-13 17:37:11 +01:00
Carlos Santos
163e0d5f99 frontend: Update meeting route to use dynamic component loading for AppCeMeetingComponent 2026-01-13 17:36:57 +01:00
Carlos Santos
834dc2be42 frontend: Update E2EE UI tests to reflect changes in expected video poster counts 2026-01-13 17:36:31 +01:00
Carlos Santos
7cddb59e2d frontend: Refactors recording URL generation
Moves recording URL generation to the component using the URL.

This provides more flexibility in how the URL is generated,
allowing the component to handle different scenarios.
The service is no longer responsible for generating the URL.
2026-01-12 20:13:26 +01:00
Carlos Santos
8afed3a2f8 frontend: Refactors project structure for better organization
Moves code into domain-specific folders for better modularity.
Updates imports to reflect the new directory structure.
2026-01-12 19:51:49 +01:00
Carlos Santos
dac64bb1a9 frontend: project restructuring by domain
- centralize HTTP interceptor error handling via registry and handlers
2026-01-12 17:52:46 +01:00
Carlos Santos
c42a3ce1cf frontend: refactor layout option IDs to use constants from MeetRecordingLayout 2026-01-09 11:57:41 +01:00
Carlos Santos
6455a4937c frontend: refactor GlobalConfigService to use Angular's inject for dependency injection 2026-01-09 11:51:23 +01:00
Carlos Santos
4bee373e85 frontend: refactor ConfigComponent to use Angular's inject for services 2026-01-09 11:50:01 +01:00
Carlos Santos
e0c0453a02 frontend: refactor ColorField and ThemeColors types for color configuration 2026-01-09 11:48:30 +01:00
Carlos Santos
7a83cc57fd frontend: remove unused imports in MeetingComponent 2026-01-09 11:38:03 +01:00
Carlos Santos
7d6f61e12c frontend: update default layout mode to SMART_MOSAIC in MeetLayoutService 2026-01-09 11:37:51 +01:00
Carlos Santos
6f841eb254 Adds recording layout configuration
Enables configuration of recording layouts.

Specifies the recording layout in the room configuration.
Now supports different layouts, such as grid, speaker, and single-speaker.
Updated zod validation schemas
Updated integration tests
2026-01-08 19:51:04 +01:00
Carlos Santos
be5e3ffb1d backend: enhance room configuration schemas for updates and creation 2026-01-07 19:51:35 +01:00
Carlos Santos
0ba9d0b297 backend: Simplifies room configuration
The default configuration is assigned in the API validator middleware.
Streamlines the room configuration process by directly using the provided configuration options.
2026-01-07 18:01:14 +01:00
juancarmore
caad4bc550 backend: remove legacy storage service and migration process 2026-01-07 14:07:40 +01:00
juancarmore
450aa85b88 Revert "Revert commits 6c7bfd4 5638025 da7759d ba374ce cf84de4 39a9b7d e990c19"
This reverts commit 0ab6a48e13ec15267de4373f2647745cc184bb87.
2026-01-07 10:13:08 +01:00
juancarmore
86af733b37 backend: fix filename format for API keys in S3KeyBuilder 2025-12-31 00:51:56 +01:00
juancarmore
8d685e6ae5 test: enhance recordings and rooms API tests with filtering and sorting functionality 2025-12-31 00:14:14 +01:00
juancarmore
05980df465 test: update import paths for RoomData and TestContext in various test files 2025-12-31 00:12:48 +01:00
juancarmore
744fd05724 frontend: improve promise handling in MeetingLobbyService 2025-12-29 17:42:06 +01:00
cruizba
d1431687f0 bump to 3.5.0 2025-12-29 13:11:46 +01:00
juancarmore
87b86652dc backend: update room creation to use roomConfig correctly 2025-12-25 14:18:02 +01:00
Carlos Santos
115993fe69 frontend: adjust horizontal layout styles for improved spacing and responsiveness 2025-12-23 16:50:49 +01:00
Carlos Santos
f65f5dd33d frontend: refactor hidden participants indicator styles for improved layout and consistency 2025-12-23 13:51:16 +01:00
Carlos Santos
d78eae9810 frontend: update styles in hidden participants indicator for improved consistency and theming 2025-12-23 13:35:07 +01:00
Carlos Santos
8fbe8fb716 frontend: enhance hidden participants indicator to display names of hidden participants in both horizontal and vertical layouts 2025-12-23 13:08:25 +01:00
Carlos Santos
6a9bd2be95 frontend: adjust step content card styles for improved layout and add height property to recordings header for better UX 2025-12-23 11:40:27 +01:00
Carlos Santos
320135dd39 frontend: fix overflow property in users permissions icon for better styling 2025-12-23 11:35:30 +01:00
Carlos Santos
0ca445a89b frontend: refine layout and spacing in room details component for improved visual consistency 2025-12-23 11:25:54 +01:00
Carlos Santos
76ea36cf69 frontend: refactor filter menu styles for consistency across recording and rooms lists components 2025-12-23 11:02:58 +01:00
juancarmore
b0b95f38a8 frontend: remove UtilsHelper and update repositories and services to handle field selection directly in database 2025-12-23 01:05:01 +01:00
juancarmore
6ad700f538 frontend: enhance empty state message in recording lists to show room-specific information 2025-12-22 21:50:19 +01:00
juancarmore
11dcd1238a frontend: update room recordings component to support filters and sorting 2025-12-22 21:22:56 +01:00
juancarmore
8f858267b4 frontend: implement sorting functionality in rooms list and update filters to support sorting options 2025-12-22 20:53:26 +01:00
juancarmore
cea8301e00 frontend: add sorting functionality to recording lists and update filters to include sort options 2025-12-22 20:31:41 +01:00
juancarmore
f2c4df0de6 frontend: enable filters in rooms list and update room service to support status and sorting options 2025-12-22 19:29:12 +01:00
juancarmore
eb3e11c37c frontend: enable filters in recording lists and update filter handling in service 2025-12-22 17:35:54 +01:00
juancarmore
f5b805f3a3 backend: enhance recording and room repositories with additional filtering options 2025-12-22 17:21:57 +01:00
juancarmore
1c955c60d0 backend: enhance recording and room filters with status and sorting options 2025-12-22 17:21:57 +01:00
juancarmore
113dbe4f88 openapi: add query parameters for status, sort field, and sort order in get all endpoints 2025-12-22 17:21:57 +01:00
juancarmore
f6d685a158 backend: modify room config validator and ensure recording is disabled when E2EE is enabled 2025-12-22 17:21:57 +01:00
Carlos Santos
60cb1afdf3 frontend: implement automatic participant synchronization using signals in MeetingContextService 2025-12-22 16:54:51 +01:00
Carlos Santos
b4f482f9d7 frontend: enhance hidden participants indicator with improved layout and description text 2025-12-22 16:54:36 +01:00
Carlos Santos
3a83efa668 frontend: add hidden participants indicator component with responsive layouts 2025-12-22 14:12:17 +01:00
juancarmore
0ab6a48e13 Revert commits 6c7bfd4 5638025 da7759d ba374ce cf84de4 39a9b7d e990c19 2025-12-19 12:48:22 +01:00
Carlos Santos
9a853f285b test: remove console logs and update chat message expectations in E2EE UI tests 2025-12-17 17:47:28 +01:00
Carlos Santos
1d552c9098 frontend: refactor isMobileView to use computed property for better performance 2025-12-17 11:44:49 +01:00
Carlos Santos
c806e90e42 docker: update Node.js version in Dockerfile to 22.21.1 2025-12-17 11:20:08 +01:00
Carlos Santos
3a2ce89a3d chore: update dependencies to latest versions
- Updated dotenv from 16.5.0 to 16.6.1
- Updated express from 5.1.0 to 5.2.1
- Updated @types/express from 5.0.1 to 5.0.6
- Updated @types/node from 22.15.17 to 22.19.3
- Updated @types/socket.io from 3.0.1 to 3.0.2
- Updated concurrently from 9.1.2 to 9.2.1
- Updated typescript from 5.9.2 to 5.9.3
2025-12-17 11:01:01 +01:00
Carlos Santos
7c75a9ddd0 frontend: reorder imports and add type annotation for currentTheme computed property 2025-12-17 10:08:37 +01:00
Carlos Santos
4d3adc1922 frontend: remove unused webpack configuration file 2025-12-16 18:23:19 +01:00
Carlos Santos
d925cb7843 frontend: refactor step indicator layout for improved responsiveness and structure 2025-12-16 17:58:32 +01:00
Carlos Santos
59ea1f881b frontend: rename DEFAULT_MAX_SPEAKERS to INITIAL_SPEAKERS_COUNT and adjust max speakers for mobile devices 2025-12-16 12:42:42 +01:00
Carlos Santos
d059872667 frontend: remove deprecated end-to-end tests and configuration files 2025-12-16 12:04:45 +01:00
Carlos Santos
bd1c67ba31 Add test suite documentation for OpenVidu Meet 2025-12-16 12:04:34 +01:00
Carlos Santos
f178f2a611 frontend: Increase minimum speaking duration for smart layout display to enhance participant tracking 2025-12-11 13:50:25 +01:00
Carlos Santos
477119a06f frontend: Updated livekit client js 2025-12-11 10:09:59 +01:00
Carlos Santos
cbe07bcf4f frontend: Remove redundant visibility checks for speakers in custom layout tests 2025-12-10 17:16:23 +01:00
Carlos Santos
34f50d0dee frontend: Add wait timeout for virtual background application in tests 2025-12-10 15:58:15 +01:00
Carlos Santos
9ff200fa88 frontend: Add test for hiding audio-muted participants in Smart Mosaic layout 2025-12-10 11:10:10 +01:00
Carlos Santos
d7cefdfd47 frontend: Update E2E tests to handle optional event text and clean up imports 2025-12-09 12:19:17 +01:00
Piwccle
c93b369a4f
Update GCS bucket name in integration test workflow 2025-12-05 15:18:16 +01:00
Carlos Santos
cf3f03bf3c ci: Add LK CLI installation step to E2E test workflow
test: Introduce wait timeout before leaving the room in tests
2025-12-05 12:10:34 +01:00
Carlos Santos
2761e68dd8 backend: Implement room status validation and cleanup for active meetings 2025-12-05 11:49:14 +01:00
Carlos Santos
a3d4fda6ae frontend: Adds tests for Smart Mosaic layout 2025-12-04 19:42:44 +01:00
Carlos Santos
1abdc45ff3 frontend: Enhances custom layout screen sharing
Ensures screen sharing participants are always displayed, even if not active speakers.

Modifies the participant proxy to selectively hide camera tracks when a participant is only displayed for screen sharing.
This prevents unnecessary camera rendering in the custom layout.
2025-12-04 19:41:58 +01:00
Carlos Santos
5ef051658a frontend: Enhances smart mosaic layout
Improves the smart mosaic layout to enhance the user experience and performance.

- Updates participant rendering logic for smart mosaic layout.
- Optimizes audio track management to prevent audio leaks.
- Implements audio focus by selectively muting tracks for inactive speakers.
2025-12-04 17:30:25 +01:00
Carlos Santos
c51a5173dd root: Enables organize imports on save
Configures the IDE to automatically organize imports upon saving files.

This enhances code cleanliness and consistency by ensuring imports are
automatically sorted and unnecessary imports are removed.
2025-12-04 16:52:58 +01:00
Carlos Santos
07b22a0d29 Refactors room parameter extraction
Streamlines parameter handling by centralizing logic.
The `RoomService` is no longer responsible for setting the `roomId` and `roomSecret`.
Instead, the `MeetingContextService` handles this and persists the room secret in session storage.
2025-12-03 18:01:58 +01:00
Carlos Santos
1663b008ed frontend (test): add Smart Mosaic layout helper functions and fake participant management
- Implemented helper functions for configuring Smart Mosaic layout, including setting participant count and waiting for participant visibility.
- Created a new file for managing fake participants, allowing for joining and disconnecting from LiveKit rooms using both CLI and browser-based methods.
- Introduced interfaces for browser-based fake participant options to streamline participant creation with audio and video assets.
2025-12-02 21:02:40 +01:00
Carlos Santos
f930bf1447 frontend: Exposes and provides layout service
Exposes the layout and storage services from the shared components library.

Provides the layout service to make it available for dependency injection.
2025-12-02 21:01:12 +01:00
Carlos Santos
8e9443351c frontend: Improves active speaker detection
Refines active speaker detection for smart layouts.

It now considers audio level threshold, minimum speaking duration, and a grace period to avoid rapid speaker switching.

Also, updates the speaker recency order to prioritize currently active speakers while maintaining a history of recent speakers.
2025-12-02 21:00:33 +01:00
juancarmore
6c7bfd4d3f openapi: add accessUrl field to room schema and update success responses that include room info 2025-12-02 14:18:39 +01:00
Carlos Santos
68c5ce7cd2 frontend: Refactors layout and feature configurations
Consolidates layout management into a dedicated component and service.

- Replaces layout selection logic with feature-based approach.
- Improves code readability and maintainability.
2025-12-01 16:55:54 +01:00
juancarmore
5638025211 Refactor OpenAPI components for user and room management
- Updated user login request body to define username and password directly instead of referencing an external schema.
- Removed obsolete recording token request schema.
- Added new request body for updating room anonymous access configuration.
- Deleted outdated room guests request body.
- Enhanced room member request body documentation for clarity on custom permissions.
- Introduced new request body for updating room roles configuration.
- Added error response schema for user ID already exists.
- Created success response schema for retrieving authenticated user info.
- Modified success response for retrieving multiple users to use userId instead of username.
- Updated success response for room members to reflect changes in memberId and access URLs.
- Adjusted success response for room details to include roles instead of guests.
- Created success response for updating room anonymous access configuration.
- Created success response for updating room roles configuration.
- Revised meet-user schema to use userId instead of username and simplified role representation.
- Deleted obsolete user-credentials schema.
- Introduced meet-room-anonymous-config schema for anonymous access configuration.
- Removed obsolete meet-room-guests schema.
- Updated meet-room-member schema to clarify memberId and name usage.
- Revised meet-room schema to replace guests with roles and added anonymous access configuration.
- Updated OpenAPI paths to reflect changes in user and room management endpoints.
2025-12-01 13:50:27 +01:00
juancarmore
da7759d249 openapi: add specification for user management API with create, retrieve and delete user endpoints 2025-11-28 13:31:37 +01:00
juancarmore
ba374ce229 openapi: standardize 'username' field naming and update related descriptions for room member APIs 2025-11-28 12:41:22 +01:00
juancarmore
cf84de4221 openapi: remove deprecated room member roles and permissions endpoints and related schemas 2025-11-28 12:30:43 +01:00
juancarmore
39a9b7da02 openapi: add room guests management API with update permissions for moderator and speaker roles 2025-11-28 12:17:24 +01:00
juancarmore
e990c19672 openapi: add specification for room member management API with add, update, delete, and retrieve endpoints 2025-11-28 11:19:59 +01:00
Carlos Santos
66b7f6026b frontend: Enhances smart mosaic layout configuration
Allows configuring the number of visible participants in Smart Mosaic layout mode using a slider.

The minimum and maximum number of participants are now configurable via constants.

Updates the slider to use value binding instead of ngModel.
2025-11-27 12:30:38 +01:00
Carlos Santos
21971e1895 frontend: enhance E2EE key input handling with computed visibility and raw value access 2025-11-27 09:33:20 +01:00
cruizba
246d6e91a4 docker: add tzdata installation to Dockerfiles for timezone support 2025-11-26 11:12:42 +01:00
Carlos Santos
d20571b0ef frontend: enable layout selector feature for smart layout configuration 2025-11-25 13:57:09 +01:00
Carlos Santos
f6abd1cb4c frontend: Refactor customization components
Moves the copy link button to a new component for additional toolbar buttons.

This allows for better organization and customization of the toolbar,
especially on mobile where space is limited. The "leave" button for
moderators is now separate.

Renamed components for better understanding and readability
2025-11-25 13:55:45 +01:00
Carlos Santos
bd021c9576 frontend: implement layout selector feature with conditional rendering in settings and toolbar 2025-11-25 13:55:45 +01:00
Carlos Santos
c3ca84ad66 frontend: remove unused meeting components plugins and action handler interfaces 2025-11-25 13:55:45 +01:00
Carlos Santos
153af9c673 frontend: enhance layout management with reactive settings and storage integration 2025-11-25 13:55:45 +01:00
Carlos Santos
c8cfb6598e frontend: add meeting settings panel and more options buttons for layout configuration 2025-11-25 13:55:45 +01:00
Carlos Santos
b177b3b02e frontend: update no rooms state message and styling for better user guidance 2025-11-25 13:55:45 +01:00
Carlos Santos
f83a5d8942 frontend: adjust margin-bottom for recordings toolbar to improve spacing 2025-11-25 13:55:45 +01:00
Carlos Santos
40475dc372 frontend: use content projection for configuring videoconference components
Refactored all components and services related to the meeting
2025-11-25 13:55:45 +01:00
Carlos Santos
fd998e7b6b frontend: implement MeetingLayoutComponent with reactive layout management and active speakers tracking 2025-11-25 13:55:44 +01:00
juancarmore
8ccc5d1a8b test: refactor code in tests for garbage collection of orphaned locks, stale recordings and expired rooms 2025-11-24 20:17:10 +01:00
juancarmore
f71b567823 backend: extract shceduler methods from RoomService and RecordingService and create RoomScheduledTasksService and RecordingScheduledTasksService for managing scheduled tasks 2025-11-24 20:14:25 +01:00
juancarmore
a9360ef452 backend: refactor recording access secret retrieval to use RecordingService 2025-11-23 21:47:46 +01:00
juancarmore
3aaf976964 backend: add new methods to global config service and refactor code for improved clarity 2025-11-23 21:18:42 +01:00
juancarmore
73813feb38 backend: rename and refactor various schemas and functions 2025-11-23 20:30:50 +01:00
juancarmore
bdbc6d02ad test: update orphaned lock age in garbage collector tests for accuracy 2025-11-23 17:46:15 +01:00
juancarmore
848cf2ca17 test: refactor stale recordings cleanup tests for improved clarity and functionality 2025-11-23 17:23:53 +01:00
juancarmore
49b44d0353 backend: remove unnecessary index files and update import paths 2025-11-23 17:23:53 +01:00
juancarmore
0d6838019d backend: enhance recording management with active recordings retrieval and stale cleanup improvements 2025-11-23 17:23:52 +01:00
juancarmore
253b435fbe backend: add SERVER_TRUST_PROXY configuration for flexible proxy handling 2025-11-23 17:23:52 +01:00
juancarmore
447a1fc9e5 backend: refactor internal configuration and service tasks for improved room and recording management 2025-11-23 17:23:52 +01:00
juancarmore
5234b28917 backend: update environment variable defaults to use nullish coalescing operator 2025-11-23 17:23:52 +01:00
juancarmore
69df748002 backend: refactor code to centralize all TS interfaces, types, enums and schemas under the models directory 2025-11-23 17:23:52 +01:00
cruizba
b711840349 ci: update workflows to use LABEL_WORKER_SELFHOSTED var 2025-11-19 20:08:24 +01:00
cruizba
69399bb2ff meet-demo: remove Caddyfile reference from deployment README 2025-11-19 17:53:24 +01:00
cruizba
77528b28f4 meet-demo: remove Caddyfile and update docker-compose to use auto-https image 2025-11-19 17:51:57 +01:00
juancarmore
fad38b696d backend: refactor environment variable usage across services and tests 2025-11-18 18:43:05 +01:00
juancarmore
e3fe104b05 backend: enhance login limiter configuration for better proxy compatibility and adjust base URL middleware condition 2025-11-18 17:41:36 +01:00
juancarmore
4f9116707c frontend: update room configuration methods to accept partial configurations and improve handling of optional properties 2025-11-18 14:22:02 +01:00
juancarmore
3f25ba6f74 test: update room configuration methods to accept partial configurations and enhance related tests 2025-11-18 14:20:33 +01:00
juancarmore
496591695a backend: update room configuration schemas for partial updates and default values 2025-11-18 14:19:56 +01:00
juancarmore
45ee463bc6 backend: enhance migration service to handle existing records and track failures 2025-11-18 14:02:03 +01:00
juancarmore
3ae55d0814 backend: add delete method for global configuration and skip initialization if already set 2025-11-18 11:38:42 +01:00
juancarmore
f74b50d5c8 docs: update README to reflect MongoDB storage architecture and migration system 2025-11-18 10:59:09 +01:00
juancarmore
0f237af827 backend: implement MongoDB schema migration system
- Added internal configuration for schema versions in internal-config.ts.
- Created migration README.md to document the migration process and architecture.
- Developed base migration class and specific migration files for each collection (API key, global config, room, recording, user).
- Established migration registry to manage and execute migrations in order.
- Updated repository schemas to include schemaVersion for migration tracking.
- Enhanced migration service to orchestrate schema migrations and handle migration execution.
2025-11-18 10:27:26 +01:00
juancarmore
e30aa5f1a5 backend: update sanitizeRoomId to allow uppercase letters in identifiers 2025-11-17 14:47:28 +01:00
juancarmore
f62e59168d test: update non-existent IDs format in bulk delete recording and room tests 2025-11-17 13:46:58 +01:00
juancarmore
99283ab63d test: update room member token response tests to use participant identity prefix 2025-11-14 20:34:02 +01:00
juancarmore
6b3ef47f08 backend: enhance participant identity handling by creating a unique identity based on participant name 2025-11-14 20:33:48 +01:00
juancarmore
152a877054 test: enhance room creation tests with additional sanitization cases and roomId prefix validation 2025-11-14 19:14:57 +01:00
juancarmore
3665c70105 backend: update room validators to admit all types of characters in the room name and add room ID prefix sanitization method to create roomId from room name 2025-11-14 19:14:00 +01:00
juancarmore
294bd1b7ec frontend: update error messages for invalid room and recording links in ErrorComponent 2025-11-14 12:55:49 +01:00
juancarmore
8d12105b91 ci: fix report and log paths in backend and E2E test workflows 2025-11-14 12:18:44 +01:00
Piwccle
28b58a80bf fix: update GCS bucket name to openvidu-appdata-gcp in backend integration tests 2025-11-14 12:04:18 +01:00
juancarmore
a518b16b6b ci: update artifact path in backend integration test workflow 2025-11-14 11:34:36 +01:00
juancarmore
6eb33c6198 Delete participant and recording tokens and implement room member token. Remove unused cookie transport mode for tokens 2025-11-14 11:23:25 +01:00
Carlos Santos
a56a119993 frontend: correct property name for virtual backgrounds in RoomConfigComponent 2025-11-13 13:51:40 +01:00
Carlos Santos
26bc6cdfc1 backend: improve documentation for stale recording evaluation logic 2025-11-13 10:50:22 +01:00
Carlos Santos
f3de3e0fa3 test: update leaveRoom calls to include optional parameters for role and force leave 2025-11-12 18:14:03 +01:00
Carlos Santos
72119685ad frontend: remove build:ov-components from build script 2025-11-12 16:56:54 +01:00
Carlos Santos
84b74ea0f3 frontend: update livekit-client version to 2.15.15 in package.json and pnpm-lock.yaml 2025-11-12 12:00:43 +01:00
Carlos Santos
9fe20f6e87 build: enhance clean script to remove pnpm-lock.yaml and add clean:ov-components 2025-11-12 11:22:57 +01:00
Carlos Santos
27094be54e test: enhance leaveRoom function to optionally wait for meeting to end 2025-11-11 20:40:53 +01:00
Carlos Santos
d377b016e2 tests: update log level to debug and remove commented timeout in tests 2025-11-11 19:53:18 +01:00
Carlos Santos
5b94728bc9 baackend: allow meeting timeouts to be set via environment variables 2025-11-11 19:53:00 +01:00
Carlos Santos
5131f9e717 test: reduce wait time for recording tests and improve cleanup process 2025-11-11 19:43:23 +01:00
Carlos Santos
32a9a31d8b test: disconnect all participants for allowing update room 2025-11-11 18:16:46 +01:00
Carlos Santos
ae5907cbbd meet.sh: add webcomponent bundle watcher to development commands 2025-11-11 16:55:17 +01:00
Carlos Santos
d9a31edb60 frontend: update livekit-client dependency to version 2.15.15 2025-11-11 16:27:24 +01:00
Carlos Santos
d3554aa6cb backend: fixed unique name reservation logic to prevent infinite suffix concatenation 2025-11-11 16:12:54 +01:00
Carlos Santos
3ec9b43ce4 test: add tests for unique name reservation edge cases 2025-11-11 16:04:24 +01:00
Carlos Santos
253ad630c7 backend: set default timeouts for meeting empty and departure scenarios 2025-11-11 14:02:27 +01:00
Carlos Santos
d72149c97d Prevents editing rooms with active meetings
Enhances room management by preventing modifications to rooms with active meetings.

Adds validation to backend to prevent updates to room configuration during an active meeting.

Improves frontend user experience by disabling the room editing option and adding a guard to redirect users away from the edit page.
2025-11-11 14:00:00 +01:00
Carlos Santos
449f9cbf25 Merge branch 'e2ee_feature' 2025-11-10 17:55:10 +01:00
Carlos Santos
b055ef0333 update file exclusion patterns in workspace settings
webcomponent: Added missing and necessary js file

Update .gitignore to specify backend public directory exclusion

webcomponent: Add error handling for invalid base URL in OpenViduMeet component

webcomponent: Update Jest configuration for improved testing setup

webcomponent: Enhance iframe attribute tests and add support for optional query parameters

webcomponent: Refactor documentation copying in build_webcomponent_doc function for improved readability and add absolute path resolution

Add E2EE_KEY property to WebComponentProperty enum for end-to-end encryption support

meet.sh: Enhance build_rest_api_doc function with output file handling and user confirmation for overwriting

frontend: replace removeRoomSecretGuard with removeQueryParamsGuard for enhanced query parameter management

frontend: add E2EE key handling in room service and update query params guard

Updated pnpm-lock.yaml

Enables end-to-end encryption (E2EE)

Adds E2EE functionality to meeting rooms.

Significant changes:
- Allows encryption of the participant name
- Introduces setting and getting E2EE keys
- Ensures recording is disabled when encryption is enabled

webcomponent: Added e2e test for checking the e2ee funcionality

frontend: Sanitize participant name before request for a token

fix: clean up formatting in openvidu-meet.code-workspace
2025-11-10 17:54:33 +01:00
juancarmore
1d55311757 test: enhance type safety in request helpers 2025-11-07 09:59:55 +01:00
juancarmore
d52524241f test: add test for handling expired access token with valid participant token 2025-11-06 17:49:04 +01:00
juancarmore
3fdf2144ab backend: streamline authentication validators and improve error handling 2025-11-06 17:48:46 +01:00
juancarmore
e6d04aca16 Migrate storage from S3 to MongoDB:
commit 7fc703b7a01c038cfff69c88fea5d681b3011ea1
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Nov 5 17:45:06 2025 +0100

    backend: add E2EE configuration schema to MeetRoom

commit 3ad51133aaa696c36b9fc5dd1c271b5e09077e0b
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Nov 5 16:15:13 2025 +0100

    backend: enhance MongoDB configuration logging and validation

commit b5b52e97dd4a0e16dbb5cda53dc406aa5c739380
Author: cruizba <carlos.ruizbal@gmail.com>
Date:   Wed Nov 5 15:50:05 2025 +0100

    feat: add MongoDB configuration options for optional mongodb and configurable uri

commit c6f0c35435a18365c99f44c692d5d2f2a9bd53ab
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Nov 5 13:59:10 2025 +0100

    ci: update backend integration test scripts and workflow

commit 19a1348f2f695a27694f1c5e80de696d039b6f4e
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 31 12:05:38 2025 +0100

    frontend: replace AuthService with ApiKeyService for API key management

commit 9465e40bc1babfae1203dc317907dc86dc57cd0c
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 31 12:05:07 2025 +0100

    test: refactor auth and api key tests structure to improve consistency

commit b154aa8186eaaa51e027fc1459b9175f87affbd8
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 31 12:02:42 2025 +0100

    openapi: move API key management endpoints to a dedicated file and update references

commit 6987d2b587d1cd6ba85f2ea38c408957e5f0de04
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 31 12:01:00 2025 +0100

    backend: move API key management endpoints to its own controller

commit 8c9452bb74887265920942e3253921a43504790b
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 31 12:00:00 2025 +0100

    backend: comment out MigrationService import and related export to prevent initialization error

commit daa923fa9f6ee68cb4f4ebfa61ce16026fbdc374
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 23:09:18 2025 +0100

    backend: implement migration service

commit 058593fb9488ae00077e28a591c7ea2a8b8d96cc
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 23:08:05 2025 +0100

    backend: add migration repository and model to handle database migrations

commit 4cbc9a9f48ede801333bfe37f0dba2993a79c29c
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 19:41:01 2025 +0100

    backend: refactor update repository methods to throw errors instead of returning null for not found cases

commit 03496a733b9fa39776eb4bf70057459c7e567954
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 17:55:42 2025 +0100

    openapi: update roomName parameter description and reference in recordings path

commit 74293e04967fb1416b69324294ae864df9173f91
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 17:55:04 2025 +0100

    openapi: add analytics endpoint and schema for usage metrics

commit 8de171b0b340ffa787ef136a3e516f03f96b1938
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 17:40:24 2025 +0100

    test: add analytics API and corresponding security tests

commit aaa15acdda5f09c6c0e45d24385cc9ec5daca55b
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 14:04:58 2025 +0100

    frontend: implement analytics service and update overview component to use new metrics

commit 13bad60bcc02e9d7aa46fc9bb96f7cc85ec818cc
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 14:04:23 2025 +0100

    backend: add analytics endpoint for usage metrics

commit ee820bba27f421bb2f9d34130bc00b41aefad217
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 13:18:29 2025 +0100

    backend: replace z.enum with z.nativeEnum for improved type safety in validation schemas

commit 1d394d059e6beef47faddd2205482974ecc1860c
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Thu Oct 30 11:50:03 2025 +0100

    backend: update MongoDB configuration to use new environment variables and improve connection string handling

commit 56c0c3a1bd19bbd2a5e0fdbe582fdf288c6f33d1
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 18:23:06 2025 +0100

    frontend: update room ID reference in recording lists component

commit 189d1b26ad18d29cf9f7c6f85c2524ed5ad33f72
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 18:12:07 2025 +0100

    tests: remove unused MeetStorageService references and related tests

commit fe3fcdba35afcf186b0ff05e9ec3b2ae05da1005
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 17:31:18 2025 +0100

    backend: rename MeetStorageService to LegacyStorageService and remove all unused methods

commit fa782f234d561b5f7f6d4a50e54e3278b9beaec4
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 15:56:31 2025 +0100

    backend: replace MeetStorageService with RecordingRepository and BlobStorageService for recording management

commit 51dea37c07e477bc7e447b2e57acd21b44deb5e4
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 15:53:48 2025 +0100

    frontend: add roomName filter to recording service and recordings component

commit fa283e7c51b3382300cb25fa5f8a9e144637c757
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 15:53:04 2025 +0100

    backend: add roomName filter in get recordings endpoint

commit d1dfb24cfda2e22d739f506bf0213275cd4b2bdd
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 15:51:00 2025 +0100

    backend: implement BlobStorageService for managing recording media files in object storage

commit ce293cf37545fa3aaad638eb25dfd9ae5fc8dd72
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 15:48:04 2025 +0100

    backend: add unique index for efficient querying on MeetApiKey and MeetGlobalConfig schemas

commit 3d999b4249e15f63ef086d2ab38485e0fbadb27e
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Wed Oct 29 15:47:44 2025 +0100

    backend: add RecordingRepository and schema for managing recording entities

commit 757636c55254e76643b99a66bc583ab834c5eadd
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Tue Oct 28 13:05:12 2025 +0100

    tests: refactor list rooms with pagination test to create rooms sequentially and ensure correct ordering

commit cda25543e30883431962bef8617cb245eade8a1d
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Tue Oct 28 13:04:32 2025 +0100

    tests: centralize method restoreDefaultGlobalConfig and refactor code

commit 726d128d7471ad4abbaabda086304f22705ddf82
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Tue Oct 28 13:01:17 2025 +0100

    backend: enhance GlobalConfig schema with authentication, security, webhook, and room configuration sub-schemas

commit fd49fbb03cd8d70f29cc5781a0e0b9b5244f4747
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Tue Oct 28 11:02:34 2025 +0100

    backend: add StorageInitService for managing storage initialization and refactor dependency injection

commit 783f480337e61bfc19ad6d19f3b84c523577c309
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Tue Oct 28 11:01:58 2025 +0100

    backend: refactor middleware and services to use GlobalConfigService for configuration management

commit d28247647c2e0712c0575faa8a85a8c67a75f343
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 22:23:40 2025 +0100

    backend: move authenticateUser method to UserService and rename AuthService to ApiKeyService

commit c8f98391a178da4f9525069203fe4e3d2aecfaaa
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 22:21:37 2025 +0100

    backend: implement GlobalConfigService for managing global configuration and update related controllers

commit 08421feffc8cd4cadb8f2df3b4c41169d4776572
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 22:20:23 2025 +0100

    backend: add GlobalConfigRepository and schema for managing global configuration

commit e1e1b0dda511fb5fbdd8fc88f8a691bc974866c9
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 13:53:52 2025 +0100

    backend: refactor AuthService and MeetStorageService to use ApiKeyRepository for API key management

commit c46fd1669d0923a63195ef95ddf3105584fc18fc
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 13:52:56 2025 +0100

    backend: add ApiKeyRepository and schema for managing API keys

commit c1220eb89b98e842009fd16d95ddd87fd87ae02c
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 13:52:27 2025 +0100

    backend: rename UserDocument and UserModel to MeetUserDocument and MeetUserModel for consistency

commit 331e4ca264086e4fd0e947f2c8adc04dbfe7f831
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 12:27:43 2025 +0100

    backend: replace MeetStorageService usage with UserRepository in UserService

commit ec074307c3cd8c30f4babef5194fc4ebbe7ea7c0
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 12:05:15 2025 +0100

    test: update startTestServer calls to await for asynchronous initialization

commit 3bba2e2822824a1855e6691c0c3b456c9ac5dd3a
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Mon Oct 27 12:04:39 2025 +0100

    test: initialize eager services in startTestServer and update calls to await for asynchronous initialization

commit e52f7353515f95835c9d15dba41ff33a2e26d367
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 19:40:04 2025 +0200

    backend: add User schema and repository for user management

commit 10c548afa9e45dd72d0fb86c9dab0a601c08e652
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 19:39:38 2025 +0200

    backend: add findAll method to BaseRepository and findExpiredRooms method to RoomRepository

commit cbe467e0e5475311f8aea4b4ff99a481007537c0
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 19:39:09 2025 +0200

    backend: optimize MeetRoom schema by adding indexes for efficient querying

commit fb95ef3248e64721e107c3c019e6a61a210ad6ce
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 18:07:38 2025 +0200

    backend: enhance cursor-based pagination to handle null/undefined values in MongoDB queries

commit bf709bb8e4a301a5738e44c7d7fb2f219846c3ce
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 18:07:25 2025 +0200

    ci: update integration test paths to reflect new directory structure

commit 67ce9da156dccded23eb2b9b9a8a34c835d7f27b
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 15:09:21 2025 +0200

    backend: replace storage service with RoomRepository for room management

commit 25dcd057d6597910fa4992dc45934e85edbd6a3e
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 15:07:55 2025 +0200

    backend: implement RoomRepository to manage MeetRoom objects in MongoDB

commit 42e6036741871b964d9d7a644210eedeaf1ad543
Author: juancarmore <juancar_more2@hotmail.com>
Date:   Fri Oct 24 15:05:31 2025 +0200

    backend: add mongoose dependecy and create MongoDBService
2025-11-05 17:48:38 +01:00
Carlos Santos
684d575c08 frontend: Fixed error with basic creation room 2025-11-05 17:43:47 +01:00
Carlos Santos
7dd368476e Merge branch 'e2ee_feature' 2025-11-05 17:11:51 +01:00
Carlos Santos
fd905286a6 typings: add E2EE configuration interface to MeetRoomConfig
frontend: add End-to-End Encryption (E2EE)

- Updated meeting lobby and room wizard components to handle E2EE settings.
- Added E2EE configuration options in the room wizard and lobby services.
- Implemented validation for E2EE key input in participant forms.
- Enhanced UI to reflect E2EE restrictions on recording and streaming.
- Added animations for E2EE warning and info sections.

backend: Added E2EE configuration and middleware

backend: Added e2ee configuration property to openapi

Enables E2EE functionality

Configures the application to support end-to-end encryption (E2EE).

Copies the necessary worker script to the assets folder.

Passes the E2EE key to the meeting component.

Adds a script to remove node_modules and dist folder.

frontend: Add E2EE UI tests and configuration options

webcomponent: Ensure cleanup of test environment after moderation tests

frontend: Update E2EE description and restrictions

webcomponent: Enhance E2EE UI tests by adding participant interactions and verifying visibility with correct keys

backend: Updated start recording example response
2025-11-05 17:11:30 +01:00
682 changed files with 31914 additions and 17677 deletions

View File

@ -141,8 +141,6 @@
**/*.mov
**/*.mkv
**/*.webm
**/*.mp3
**/*.wav
**/*.flac
# ====================================================

View File

@ -2,14 +2,14 @@ name: Backend Integration Tests
on:
push:
paths:
- 'backend/src/**'
- 'backend/package.json'
- 'backend/pnpm-lock.yaml'
- 'backend/tests/**'
- 'meet-ce/backend/src/**'
- 'meet-ce/backend/package.json'
- 'pnpm-lock.yaml'
- 'meet-ce/backend/tests/**'
- '.github/workflows/backend-integration-test.yaml'
pull_request:
paths:
- 'backend/src/**'
- 'meet-ce/backend/src/**'
workflow_dispatch:
inputs:
use-aws:
@ -22,7 +22,7 @@ on:
jobs:
build-components:
name: Build OpenVidu Components Angular
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
steps:
- name: Build Components
id: build
@ -33,26 +33,19 @@ jobs:
test-api:
name: ${{ matrix.test-name }}
needs: build-components
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
strategy:
fail-fast: false
matrix:
include:
- test-name: 'Rooms API Tests'
test-script: 'test:integration-backend-rooms'
- test-name: 'Room Management API Tests (Rooms, Meetings)'
test-script: 'test:integration-backend-room-management'
- test-name: 'Webhook Tests'
test-script: 'test:integration-backend-webhooks'
- test-name: 'Security API Tests'
test-script: 'test:integration-backend-security'
azure-container: 'openvidu-appdata-security'
- test-name: 'Global Config API Tests'
test-script: 'test:integration-backend-global-config'
- test-name: 'Participants API Tests'
test-script: 'test:integration-backend-participants'
- test-name: 'Meetings API Tests'
test-script: 'test:integration-backend-meetings'
- test-name: 'Users API Tests'
test-script: 'test:integration-backend-users'
- test-name: 'Auth & Security API Tests (Security, Auth, API Keys, Users)'
test-script: 'test:integration-backend-auth-security'
- test-name: 'Config & Analytics API Tests (Global Config, Analytics)'
test-script: 'test:integration-backend-config-analytics'
steps:
- name: Install LK CLI
run: curl -sSL https://get.livekit.io/cli | bash
@ -85,13 +78,11 @@ jobs:
with:
build_components_angular: 'true'
components_artifact_name: ${{ needs.build-components.outputs.artifact_name }}
env:
MEET_AZURE_CONTAINER_NAME: ${{ matrix.azure-container || '' }}
- name: Run tests
run: pnpm run ${{ matrix.test-script }}
env:
JEST_JUNIT_OUTPUT_DIR: './backend/reports/'
JEST_JUNIT_OUTPUT_DIR: './meet-ce/backend/reports/'
- name: Upload OpenVidu Meet logs
if: failure()
@ -115,7 +106,7 @@ jobs:
start-aws-runner-s3:
name: Prepare AWS runner (S3)
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
if: ${{ inputs.use-aws != 'false' }}
outputs:
label: ${{ steps.start-ec2-runner.outputs.label }}
@ -138,7 +129,7 @@ jobs:
start-aws-runner-abs:
name: Prepare AWS runner (ABS)
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
if: ${{ inputs.use-aws != 'false' }}
outputs:
label: ${{ steps.start-ec2-runner.outputs.label }}
@ -161,7 +152,7 @@ jobs:
start-aws-runner-gcs:
name: Prepare AWS runner (GCS)
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
if: ${{ inputs.use-aws != 'false' }}
outputs:
label: ${{ steps.start-ec2-runner.outputs.label }}
@ -190,7 +181,7 @@ jobs:
- start-aws-runner-gcs
- build-components
if: ${{ always() && (needs.start-aws-runner-s3.result == 'success' || needs.start-aws-runner-s3.result == 'skipped') && (needs.start-aws-runner-abs.result == 'success' || needs.start-aws-runner-abs.result == 'skipped') && (needs.start-aws-runner-gcs.result == 'success' || needs.start-aws-runner-gcs.result == 'skipped') }}
runs-on: ${{ (matrix.storage-provider == 's3' && needs.start-aws-runner-s3.outputs.label) || (matrix.storage-provider == 'abs' && needs.start-aws-runner-abs.outputs.label) || (matrix.storage-provider == 'gcs' && needs.start-aws-runner-gcs.outputs.label) || 'ov-actions-runner' }}
runs-on: ${{ (matrix.storage-provider == 's3' && needs.start-aws-runner-s3.outputs.label) || (matrix.storage-provider == 'abs' && needs.start-aws-runner-abs.outputs.label) || (matrix.storage-provider == 'gcs' && needs.start-aws-runner-gcs.outputs.label) || vars.LABEL_WORKER_SELFHOSTED }}
strategy:
fail-fast: false
matrix:
@ -292,7 +283,7 @@ jobs:
- name: Run tests
run: pnpm run test:integration-backend-recordings
env:
JEST_JUNIT_OUTPUT_DIR: './backend/reports/'
JEST_JUNIT_OUTPUT_DIR: './meet-ce/backend/reports/'
MEET_BLOB_STORAGE_MODE: ${{ matrix.storage-provider }}
# ABS variables
MEET_AZURE_ACCOUNT_NAME: ${{ matrix.storage-provider == 'abs' && vars.MEET_AZURE_ACCOUNT_NAME || '' }}
@ -315,7 +306,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: recordings-test-${{ matrix.storage-provider }}-openvidu-meet-logs
path: backend/meet_backend.log
path: meet_backend.log
retention-days: 2
- name: Clean up credentials
@ -335,7 +326,7 @@ jobs:
- start-aws-runner-abs
- start-aws-runner-gcs
- test-recordings
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
if: ${{ always() }}
strategy:
fail-fast: false
@ -359,7 +350,7 @@ jobs:
- build-components
- test-api
- test-recordings
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
if: ${{ always() }}
steps:
- name: Remove Artifact

View File

@ -7,7 +7,7 @@ on:
jobs:
unit-test:
name: Backend Unit Tests
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
steps:
- name: Setup Node.js
uses: actions/setup-node@v5

View File

@ -7,7 +7,7 @@ on:
jobs:
e2e-tests:
name: WebComponent E2E Tests
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
steps:
- name: Setup Node.js
uses: actions/setup-node@v5
@ -17,6 +17,8 @@ jobs:
uses: pnpm/action-setup@v4
with:
version: 10.18.3
- name: Install LK CLI
run: curl -sSL https://get.livekit.io/cli | bash
- name: Setup OpenVidu Local Deployment
uses: OpenVidu/actions/start-openvidu-local-deployment@main
with:
@ -56,7 +58,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: room-test-results
path: frontend/webcomponent/test-results/
path: meet-ce/frontend/webcomponent/test-results/
retention-days: 2
- name: Upload TestApp logs on failure
@ -64,7 +66,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: room-test-testapp-logs
path: testapp/testapp.log
path: testapp.log
retention-days: 2
- name: Upload OpenVidu Meet logs on failure
@ -72,7 +74,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: room-test-openvidu-meet-logs
path: backend/meet_backend.log
path: meet_backend.log
retention-days: 2
- name: Clean up

View File

@ -7,7 +7,7 @@ on:
jobs:
unit-test:
name: WebComponent Unit Tests
runs-on: ov-actions-runner
runs-on: ${{ vars.LABEL_WORKER_SELFHOSTED }}
steps:
- name: Setup Node.js
uses: actions/setup-node@v5

2
.gitignore vendored
View File

@ -37,7 +37,7 @@ pnpm-debug.log*
**/**/test-results
**/**/public/
**/backend/public/
**/*/coverage
**/**/test-results

View File

@ -8,8 +8,8 @@ OpenVidu Meet is a fully featured video conferencing application built with Angu
2. [Prerequisites](#prerequisites)
3. [Getting Started](#getting-started)
4. [Development](#development)
- [Development Mode](#development-mode)
- [Manual Development Setup](#manual-development-setup)
- [Development Mode](#development-mode)
- [Manual Development Setup](#manual-development-setup)
5. [Building](#building)
6. [Testing](#testing)
7. [Documentation](#documentation)
@ -26,12 +26,12 @@ The OpenVidu Meet application is a monorepo managed with **pnpm workspaces** and
### Core Components
- **Frontend** (`frontend/`): Angular 20 application providing the user interface
- **shared-meet-components**: Reusable Angular library with shared components for administration and preferences
- Integrates [openvidu-components-angular](https://github.com/OpenVidu/openvidu/tree/master/openvidu-components-angular) for core video conferencing functionality
- **shared-meet-components**: Reusable Angular library with shared components for administration and preferences
- Integrates [openvidu-components-angular](https://github.com/OpenVidu/openvidu/tree/master/openvidu-components-angular) for core video conferencing functionality
- **Backend** (`backend/`): Node.js/TypeScript REST API server
- Manages rooms, participants, recordings, and authentication
- Serves the compiled frontend in production
- Manages rooms, participants, recordings, and authentication
- Serves the compiled frontend in production
- **Typings** (`typings/`): Shared TypeScript type definitions used across frontend and backend
@ -46,10 +46,9 @@ Before starting, ensure you have the following installed:
- **Node.js**: Version 22 or higher
- **pnpm**: Package manager (will be installed automatically by meet.sh if missing)
- **LiveKit**: For local testing (optional)
```bash
curl -sSL https://get.livekit.io/cli | bash
```
```bash
curl -sSL https://get.livekit.io/cli | bash
```
## Getting Started
@ -82,7 +81,7 @@ cd openvidu-meet
Then, the application will be available at [http://localhost:6080](http://localhost:6080).
> **Note:** Livereload is also available at [http://localhost:5080](http://localhost:5080).
> **Note:** Livereload is also available at [http://localhost:6081](http://localhost:6081).
## Development
@ -95,6 +94,7 @@ The recommended way to develop is using the integrated development mode that wat
```
This command starts concurrent watchers for:
- **openvidu-components-angular**: Core Angular components library
- **Typings**: Shared type definitions with automatic sync
- **Backend**: Node.js server with nodemon auto-restart
@ -103,6 +103,7 @@ This command starts concurrent watchers for:
> [!NOTE]
> The backend uses `backend/.env.development` for environment variables during development. Configure your LiveKit credentials there:
>
> ```env
> LIVEKIT_URL=ws://localhost:7880
> LIVEKIT_API_KEY=your-api-key
@ -170,6 +171,7 @@ The `meet.sh` script supports flags to optimize CI/CD pipelines:
```
**Available flags:**
- `--skip-install`: Skip dependency installation
- `--skip-build`: Skip build steps
- `--skip-typings`: Skip typings build (use when already built)
@ -225,8 +227,9 @@ The test app will be available at [http://localhost:5080](http://localhost:5080)
```
Documentation files will be generated in:
- **Webcomponent**: `docs/webcomponent-*.md` (events, commands, attributes)
- **REST API**: `backend/public/openapi/public.html`
- **REST API**: `meet-ce/backend/public/openapi/public.html`
If you specify an output directory, the documentation will be copied there.
@ -289,35 +292,41 @@ openvidu-meet/
│ ├── src/
│ │ ├── api-key.ts
│ │ ├── auth-config.ts
│ │ ├── participant.ts
│ │ ├── event.model.ts
│ │ ├── room.ts
│ │ └── ...
│ └── package.json
├── frontend/ # Angular frontend application
├── frontend/ # Angular frontend application
│ ├── src/ # Main application source
│ ├── projects/
│ │ └── shared-meet-components/ # Reusable Angular library
│ └── webcomponent/ # Web component build
├── backend/ # Node.js/Express backend
├── backend/ # Node.js/Express backend
│ ├── src/
│ │ ├── config/ # Configuration files
│ │ ├── controllers/ # REST API controllers
│ │ ├── services/ # Business logic
│ │ ├── helpers/ # Helper functions
│ │ ├── middleware/ # Express middleware
│ │ ├── migrations/ # Database migration scripts
│ │ ├── models/ # Domain models
│ │ ├── repositories/ # Database interaction
│ │ ├── routes/ # API route definitions
│ │ ├── services/ # Business logic
│ │ ├── utils/ # Utility functions
│ │ └── environment.ts # Environment configuration
│ ├── openapi/ # OpenAPI specifications
│ └── public/ # Static files (includes built frontend)
├── testapp/ # Testing application
├── testapp/ # Testing application
│ ├── src/
│ └── public/
├── docker/ # Docker build files
├── docker/ # Docker build files
│ └── create_image.sh
├── docs/ # Generated documentation
├── scripts/ # Build and utility scripts
├── docs/ # Generated documentation
├── scripts/ # Build and utility scripts
└── openvidu-meet-pro/ # Professional Edition (separate license)
```
@ -412,6 +421,7 @@ Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for detai
- [OpenVidu Website](https://openvidu.io/)
- [OpenVidu Meet](https://openvidu.io/latest/meet/)
---
For questions and support, visit our [community forum](https://openvidu.discourse.group/).

View File

@ -1,8 +1,9 @@
{
"jest.jestCommandLine": "node --experimental-vm-modules ../../node_modules/.bin/jest",
"jest.jestCommandLine": "node --experimental-vm-modules ../../node_modules/.bin/jest --config jest.integration.config.mjs",
"jest.rootPath": "backend",
"jest.nodeEnv": {
"NODE_OPTIONS": "--experimental-vm-modules"
},
"jest.runMode": "on-demand"
}

View File

@ -1,6 +1,7 @@
USE_HTTPS=false
MEET_LOG_LEVEL=verbose
MEET_LOG_LEVEL=debug
SERVER_CORS_ORIGIN=*
MEET_INITIAL_API_KEY=meet-api-key
MEET_INITIAL_WEBHOOK_ENABLED=true
MEET_INITIAL_WEBHOOK_URL=http://localhost:5080/webhook
MEET_INITIAL_WEBHOOK_URL=http://localhost:5080/webhook
MEETING_DEPARTURE_TIMEOUT=1s

View File

@ -23,9 +23,26 @@ pnpm install
pnpm run build:prod
```
## Storage Structure
## Storage Architecture
The OpenVidu Meet backend uses an S3 bucket to store all application data, including rooms, recordings, user information, and system config. The bucket follows a hierarchical structure organized as follows:
The OpenVidu Meet backend uses **MongoDB** as its primary data storage system for all application data, including rooms, recordings, user information, API keys, and system configuration.
### MongoDB Collections
The application manages the following MongoDB collections:
- **`meetglobalconfigs`**: System-wide configuration (singleton collection)
- **`meetusers`**: User accounts with authentication and roles
- **`meetapikeys`**: API keys for authentication
- **`meetrooms`**: Room configurations and metadata
- **`meetrecordings`**: Recording metadata and access information
- **`meetmigrations`**: Migration tracking for data and schema migrations
Each document in these collections includes a `schemaVersion` field for schema evolution tracking (internal use only, not exposed via API).
### Legacy Storage (S3/ABS/GCS)
Prior versions of OpenVidu Meet used cloud object storage (S3, Azure Blob Storage, or Google Cloud Storage) for data persistence. The legacy storage structure followed this organization:
### Bucket Structure
@ -109,6 +126,45 @@ Where:
This naming convention ensures uniqueness and provides traceability between the recording file, its metadata, and the originating room session.
---
## Data Migration System
OpenVidu Meet includes a comprehensive migration system to handle data persistence changes and schema evolution.
### Legacy Storage to MongoDB Migration
On first startup, the application automatically migrates existing data from legacy storage (S3/Azure Blob Storage/Google Cloud Storage) to MongoDB. This migration:
- **Runs automatically** on application startup if legacy storage is configured
- **Is idempotent** - safe to run multiple times (skips already migrated data)
- **Preserves all data** - rooms, recordings, users, API keys, and global config
- **Tracks progress** in the `meetmigrations` collection
- **Is HA-safe** using distributed locks to prevent concurrent migrations
### MongoDB Schema Migration System
The application uses a schema versioning system to safely evolve MongoDB document structures over time. This system:
- **Runs automatically** at startup before accepting requests
- **Tracks schema versions** via the `schemaVersion` field in each document
- **Supports forward-only migrations** (v1 → v2 → v3)
- **Processes in batches** for efficiency with large collections
- **Is HA-safe** using distributed locks
- **Validates before execution** to ensure migration safety
Schema migrations handle scenarios like:
- Adding new required fields with default values
- Removing deprecated fields
- Renaming or restructuring fields
- Data type transformations
For detailed information about creating and managing schema migrations, see:
📖 **[Schema Migration Documentation](./src/migrations/README.md)**
---
## Recordings
The recording feature is based on the following key concepts:
@ -140,10 +196,10 @@ flowchart TD
L -- "Error (recording not found, already stopped,\nor unknown error)" --> O["Reject Request"] --> J
```
4. **Failure handling**:
3. **Failure handling**:
If an OpenVidu instance crashes while a recording is active, the lock remains in place. This scenario can block subsequent recording attempts if the lock is not released promptly. To mitigate this issue, a lock garbage collector is implemented to periodically clean up orphaned locks.
The garbage collector runs when the OpenVidu deployment starts, and then every 30 minutes.
The garbage collector runs when the OpenVidu deployment starts, and then every 15 minutes.
```mermaid
graph TD;
@ -169,46 +225,53 @@ graph TD;
L --> M
M -->|More rooms| E
M -->|No more rooms| N[Process completed]
```
5. **Stale recordings cleanup**:
To handle recordings that become stale due to network issues, LiveKit or Egress crashes, or other unexpected situations, a separate cleanup process runs every 15 minutes to identify and abort recordings that haven't been updated within a configured threshold (5 minutes by default).
4. **Stale recordings cleanup**:
To handle recordings that become stale due to network issues, LiveKit or Egress crashes, or other unexpected situations, a separate cleanup process runs every 14 minutes to identify and abort recordings that haven't been updated within a configured threshold (5 minutes by default).
```mermaid
graph TD;
A[Initiate stale recordings cleanup] --> B[Get all in-progress recordings from LiveKit]
A[Initiate stale recordings cleanup] --> B[Get all active recordings from database<br/>ACTIVE or ENDING status]
B -->|Error| C[Log error and exit]
B -->|No recordings found| D[Log and exit]
B -->|Recordings found| E[Process recordings in batches of 10]
E --> F[For each recording in batch]
F --> G[Extract recording ID and updatedAt]
G --> H[Get recording status from storage]
F --> G[Extract recordingId, roomId and egressId]
G --> H[Check for corresponding egress in LiveKit]
H -->|Recording already ABORTED| I[Mark as already processed]
H -->|Recording active| J[Check if updatedAt exists]
H -->|No egress found| I[Recording is stale - no egress exists]
H -->|Egress exists| J[Extract updatedAt from egress]
J -->|No updatedAt timestamp| K[Keep as fresh - log warning]
J -->|Has updatedAt| L[Calculate if stale]
I --> K[Update status to ABORTED in database]
K --> L[Log successful abort - no egress found]
L -->|Still fresh| M[Log as fresh]
L -->|Is stale| N[Abort stale recording]
J -->|No updatedAt timestamp| M[Keep as fresh - log warning]
J -->|Has updatedAt| N[Check if recording age is stale]
N --> O[Update status to ABORTED in storage]
N --> P[Stop egress in LiveKit]
O --> Q[Log successful abort]
P --> Q
N -->|Age not stale| O[Log as fresh]
N -->|Age is stale| P[Check room existence]
I --> R[Continue to next recording]
K --> R
M --> R
Q --> R
P -->|Room does not exist| Q[Mark as stale]
P -->|Room exists| R[Check if room has participants]
R -->|More recordings in batch| F
R -->|Batch complete| S[Process next batch]
S -->|More batches| E
S -->|All batches processed| T[Log completion metrics]
T --> U[Process completed]
R -->|No participants| Q
R -->|Has participants| O
Q --> S[Update status to ABORTED in database]
Q --> T[Stop egress in LiveKit]
S --> U[Log successful abort]
T --> U
L --> V[Continue to next recording]
M --> V
O --> V
U --> V
V -->|More recordings in batch| F
V -->|Batch complete| W[Process next batch]
W -->|More batches| E
W -->|All batches processed| X[Log completion metrics]
X --> Y[Process completed]
```

View File

@ -1,9 +1,15 @@
export * from './src/routes/index.js';
export * from './src/controllers/index.js';
export * from './src/services/index.js';
export * from './src/models/index.js';
export * from './src/helpers/index.js';
// Main entry point for @openvidu-meet/backend package
export * from './src/config/internal-config.js';
export * from './src/environment.js';
export * from './src/server.js';
// Export other modules as needed
export * from './src/config/index.js';
export * from './src/controllers/index.js';
export * from './src/helpers/index.js';
export * from './src/middlewares/index.js';
export * from './src/models/index.js';
export * from './src/routes/index.js';
export * from './src/services/index.js';
export * from './src/utils/index.js';

View File

@ -15,16 +15,19 @@ const jestConfig = {
'^(\\.{1,2}/.*)\\.js$': '$1' // Allow importing js files and resolving to ts files
},
transform: {
'^.+\\.tsx?$': ['ts-jest', {
tsconfig: {
module: 'esnext',
moduleResolution: 'node16',
esModuleInterop: true,
allowSyntheticDefaultImports: true,
isolatedModules: true
},
useESM: true
}]
'^.+\\.tsx?$': [
'ts-jest',
{
tsconfig: {
module: 'esnext',
moduleResolution: 'node16',
esModuleInterop: true,
allowSyntheticDefaultImports: true,
isolatedModules: true
},
useESM: true
}
]
}
};

View File

@ -0,0 +1,12 @@
import baseConfig from './jest.config.mjs';
const integrationConfig = {
...baseConfig,
runInBand: true,
forceExit: true,
detectOpenHandles: true,
testMatch: ['**/tests/integration/**/*.(spec|test).ts'],
};
export default integrationConfig;

View File

@ -1,6 +0,0 @@
description: >
The cookie containing the access token.
This cookie is used to authenticate the user in subsequent requests.
schema:
type: string
example: 'OvMeetAccessToken=token_123456; Path=/; HttpOnly; SameSite=Strict'

View File

@ -1,6 +0,0 @@
description: >
The cookie containing the participant token.
This cookie is used to authenticate the participant in the room.
schema:
type: string
example: 'OvMeetParticipantToken=token_123456; Path=/; HttpOnly; SameSite=Strict'

View File

@ -1,6 +0,0 @@
description: >
The cookie containing the recording token.
This cookie is used to access the recordings in a room.
schema:
type: string
example: 'OvMeetRecordingToken=token_123456; Path=/; HttpOnly; SameSite=Strict'

View File

@ -1,6 +0,0 @@
description: >
The cookie containing the refresh token.
This cookie is used to refresh the access token when it expires.
schema:
type: string
example: 'OvMeetRefreshToken=token_123456; Path=/meet/internal-api/v1/auth; HttpOnly; SameSite=Strict'

View File

@ -1,7 +0,0 @@
name: participantIdentity
in: path
required: true
description: The identity of the participant.
schema:
type: string
example: 'Alice'

View File

@ -1,6 +1,6 @@
name: secret
in: path
required: true
description: The secret value from the room URL used to connect to the room.
description: The secret value from the room URL used to access the room.
schema:
type: string

View File

@ -1,12 +0,0 @@
name: x-participant-role
in: header
description: |
The role of the participant in the meeting. It can be one of the following values:
- `moderator`: Can manage the room and its participants.
- `speaker`: Can publish media streams to the room.
This is required to distinguish roles when multiple are present in the participant token
required: true
schema:
type: string
enum: ['moderator', 'speaker']

View File

@ -1,12 +1,7 @@
name: status
in: query
required: false
description: |
Filter recordings by their status.
You can provide multiple statuses as a comma-separated list (e.g., `status=active,failed`).
> ⚠️ **Note:** Using this filter may impact performance for large datasets.
description: Filter recordings by their status.
schema:
type: string
enum:

View File

@ -2,7 +2,8 @@ name: roomName
in: query
required: false
description: >
The name of the room.
Filter rooms by name. The search is case-insensitive and matches rooms that contain the specified text.
For example, 'room' will match 'MyRoom', 'room123', and 'Conference Room'.
schema:
type: string
example: 'room'

View File

@ -0,0 +1,10 @@
name: status
in: query
required: false
description: Filter rooms by their status.
schema:
type: string
enum:
- open
- active_meeting
- closed

View File

@ -0,0 +1,6 @@
name: sortField
in: query
required: false
description: The field by which to sort the results.
schema:
type: string

View File

@ -0,0 +1,9 @@
name: sortOrder
in: query
required: false
description: The order in which to sort the results. Use "asc" for ascending order and "desc" for descending order.
schema:
type: string
enum:
- asc
- desc

View File

@ -0,0 +1,6 @@
description: Create AI assistant activation request
required: true
content:
application/json:
schema:
$ref: '../../schemas/internal/ai-assistant-create-request.yaml'

View File

@ -1,6 +0,0 @@
description: Participant details
required: true
content:
application/json:
schema:
$ref: '../../schemas/internal/meet-participant-options.yaml'

View File

@ -0,0 +1,6 @@
description: Room member token options
required: true
content:
application/json:
schema:
$ref: '../../schemas/internal/room-member-token-options.yaml'

View File

@ -1,11 +0,0 @@
description: Room to record
required: true
content:
application/json:
schema:
type: object
properties:
roomId:
type: string
description: The unique identifier of the room to record.
example: 'room-123'

View File

@ -0,0 +1,35 @@
description: Room to record
required: true
content:
application/json:
schema:
type: object
properties:
roomId:
type: string
description: The unique identifier of the room to record.
example: 'room-123'
config:
type: object
description: |
Optional configuration to override the room's recording configuration for this specific recording.
If not provided, the recording will use the configuration defined in the room's config.
properties:
layout:
type: string
enum:
- grid
- speaker
- single-speaker
example: speaker
description: |
Defines the layout of the recording. This will override the room's default recording layout.
Options are:
- `grid`: All participants are shown in a grid layout.
- `speaker`: The active speaker is shown prominently, with other participants in smaller thumbnails.
- `single-speaker`: Only the active speaker is shown in the recording.
encoding:
description: Defines the encoding settings for the recording. This will override the room's default recording encoding.
oneOf:
- $ref: '../schemas/meet-room-config.yaml#/MeetRecordingEncodingPreset'
- $ref: '../schemas/meet-room-config.yaml#/MeetRecordingEncodingOptions'

View File

@ -11,6 +11,7 @@ content:
chat:
enabled: true
recording:
enabled: false
enabled: true
encoding: H264_720P_30
virtualBackground:
enabled: true

View File

@ -0,0 +1,17 @@
description: New room status
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum:
- open
- active_meeting
- closed
example: closed
description: |
The new status of the room. Options are:
- open: The room will be open for new participants to join.
- closed: The room will be closed to new participants.

View File

@ -2,7 +2,7 @@ description: Conflict — The recording cannot be started due to resource state
content:
application/json:
schema:
$ref: '../../schemas/error.yaml'
$ref: '../schemas/error.yaml'
examples:
already_recording:
summary: Room is already being recorded

View File

@ -2,7 +2,7 @@ description: Conflict — The recording is starting or already stopped
content:
application/json:
schema:
$ref: '../../schemas/error.yaml'
$ref: '../schemas/error.yaml'
examples:
starting_recording:
summary: Recording is starting

View File

@ -0,0 +1,8 @@
description: Room not found
content:
application/json:
schema:
$ref: '../schemas/error.yaml'
example:
error: 'Room Error'
message: 'Room "room_123" has an active meeting'

View File

@ -2,7 +2,7 @@ description: Service Unavailable — The recording service is unavailable
content:
application/json:
schema:
$ref: '../../schemas/error.yaml'
$ref: '../schemas/error.yaml'
examples:
starting_timeout:
summary: Recording service timed out

View File

@ -1,4 +1,4 @@
description: Forbidden — Insufficient permissions
description: Forbidden - Insufficient Permissions
content:
application/json:
schema:

View File

@ -0,0 +1,16 @@
description: Forbidden
content:
application/json:
schema:
$ref: '../schemas/error.yaml'
examples:
forbidden_error:
summary: Forbidden Error Example
value:
error: Authorization Error
message: 'Insufficient permissions to access this resource'
recording_not_allowed:
summary: Recording Not Allowed in Room Example
value:
error: Recording Error
message: 'Recording is disabled for room room-123'

View File

@ -1,8 +0,0 @@
description: Invalid participant role provided
content:
application/json:
schema:
$ref: '../../schemas/error.yaml'
example:
error: Participant Error
message: 'No valid participant role provided'

View File

@ -1,8 +0,0 @@
description: Conflict — The participant already exists in the room
content:
application/json:
schema:
$ref: '../../schemas/error.yaml'
example:
error: 'Participant Error'
message: 'Participant "Alice" already exists in room "room_123"'

View File

@ -1,8 +0,0 @@
description: Room metadata not found
content:
application/json:
schema:
$ref: '../../schemas/error.yaml'
example:
error: 'Room Error'
message: 'Room metadata for "room_123" not found. Room "room_123" does not exist or has no recordings associated'

View File

@ -0,0 +1,5 @@
description: Successfully created or reused AI assistant activation
content:
application/json:
schema:
$ref: '../../schemas/internal/ai-assistant-create-response.yaml'

View File

@ -1,13 +0,0 @@
description: Successfully generated the participant token
# headers:
# Set-Cookie:
# $ref: '../../headers/set-cookie-participant-token.yaml'
content:
application/json:
schema:
type: object
properties:
token:
type: string
description: >
The token to authenticate the participant.

View File

@ -1,13 +0,0 @@
description: Successfully generated the recording token
# headers:
# Set-Cookie:
# $ref: '../../headers/set-cookie-recording-token.yaml'
content:
application/json:
schema:
type: object
properties:
token:
type: string
description: >
The token to access the recordings in the specified OpenVidu Meet room.

View File

@ -0,0 +1,10 @@
description: Successfully generated the room member token
content:
application/json:
schema:
type: object
properties:
token:
type: string
description: >
The token to authenticate the user to access the room and its resources.

View File

@ -0,0 +1,5 @@
description: Analytics data retrieved successfully
content:
application/json:
schema:
$ref: '../../schemas/internal/meet-analytics.yaml'

View File

@ -0,0 +1,5 @@
description: Successfully retrieved captions config
content:
application/json:
schema:
$ref: '../../schemas/internal/global-captions-config.yaml'

View File

@ -2,4 +2,4 @@ description: Successfully retrieved user profile
content:
application/json:
schema:
$ref: '../../schemas/internal/user.yaml'
$ref: '../../schemas/internal/meet-user.yaml'

View File

@ -2,4 +2,4 @@ description: Successfully retrieved the room role and associated permissions
content:
application/json:
schema:
$ref: '../../schemas/internal/meet-room-role-permissions.yaml'
$ref: '../../schemas/internal/room-member-role-permissions.yaml'

View File

@ -4,7 +4,7 @@ content:
schema:
type: array
items:
$ref: '../../schemas/internal/meet-room-role-permissions.yaml'
$ref: '../../schemas/internal/room-member-role-permissions.yaml'
example:
- role: 'moderator'
permissions:
@ -17,6 +17,8 @@ content:
canUpdateOwnMetadata: true
openvidu:
canRecord: true
canRetrieveRecordings: true
canDeleteRecordings: true
canChat: true
canChangeVirtualBackground: true
- role: 'speaker'
@ -30,5 +32,7 @@ content:
canUpdateOwnMetadata: true
openvidu:
canRecord: false
canRetrieveRecordings: true
canDeleteRecordings: false
canChat: true
canChangeVirtualBackground: true

View File

@ -6,4 +6,4 @@ content:
properties:
message:
type: string
example: Participant 'Alice' kicked successfully from room 'room-123'
example: Participant 'Alice' kicked successfully from meeting in room 'room-123'

View File

@ -1,7 +1,4 @@
description: Successfully refreshed the access token
# headers:
# Set-Cookie:
# $ref: '../../headers/set-cookie-access-token.yaml'
content:
application/json:
schema:

View File

@ -1,9 +1,4 @@
description: Successfully logged in
# headers:
# Set-Cookie:
# $ref: '../../headers/set-cookie-access-token.yaml'
# Set-Cookie*:
# $ref: '../../headers/set-cookie-refresh-token.yaml'
content:
application/json:
schema:

View File

@ -1,11 +1,4 @@
description: Successfully logged out
# headers:
# Set-Cookie:
# description: >
# Clears the access and refresh token cookie.
# schema:
# type: string
# example: 'OvMeetAccessToken=; Path=/; HttpOnly; SameSite=Strict'
content:
application/json:
schema:

View File

@ -11,6 +11,7 @@ content:
roomId: 'room-123'
roomName: 'room'
status: 'complete'
layout: 'grid'
filename: 'room-123--XX445.mp4'
startDate: 1600000000000
endDate: 1600000003600
@ -25,5 +26,6 @@ content:
roomId: 'room-456'
roomName: 'room'
status: 'active'
layout: 'grid'
filename: 'room-456--QR789.mp4'
startDate: 1682500000000

View File

@ -19,6 +19,7 @@ content:
roomId: 'room-123'
roomName: 'room'
status: 'active'
layout: 'grid'
filename: 'room-123--XX445.mp4'
startDate: 1620000000000
endDate: 1620000003600
@ -29,6 +30,7 @@ content:
roomId: 'room-456'
roomName: 'room'
status: 'complete'
layout: 'grid'
filename: 'room-456--XX678.mp4'
startDate: 1625000000000
endDate: 1625000007200

View File

@ -19,8 +19,15 @@ content:
enabled: true
recording:
enabled: false
layout: grid
encoding: H264_720P_30
allowAccessTo: admin_moderator_speaker
virtualBackground:
enabled: true
e2ee:
enabled: false
captions:
enabled: true
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
status: open
@ -43,8 +50,21 @@ content:
enabled: true
recording:
enabled: false
layout: grid
encoding:
video:
width: 1920
height: 1080
framerate: 30
codec: H264_MAIN
audio:
codec: OPUS
bitrate: 128
allowAccessTo: admin_moderator_speaker
virtualBackground:
enabled: true
e2ee:
enabled: false
fields=moderatorUrl,speakerUrl:
summary: Response containing only moderator and speaker URLs

View File

@ -28,8 +28,15 @@ content:
enabled: true
recording:
enabled: false
layout: grid
encoding: H264_720P_30
allowAccessTo: admin_moderator_speaker
virtualBackground:
enabled: true
e2ee:
enabled: false
captions:
enabled: true
moderatorUrl: 'http://localhost:6080/room/room-123?secret=123456'
speakerUrl: 'http://localhost:6080/room/room-123?secret=654321'
status: open
@ -46,8 +53,21 @@ content:
enabled: false
recording:
enabled: true
layout: grid
encoding:
video:
width: 1280
height: 720
framerate: 60
codec: H264_HIGH
audio:
codec: AAC
bitrate: 192
allowAccessTo: admin_moderator_speaker
virtualBackground:
enabled: false
e2ee:
enabled: false
moderatorUrl: 'http://localhost:6080/room/room-456?secret=789012'
speakerUrl: 'http://localhost:6080/room/room-456?secret=210987'
status: open
@ -80,6 +100,8 @@ content:
enabled: false
virtualBackground:
enabled: true
e2ee:
enabled: false
- roomId: 'room-456'
roomName: 'room'
creationDate: 1620001000000
@ -91,6 +113,8 @@ content:
enabled: true
virtualBackground:
enabled: false
e2ee:
enabled: false
pagination:
isTruncated: true
nextPageToken: 'abc123'

View File

@ -0,0 +1,10 @@
description: Success response for scheduling room closure
content:
application/json:
schema:
type: object
properties:
message:
type: string
example:
message: Room 'room-123' scheduled to be closed when the meeting ends

View File

@ -1,12 +0,0 @@
description: >
All specified rooms were marked for deletion (due to active participants)
and will be removed once all participants leave.
content:
application/json:
schema:
type: object
properties:
message:
type: string
example:
message: Rooms 'room-123, room-456' marked for deletion

View File

@ -2,12 +2,13 @@ description: Successfully created the OpenVidu Meet recording
content:
application/json:
schema:
$ref: '../../schemas/meet-recording.yaml'
$ref: '../schemas/meet-recording.yaml'
example:
recordingId: 'room-123--EG_XYZ--XX445'
roomId: 'room-123'
roomName: 'room'
status: 'active'
layout: 'speaker'
filename: 'room-123--XX445.mp4'
startDate: 1600000000000
headers:

View File

@ -8,12 +8,13 @@ headers:
content:
application/json:
schema:
$ref: '../../schemas/meet-recording.yaml'
$ref: '../schemas/meet-recording.yaml'
example:
recordingId: 'room-123--EG_XYZ--XX445'
roomId: 'room-123'
roomName: 'room'
status: 'ending'
layout: 'speaker'
filename: 'room-123--XX445.mp4'
startDate: 1600000000000
details: 'End reason: StopEgress API'

View File

@ -0,0 +1,10 @@
description: Success response for updating room status
content:
application/json:
schema:
type: object
properties:
message:
type: string
example:
message: Room 'room-123' closed successfully

View File

@ -0,0 +1,37 @@
type: object
required:
# - scope
- capabilities
properties:
# scope:
# type: object
# required:
# - resourceType
# - resourceIds
# properties:
# resourceType:
# type: string
# enum: ['meeting']
# description: Scope resource type where assistant will be activated.
# example: meeting
# resourceIds:
# type: array
# minItems: 1
# items:
# type: string
# minLength: 1
# description: List of target resource ids.
# example: ['meeting_123']
capabilities:
type: array
minItems: 1
items:
type: object
required:
- name
properties:
name:
type: string
enum: ['live_captions']
description: AI capability to activate.
example: live_captions

View File

@ -0,0 +1,14 @@
type: object
required:
- id
- status
properties:
id:
type: string
description: Identifier of the assistant activation.
example: asst_123
status:
type: string
enum: ['active']
description: Current assistant activation state.
example: active

View File

@ -0,0 +1,8 @@
type: object
properties:
enabled:
type: boolean
description: Indicates whether captions are enabled in the system
example: true
required:
- enabled

View File

@ -0,0 +1,24 @@
type: object
description: Usage analytics data for OpenVidu Meet
properties:
totalRooms:
type: integer
description: Total number of rooms created
example: 42
activeRooms:
type: integer
description: Number of rooms currently with an active meeting
example: 3
totalRecordings:
type: integer
description: Total number of recordings created
example: 128
completeRecordings:
type: integer
description: Number of recordings that are complete and playable
example: 125
required:
- totalRooms
- activeRooms
- totalRecordings
- completeRecordings

View File

@ -1,21 +0,0 @@
type: object
required:
- roomId
- secret
properties:
roomId:
type: string
description: The unique identifier of the room where the participant will join.
example: 'room-123'
secret:
type: string
description: The secret token from the room Url
example: 'abc123456'
participantName:
type: string
description: The name of the participant.
example: 'Alice'
participantIdentity:
type: string
description: The unique identity of the participant.
example: 'Alice'

View File

@ -4,10 +4,10 @@ properties:
type: string
enum: ['moderator', 'speaker']
description: |
A role that a participant can have in a room.
The role determines the permissions of the participant in the room.
- `moderator`: Can manage the room and its participants.
- `speaker`: Can publish media streams to the room.
A role that a user can have as a member of a room.
The role determines the permissions of the user in the room.
- `moderator`: Can manage the room resources and meeting participants.
- `speaker`: Can publish media streams to the meeting.
example: 'moderator'
permissions:
type: object
@ -50,15 +50,25 @@ properties:
canRecord:
type: boolean
description: >
Indicates whether the participant can record the room.
Indicates whether the user can record a meeting in the room.
example: true
canRetrieveRecordings:
type: boolean
description: >
Indicates whether the user can retrieve and play recordings of meetings in the room.
example: true
canDeleteRecordings:
type: boolean
description: >
Indicates whether the user can delete recordings of meetings in the room.
example: true
canChat:
type: boolean
description: >
Indicates whether the participant can send and receive chat messages in the room.
Indicates whether the user can send and receive chat messages in the room.
example: true
canChangeVirtualBackground:
type: boolean
description: >
Indicates whether the participant can change their own virtual background.
Indicates whether the user can change their own virtual background.
example: true

View File

@ -0,0 +1,20 @@
type: object
required:
- secret
properties:
secret:
type: string
description: A secret key for room access. Determines the member's role.
example: 'abc123456'
grantJoinMeetingPermission:
type: boolean
description: Whether to grant permission to join the meeting. If true, participantName must be provided.
example: true
participantName:
type: string
description: The name of the participant when joining the meeting. Required if `grantJoinMeetingPermission` is true and this is a new token (not a refresh).
example: 'Alice'
participantIdentity:
type: string
description: The identity of the participant in the meeting. Required when refreshing an existing token with meeting permissions.
example: 'Alice'

View File

@ -26,6 +26,10 @@ MeetRoomTheme:
minLength: 1
maxLength: 50
example: "Default Theme"
enabled:
type: boolean
description: Whether the theme is enabled
example: true
baseTheme:
$ref: '#/MeetRoomThemeMode'
description: Base theme mode (light or dark)
@ -51,6 +55,7 @@ MeetRoomTheme:
example: "#CCCCCC"
required:
- name
- enabled
- baseTheme
MeetRoomThemeMode:

View File

@ -22,6 +22,58 @@ properties:
enum: ['starting', 'active', 'ending', 'complete', 'failed', 'aborted', 'limit_reached']
example: 'active'
description: The status of the recording.
layout:
type: string
example: 'grid'
description: The layout of the recording.
encoding:
oneOf:
- type: string
enum: ['H264_720P_30', 'H264_720P_60', 'H264_1080P_30', 'H264_1080P_60', 'PORTRAIT_H264_720P_30', 'PORTRAIT_H264_720P_60', 'PORTRAIT_H264_1080P_30', 'PORTRAIT_H264_1080P_60']
description: Encoding preset
- type: object
properties:
video:
type: object
properties:
width:
type: integer
example: 1920
height:
type: integer
example: 1080
framerate:
type: integer
example: 30
codec:
type: string
enum: ['DEFAULT_VC', 'H264_BASELINE', 'H264_MAIN', 'H264_HIGH', 'VP8']
bitrate:
type: integer
example: 4500
keyFrameInterval:
type: number
example: 2
depth:
type: integer
example: 24
audio:
type: object
properties:
codec:
type: string
enum: ['DEFAULT_AC', 'OPUS', 'AAC', 'AC_MP3']
bitrate:
type: integer
example: 128
frequency:
type: integer
example: 48000
description: Advanced encoding options
description: |
The encoding configuration used for this recording.
Can be either a preset string or advanced encoding options.
example: 'H264_720P_30'
filename:
type: string
example: 'room-123--XX445.mp4'

View File

@ -10,6 +10,12 @@ MeetRoomConfig:
virtualBackground:
$ref: '#/MeetVirtualBackgroundConfig'
description: Config for virtual background in the room.
e2ee:
$ref: '#/MeetE2EEConfig'
description: Config for End-to-End Encryption (E2EE) in the room.
captions:
$ref: '#/MeetCaptionsConfig'
description: Config for live captions in the room.
MeetChatConfig:
type: object
properties:
@ -26,6 +32,29 @@ MeetRecordingConfig:
default: true
example: true
description: If true, the room will be allowed to record the video of the participants.
layout:
type: string
enum:
- grid
- speaker
- single-speaker
# - grid-light
# - speaker-light
# - single-speaker-light
default: grid
example: grid
description: |
Defines the layout of the recording. Options are:
- `grid`: All participants are shown in a grid layout.
- `speaker`: The active speaker is shown prominently, with other participants in smaller thumbnails.
- `single-speaker`: Only the active speaker is shown in the recording.
# - `grid-light`: Similar to `grid` but with a light-themed background.
# - `speaker-light`: Similar to `speaker` but with a light-themed background.
# - `single-speaker-light`: Similar to `single-speaker` but with a light-themed background.
encoding:
oneOf:
- $ref: '#/MeetRecordingEncodingPreset'
- $ref: '#/MeetRecordingEncodingOptions'
allowAccessTo:
type: string
enum:
@ -47,3 +76,184 @@ MeetVirtualBackgroundConfig:
default: true
example: true
description: If true, the room will be allowed to use virtual background.
MeetE2EEConfig:
type: object
properties:
enabled:
type: boolean
default: false
example: false
description: >
If true, the room will have End-to-End Encryption (E2EE) enabled.<br/>
This ensures that the media streams are encrypted from the sender to the receiver, providing enhanced privacy and security for the participants.<br/>
**Enabling E2EE will disable the recording feature for the room**.
MeetCaptionsConfig:
type: object
properties:
enabled:
type: boolean
default: true
example: true
description: >
If true, the room will have live captions enabled.<br/>
This allows participants to see real-time captions of the all participants' speech during the meeting.<br/>
MeetRecordingEncodingPreset:
type: string
enum:
- H264_720P_30
- H264_720P_60
- H264_1080P_30
- H264_1080P_60
- PORTRAIT_H264_720P_30
- PORTRAIT_H264_720P_60
- PORTRAIT_H264_1080P_30
- PORTRAIT_H264_1080P_60
description: |
Predefined encoding presets for recordings. Each preset defines a combination of resolution, frame rate, and codec:
- `H264_720P_30`: 1280x720, 30fps, 3000kbps, H.264_MAIN / OPUS **(default)**
- `H264_720P_60`: 1280x720, 60fps, 4500kbps, H.264_MAIN / OPUS
- `H264_1080P_30`: 1920x1080, 30fps, 4500kbps, H.264_MAIN / OPUS
- `H264_1080P_60`: 1920x1080, 60fps, 6000kbps, H.264_MAIN / OPUS
- `PORTRAIT_H264_720P_30`: 720x1280, 30fps, 3000kbps, H.264_MAIN / OPUS
- `PORTRAIT_H264_720P_60`: 720x1280, 60fps, 4500kbps, H.264_MAIN / OPUS
- `PORTRAIT_H264_1080P_30`: 1080x1920, 30fps, 4500kbps, H.264_MAIN / OPUS
- `PORTRAIT_H264_1080P_60`: 1080x1920, 60fps, 6000kbps, H.264_MAIN / OPUS
example: H264_720P_30
MeetRecordingVideoCodec:
type: string
enum:
- DEFAULT_VC
- H264_BASELINE
- H264_MAIN
- H264_HIGH
- VP8
description: |
Video codec options for recording encoding:
- `DEFAULT_VC`: Use the default video codec (H.264_MAIN)
- `H264_BASELINE`: H.264 Baseline profile
- `H264_MAIN`: H.264 Main profile
- `H264_HIGH`: H.264 High profile
- `VP8`: VP8 codec
example: H264_MAIN
MeetRecordingAudioCodec:
type: string
enum:
- DEFAULT_AC
- OPUS
- AAC
- AC_MP3
description: |
Audio codec options for recording encoding:
- `DEFAULT_AC`: Use the default audio codec (OPUS)
- `OPUS`: Opus codec
- `AAC`: AAC codec
- `AC_MP3`: MP3 codec
example: OPUS
MeetRecordingVideoEncodingOptions:
type: object
required:
- width
- height
- framerate
- codec
- bitrate
- keyFrameInterval
- depth
properties:
width:
type: integer
minimum: 1
example: 1280
description: |
Video width in pixels
height:
type: integer
minimum: 1
example: 720
description: |
Video height in pixels
framerate:
type: integer
minimum: 1
example: 30
description: |
Frame rate in fps
codec:
$ref: '#/MeetRecordingVideoCodec'
description: |
Video codec
bitrate:
type: integer
minimum: 1
example: 4500
description: |
Video bitrate in kbps
keyframeInterval:
type: number
minimum: 0
example: 4
description: |
Keyframe interval in seconds
depth:
type: integer
minimum: 1
example: 24
description: |
Video depth (pixel format) in bits
description: |
Advanced video encoding options for recordings.
MeetRecordingAudioEncodingOptions:
type: object
required:
- codec
- bitrate
- frequency
properties:
codec:
$ref: '#/MeetRecordingAudioCodec'
description: |
Audio codec (required when audio is provided)
bitrate:
type: integer
minimum: 1
example: 128
description: |
Audio bitrate in kbps (required when audio is provided)
frequency:
type: integer
minimum: 1
example: 44100
description: |
Audio sample rate in Hz (required when audio is provided)
description: |
Advanced audio encoding options for recordings.
When audio encoding is provided, all fields are required.
MeetRecordingEncodingOptions:
type: object
required:
- video
- audio
properties:
video:
$ref: '#/MeetRecordingVideoEncodingOptions'
description: Video encoding configuration
audio:
$ref: '#/MeetRecordingAudioEncodingOptions'
description: Audio encoding configuration
description: |
Advanced encoding options for recordings.
Use this for fine-grained control over video and audio encoding parameters.
Both video and audio configurations are required when using advanced options.
For common scenarios, consider using encoding presets instead.
example:
video:
width: 1280
height: 720
framerate: 30
codec: H264_MAIN
bitrate: 3000
keyFrameInterval: 4
audio:
codec: OPUS
bitrate: 128
frequency: 44100

View File

@ -71,14 +71,14 @@ properties:
type: string
example: 'http://localhost:6080/room/room-123?secret=123456'
description: >
The URL for the moderator participants to join the room. The moderator role has special permissions to manage the
room and participants.
The URL for moderator room members to access the room. The moderator role has special permissions to manage the
room resources and meeting participants.
speakerUrl:
type: string
example: 'http://localhost:6080/room/room-123?secret=654321'
description: >
The URL for the speaker participants to join the room. The speaker role has permissions to publish audio and
video streams to the room.
The URL for speaker room members to access the room. The speaker role has permissions to publish audio and
video streams to the meeting.
status:
type: string
enum:

View File

@ -22,6 +22,11 @@ properties:
status:
type: string
description: The status of the recording.
example: active
layout:
type: string
description: The layout of the recording.
example: grid
filename:
type: string
description: The name of the recording file.

View File

@ -4,51 +4,21 @@ apiKeyHeader:
in: header
description: >
The API key to authenticate the request. This key is required to access the OpenVidu Meet API.
# accessTokenCookie:
# type: apiKey
# name: OvMeetAccessToken
# in: cookie
# description: >
# The JWT token to authenticate the request in case of consuming the API from the OpenVidu Meet frontend.
accessTokenHeader:
type: apiKey
name: Authorization
in: header
description: >
The JWT token to authenticate the request in case of consuming the API from the OpenVidu Meet frontend.
# refreshTokenCookie:
# type: apiKey
# name: OvMeetRefreshToken
# in: cookie
# description: >
# The JWT token to refresh the access token when it expires.
refreshTokenHeader:
type: apiKey
name: X-Refresh-Token
in: header
description: >
The JWT token to refresh the access token when it expires.
# participantTokenCookie:
# type: apiKey
# name: OvMeetParticipantToken
# in: cookie
# description: >
# The JWT token to authenticate the participant when entering the room.
participantTokenHeader:
roomMemberTokenHeader:
type: apiKey
name: X-Participant-Token
name: X-Room-Member-Token
in: header
description: >
The JWT token to authenticate the participant when entering the room.
# recordingTokenCookie:
# type: apiKey
# name: OvMeetRecordingToken
# in: cookie
# description: >
# The JWT token containing permissions to access the recordings in a room.
recordingTokenHeader:
type: apiKey
name: X-Recording-Token
in: header
description: >
The JWT token containing permissions to access the recordings in a room.
The JWT token to authenticate a room member when accessing room and its resources.

View File

@ -15,6 +15,8 @@ paths:
$ref: './paths/rooms.yaml#/~1rooms~1{roomId}'
/rooms/{roomId}/config:
$ref: './paths/rooms.yaml#/~1rooms~1{roomId}~1config'
/rooms/{roomId}/status:
$ref: './paths/rooms.yaml#/~1rooms~1{roomId}~1status'
/recordings:
$ref: './paths/recordings.yaml#/~1recordings'
/recordings/download:
@ -25,6 +27,8 @@ paths:
$ref: './paths/recordings.yaml#/~1recordings~1{recordingId}~1media'
/recordings/{recordingId}/url:
$ref: './paths/recordings.yaml#/~1recordings~1{recordingId}~1url'
/recordings/{recordingId}/stop:
$ref: './paths/recordings.yaml#/~1recordings~1{recordingId}~1stop'
components:
securitySchemes:
$ref: './components/security.yaml'
@ -37,7 +41,7 @@ components:
$ref: './components/schemas/meet-room-config.yaml#/MeetRoomConfig'
MeetRecording:
$ref: components/schemas/meet-recording.yaml
Error:
$ref: components/schemas/error.yaml
MeetWebhookEvent:
$ref: components/schemas/meet-webhook.yaml#/MeetWebhookEvent
Error:
$ref: components/schemas/error.yaml

View File

@ -14,8 +14,8 @@ paths:
$ref: './paths/internal/auth.yaml#/~1auth~1logout'
/auth/refresh:
$ref: './paths/internal/auth.yaml#/~1auth~1refresh'
/auth/api-keys:
$ref: './paths/internal/auth.yaml#/~1auth~1api-keys'
/api-keys:
$ref: './paths/internal/api-keys.yaml#/~1auth~1api-keys'
/users/profile:
$ref: './paths/internal/users.yaml#/~1users~1profile'
/users/change-password:
@ -28,33 +28,35 @@ paths:
$ref: './paths/internal/meet-global-config.yaml#/~1config~1security'
/config/rooms/appearance:
$ref: './paths/internal/meet-global-config.yaml#/~1config~1rooms~1appearance'
/rooms/{roomId}/recording-token:
$ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}~1recording-token'
/config/captions:
$ref: './paths/internal/meet-global-config.yaml#/~1config~1captions'
/rooms/{roomId}/token:
$ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}~1token'
/rooms/{roomId}/roles:
$ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}~1roles'
/rooms/{roomId}/roles/{secret}:
$ref: './paths/internal/rooms.yaml#/~1rooms~1{roomId}~1roles~1{secret}'
/recordings:
$ref: './paths/internal/recordings.yaml#/~1recordings'
/recordings/{recordingId}/stop:
$ref: './paths/internal/recordings.yaml#/~1recordings~1{recordingId}~1stop'
/participants/token:
$ref: './paths/internal/participants.yaml#/~1participants~1token'
/participants/token/refresh:
$ref: './paths/internal/participants.yaml#/~1participants~1token~1refresh'
/meetings/{roomId}:
$ref: './paths/internal/meetings.yaml#/~1meetings~1{roomId}'
/meetings/{roomId}/participants/{participantIdentity}:
$ref: './paths/internal/meetings.yaml#/~1meetings~1{roomId}~1participants~1{participantIdentity}'
/meetings/{roomId}/participants/{participantIdentity}/role:
$ref: './paths/internal/meetings.yaml#/~1meetings~1{roomId}~1participants~1{participantIdentity}~1role'
/ai/assistants:
$ref: './paths/internal/ai-assistant.yaml#/~1ai~1assistants'
/ai/assistants/{assistantId}:
$ref: './paths/internal/ai-assistant.yaml#/~1ai~1assistants~1{assistantId}'
/analytics:
$ref: './paths/internal/analytics.yaml#/~1analytics'
components:
securitySchemes:
$ref: components/security.yaml
schemas:
User:
$ref: components/schemas/internal/user.yaml
MeetApiKey:
$ref: components/schemas/internal/meet-api-key.yaml
MeetUser:
$ref: components/schemas/internal/meet-user.yaml
WebhooksConfig:
$ref: components/schemas/internal/webhooks-config.yaml
SecurityConfig:
@ -65,9 +67,15 @@ components:
$ref: components/schemas/meet-room-options.yaml
MeetRoomConfig:
$ref: components/schemas/meet-room-config.yaml#/MeetRoomConfig
MeetRoomRoleAndPermissions:
$ref: components/schemas/internal/meet-room-role-permissions.yaml
MeetRoomMemberRoleAndPermissions:
$ref: components/schemas/internal/room-member-role-permissions.yaml
MeetAnalytics:
$ref: components/schemas/internal/meet-analytics.yaml
MeetRecording:
$ref: components/schemas/meet-recording.yaml
AiAssistantCreateRequest:
$ref: components/schemas/internal/ai-assistant-create-request.yaml
AiAssistantCreateResponse:
$ref: components/schemas/internal/ai-assistant-create-response.yaml
Error:
$ref: components/schemas/error.yaml

View File

@ -0,0 +1,56 @@
/ai/assistants:
post:
operationId: createAiAssistant
summary: Create AI assistant
description: |
Activates AI assistance.
> Currently only meeting AI Assistand and `live_captions` capability is supported.
tags:
- Internal API - AI Assistants
security:
- roomMemberTokenHeader: []
requestBody:
$ref: '../../components/requestBodies/internal/create-ai-assistant-request.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-create-ai-assistant.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':
$ref: '../../components/responses/forbidden-error.yaml'
'422':
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
/ai/assistants/{assistantId}:
delete:
operationId: cancelAiAssistant
summary: Cancel AI assistant
description: |
Cancels AI assistant.
The assistant process (live_captions) is stopped only when the last participant cancels it.
tags:
- Internal API - AI Assistants
security:
- roomMemberTokenHeader: []
parameters:
- in: path
name: assistantId
required: true
schema:
type: string
minLength: 1
description: Identifier of the assistant activation returned by create operation.
example: asst_123
responses:
'204':
description: AI assistant canceled successfully.
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'422':
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'

View File

@ -0,0 +1,17 @@
/analytics:
get:
operationId: getAnalytics
summary: Get usage analytics
description: >
Retrieves usage analytics for OpenVidu Meet, including metrics for rooms and recordings.
tags:
- Internal API - Analytics
security:
- accessTokenHeader: []
responses:
'200':
$ref: '../../components/responses/internal/success-get-analytics.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'

View File

@ -0,0 +1,49 @@
/auth/api-keys:
post:
operationId: createApiKey
summary: Create a new API key
description: |
Creates a new API key, returning it in the response.
> **Note:** Only one API key can be created in the system.
> If an API key already exists, it will be replaced with the new one.
tags:
- Internal API - API Keys
security:
- accessTokenHeader: []
responses:
'201':
$ref: '../../components/responses/internal/success-create-api-key.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
get:
operationId: getApiKeys
summary: Get API keys
description: |
Retrieves the existing API keys.
> **Note:** Only one API key can exist in the system.
> If no API key exists, an empty array will be returned.
tags:
- Internal API - API Keys
security:
- accessTokenHeader: []
responses:
'200':
$ref: '../../components/responses/internal/success-get-api-keys.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
delete:
operationId: deleteApiKeys
summary: Delete API keys
description: >
Deletes the existing API keys.
tags:
- Internal API - API Keys
security:
- accessTokenHeader: []
responses:
'200':
$ref: '../../components/responses/internal/success-delete-api-key.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'

View File

@ -46,53 +46,3 @@
$ref: '../../components/responses/internal/error-invalid-refresh-token.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
/auth/api-keys:
post:
operationId: createApiKey
summary: Create a new API key
description: |
Creates a new API key, returning it in the response.
> **Note:** Only one API key can be created in the system.
> If an API key already exists, it will be replaced with the new one.
tags:
- Internal API - Authentication
security:
- accessTokenHeader: []
responses:
'201':
$ref: '../../components/responses/internal/success-create-api-key.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
get:
operationId: getApiKeys
summary: Get API keys
description: |
Retrieves the existing API keys.
> **Note:** Only one API key can exist in the system.
> If no API key exists, an empty array will be returned.
tags:
- Internal API - Authentication
security:
- accessTokenHeader: []
responses:
'200':
$ref: '../../components/responses/internal/success-get-api-keys.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
delete:
operationId: deleteApiKeys
summary: Delete API keys
description: >
Deletes the existing API keys.
tags:
- Internal API - Authentication
security:
- accessTokenHeader: []
responses:
'200':
$ref: '../../components/responses/internal/success-delete-api-key.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'

View File

@ -139,3 +139,20 @@
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
/config/captions:
get:
operationId: getCaptionsConfig
summary: Get captions config
description: >
Retrieves the captions configuration from the environment variable MEET_CAPTIONS_ENABLED.
This endpoint returns whether captions are enabled in the system.
tags:
- Internal API - Global Config
responses:
'200':
$ref: '../../components/responses/internal/success-get-captions-config.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'

View File

@ -9,15 +9,12 @@
tags:
- Internal API - Meetings
security:
- participantTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../../components/parameters/room-id-path.yaml'
- $ref: '../../components/parameters/internal/x-participant-role.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-end-meeting.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-participant-role.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':
@ -35,16 +32,12 @@
tags:
- Internal API - Meetings
security:
- participantTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../../components/parameters/room-id-path.yaml'
- $ref: '../../components/parameters/internal/participant-identity.yaml'
- $ref: '../../components/parameters/internal/x-participant-role.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-kick-participant.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-participant-role.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':
@ -62,18 +55,14 @@
tags:
- Internal API - Meetings
security:
- participantTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../../components/parameters/room-id-path.yaml'
- $ref: '../../components/parameters/internal/participant-identity.yaml'
- $ref: '../../components/parameters/internal/x-participant-role.yaml'
requestBody:
$ref: '../../components/requestBodies/internal/update-participant-role-request.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-update-participant-role.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-participant-role.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':

View File

@ -1,58 +0,0 @@
/participants/token:
post:
operationId: generateParticipantToken
summary: Generate token for participant
description: >
Generates a token for a participant to join an OpenVidu Meet room.
tags:
- Internal API - Participant
security:
- accessTokenHeader: []
requestBody:
$ref: '../../components/requestBodies/internal/participant-token-request.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-generate-participant-token.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-room-secret.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':
$ref: '../../components/responses/forbidden-error.yaml'
'404':
$ref: '../../components/responses/error-room-not-found.yaml'
'409':
$ref: '../../components/responses/internal/error-room-closed.yaml'
'422':
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
/participants/token/refresh:
post:
operationId: refreshParticipantToken
summary: Refresh token for participant
description: >
Refresh a token for a participant in an OpenVidu Meet room.
tags:
- Internal API - Participant
security:
- accessTokenHeader: []
requestBody:
$ref: '../../components/requestBodies/internal/participant-token-request.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-generate-participant-token.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-room-secret.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':
$ref: '../../components/responses/forbidden-error.yaml'
'404':
$ref: '../../components/responses/internal/error-room-participant-not-found.yaml'
'409':
$ref: '../../components/responses/internal/error-room-closed.yaml'
'422':
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'

View File

@ -1,65 +0,0 @@
/recordings:
post:
operationId: startRecording
summary: Start a recording
description: >
Start a new recording for an OpenVidu Meet room with the specified room ID.
tags:
- Internal API - Recordings
security:
- participantTokenHeader: []
parameters:
- $ref: '../../components/parameters/internal/x-participant-role.yaml'
requestBody:
$ref: '../../components/requestBodies/internal/start-recording-request.yaml'
responses:
'201':
$ref: '../../components/responses/internal/success-start-recording.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-participant-role.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':
$ref: '../../components/responses/forbidden-error.yaml'
'404':
$ref: '../../components/responses/error-room-not-found.yaml'
'409':
$ref: '../../components/responses/internal/error-recording-conflict.yaml'
'422':
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
'503':
$ref: '../../components/responses/internal/error-service-unavailable.yaml'
/recordings/{recordingId}/stop:
post:
operationId: stopRecording
summary: Stop a recording
description: |
Stops a recording with the specified recording ID.
> **Note:** The recording must be in an `active` state; otherwise, a 409 error is returned.
tags:
- Internal API - Recordings
security:
- participantTokenHeader: []
parameters:
- $ref: '../../components/parameters/recording-id.yaml'
- $ref: '../../components/parameters/internal/x-participant-role.yaml'
responses:
'202':
$ref: '../../components/responses/internal/success-stop-recording.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-participant-role.yaml'
'401':
$ref: '../../components/responses/unauthorized-error.yaml'
'403':
$ref: '../../components/responses/forbidden-error.yaml'
'404':
$ref: '../../components/responses/error-recording-not-found.yaml'
'409':
$ref: '../../components/responses/internal/error-recording-not-active.yaml'
'422':
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'

View File

@ -1,10 +1,9 @@
/rooms/{roomId}/recording-token:
/rooms/{roomId}/token:
post:
operationId: generateRecordingToken
summary: Generate recording token
operationId: generateRoomMemberToken
summary: Generate room member token
description: >
Generates a token with recording permissions for a specified OpenVidu Meet room.
This token can be used to access the recordings in a room.
Generates a token for a user to access an OpenVidu Meet room and its resources.
tags:
- Internal API - Rooms
security:
@ -12,10 +11,10 @@
parameters:
- $ref: '../../components/parameters/room-id-path.yaml'
requestBody:
$ref: '../../components/requestBodies/internal/recording-token-request.yaml'
$ref: '../../components/requestBodies/internal/room-member-token-request.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-generate-recording-token.yaml'
$ref: '../../components/responses/internal/success-generate-room-member-token.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-room-secret.yaml'
'401':
@ -23,24 +22,26 @@
'403':
$ref: '../../components/responses/forbidden-error.yaml'
'404':
$ref: '../../components/responses/internal/error-room-metadata-not-found.yaml'
$ref: '../../components/responses/internal/error-room-participant-not-found.yaml'
'409':
$ref: '../../components/responses/internal/error-room-closed.yaml'
'422':
$ref: '../../components/responses/validation-error.yaml'
'500':
$ref: '../../components/responses/internal-server-error.yaml'
/rooms/{roomId}/roles:
get:
operationId: getRoomRolesAndPermissions
summary: Get room roles and permissions
operationId: getRoomMemberRolesAndPermissions
summary: Get room member roles and permissions
description: >
Retrieves the roles and associated permissions that a participant can have in a specified OpenVidu Meet room.
Retrieves the roles and associated permissions that a user can have as a member of a specified OpenVidu Meet room.
tags:
- Internal API - Rooms
parameters:
- $ref: '../../components/parameters/room-id-path.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-get-room-roles.yaml'
$ref: '../../components/responses/internal/success-get-room-member-roles.yaml'
'404':
$ref: '../../components/responses/error-room-not-found.yaml'
'422':
@ -52,10 +53,10 @@
operationId: getRoomRoleAndPermissions
summary: Get room role and permissions
description: |
Retrieves the role and associated permissions that a participant will have in a specified OpenVidu Meet room
when using the URL thant contains the given secret value.
Retrieves the role and associated permissions that a user will have as a member of a specified OpenVidu Meet room
when using the URL that contains the given secret value.
This endpoint is useful for checking the participant's role and permissions before joining the room.
This endpoint is useful for checking the user's role and permissions before accessing the room.
tags:
- Internal API - Rooms
parameters:
@ -63,7 +64,7 @@
- $ref: '../../components/parameters/internal/secret.yaml'
responses:
'200':
$ref: '../../components/responses/internal/success-get-room-role.yaml'
$ref: '../../components/responses/internal/success-get-room-member-role.yaml'
'400':
$ref: '../../components/responses/internal/error-invalid-room-secret.yaml'
'404':

View File

@ -1,4 +1,42 @@
/recordings:
post:
operationId: startRecording
summary: Start a recording
description: >
Start a new recording for an OpenVidu Meet room with the specified room ID.
By default, the recording will use the configuration defined in the room's settings.
However, you can optionally provide a configuration override in the request body to customize
the recording settings (e.g., layout) for this specific recording session.
If a configuration override is provided, those values will take precedence over the room's configuration.
tags:
- OpenVidu Meet - Recordings
security:
- apiKeyHeader: []
- roomMemberTokenHeader: []
requestBody:
$ref: '../components/requestBodies/start-recording-request.yaml'
responses:
'201':
$ref: '../components/responses/success-start-recording.yaml'
'401':
$ref: '../components/responses/unauthorized-error.yaml'
'403':
$ref: '../components/responses/forbidden-not-allowed-error.yaml'
'404':
$ref: '../components/responses/error-room-not-found.yaml'
'409':
$ref: '../components/responses/error-recording-conflict.yaml'
'422':
$ref: '../components/responses/validation-error.yaml'
'500':
$ref: '../components/responses/internal-server-error.yaml'
'503':
$ref: '../components/responses/error-service-unavailable.yaml'
get:
operationId: getRecordings
summary: Get all recordings
@ -6,20 +44,25 @@
Retrieves a paginated list of all recordings available in the system.
You can apply filters to narrow down the results based on specific criteria.
> **Note:** If this endpoint is called using the `recordingTokenHeader` authentication method,
By default, the recordings are sorted by start date in descending order (newest first).
> **Note:** If this endpoint is called using the `roomMemberTokenHeader` authentication method,
> the `roomId` filter will be ignored and only recordings associated with the room included in the token will be returned.
tags:
- OpenVidu Meet - Recordings
security:
- apiKeyHeader: []
- accessTokenHeader: []
- recordingTokenHeader: []
- roomMemberTokenHeader: []
parameters:
# - $ref: '../components/parameters/recording-status.yaml'
- $ref: '../components/parameters/recording-fields.yaml'
- $ref: '../components/parameters/room-id-query.yaml'
- $ref: '../components/parameters/room-name.yaml'
- $ref: '../components/parameters/recording-status.yaml'
- $ref: '../components/parameters/recording-fields.yaml'
- $ref: '../components/parameters/max-items.yaml'
- $ref: '../components/parameters/next-page-token.yaml'
- $ref: '../components/parameters/sort-field.yaml'
- $ref: '../components/parameters/sort-order.yaml'
responses:
'200':
$ref: '../components/responses/success-get-recordings.yaml'
@ -38,7 +81,7 @@
description: |
Deletes multiple recordings at once with the specified recording IDs.
> **Note:** If this endpoint is called using the `recordingTokenHeader` authentication method,
> **Note:** If this endpoint is called using the `roomMemberTokenHeader` authentication method,
> all specified recordings must belong to the same room included in the token.
> If a recording does not belong to that room, it will not be deleted.
tags:
@ -46,7 +89,7 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- recordingTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/recording-ids.yaml'
responses:
@ -71,7 +114,7 @@
Downloads multiple recordings as a ZIP file with the specified recording IDs.
The ZIP file will contain all recordings in MP4 format.
> **Note:** If this endpoint is called using the `recordingTokenHeader` authentication method,
> **Note:** If this endpoint is called using the `roomMemberTokenHeader` authentication method,
> all specified recordings must belong to the same room included in the token.
> If a recording does not belong to that room, it will not be included in the ZIP file.
tags:
@ -79,7 +122,7 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- recordingTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/recording-ids.yaml'
responses:
@ -120,7 +163,7 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- recordingTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/recording-id.yaml'
- $ref: '../components/parameters/recording-secret.yaml'
@ -152,7 +195,7 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- recordingTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/recording-id.yaml'
responses:
@ -185,7 +228,7 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- recordingTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/recording-id.yaml'
- $ref: '../components/parameters/recording-secret.yaml'
@ -244,6 +287,36 @@
$ref: '../components/responses/validation-error.yaml'
'500':
$ref: '../components/responses/internal-server-error.yaml'
/recordings/{recordingId}/stop:
post:
operationId: stopRecording
summary: Stop a recording
description: |
Stops a recording with the specified recording ID.
> **Note:** The recording must be in an `active` state; otherwise, a 409 error is returned.
tags:
- OpenVidu Meet - Recordings
security:
- apiKeyHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/recording-id.yaml'
responses:
'202':
$ref: '../components/responses/success-stop-recording.yaml'
'401':
$ref: '../components/responses/unauthorized-error.yaml'
'403':
$ref: '../components/responses/forbidden-error.yaml'
'404':
$ref: '../components/responses/error-recording-not-found.yaml'
'409':
$ref: '../components/responses/error-recording-not-active.yaml'
'422':
$ref: '../components/responses/validation-error.yaml'
'500':
$ref: '../components/responses/internal-server-error.yaml'
/recordings/{recordingId}/url:
get:
operationId: getRecordingUrl
@ -259,7 +332,7 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- recordingTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/recording-id.yaml'
# - $ref: '../components/parameters/private-access.yaml'

View File

@ -29,6 +29,8 @@
description: >
Retrieves a paginated list of all rooms available in the system.
You can apply filters to narrow down the results based on specific criteria.
By default, the rooms are sorted by creation date in descending order (newest first).
tags:
- OpenVidu Meet - Rooms
security:
@ -36,9 +38,12 @@
- accessTokenHeader: []
parameters:
- $ref: '../components/parameters/room-name.yaml'
- $ref: '../components/parameters/room-status.yaml'
- $ref: '../components/parameters/room-fields.yaml'
- $ref: '../components/parameters/max-items.yaml'
- $ref: '../components/parameters/next-page-token.yaml'
- $ref: '../components/parameters/sort-field.yaml'
- $ref: '../components/parameters/sort-order.yaml'
responses:
'200':
$ref: '../components/responses/success-get-rooms.yaml'
@ -56,10 +61,10 @@
description: |
Delete multiple OpenVidu Meet rooms at once with the specified room IDs.
If any of the rooms have active meetings or recordings,
If any of the rooms have active meetings or recordings,
deletion behavior is determined by the provided `withMeeting` and `withRecordings` deletion policies.
Depending on these policies, the rooms may be deleted/closed immediately, scheduled to be deleted/closed once the meetings end,
Depending on these policies, the rooms may be deleted/closed immediately, scheduled to be deleted/closed once the meetings end,
or the operation may fail if deletion is not permitted.
tags:
- OpenVidu Meet - Rooms
@ -94,16 +99,13 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- participantTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/room-id-path.yaml'
- $ref: '../components/parameters/room-fields.yaml'
- $ref: '../components/parameters/internal/x-participant-role.yaml'
responses:
'200':
$ref: '../components/responses/success-get-room.yaml'
'400':
$ref: '../components/responses/internal/error-invalid-participant-role.yaml'
'401':
$ref: '../components/responses/unauthorized-error.yaml'
'403':
@ -120,10 +122,10 @@
description: |
Deletes the specified OpenVidu Meet room by its room ID.
If the room has an active meeting or existing recordings,
If the room has an active meeting or existing recordings,
deletion behavior is determined by the provided `withMeeting` and `withRecordings` deletion policies.
Depending on these policies, the room may be deleted/closed immediately, scheduled to be deleted/closed once the meeting ends,
Depending on these policies, the room may be deleted/closed immediately, scheduled to be deleted/closed once the meeting ends,
or the operation may fail if deletion is not permitted.
tags:
- OpenVidu Meet - Rooms
@ -162,15 +164,12 @@
security:
- apiKeyHeader: []
- accessTokenHeader: []
- participantTokenHeader: []
- roomMemberTokenHeader: []
parameters:
- $ref: '../components/parameters/room-id-path.yaml'
- $ref: '../components/parameters/internal/x-participant-role.yaml'
responses:
'200':
$ref: '../components/responses/success-get-room-config.yaml'
'400':
$ref: '../components/responses/internal/error-invalid-participant-role.yaml'
'401':
$ref: '../components/responses/unauthorized-error.yaml'
'403':
@ -204,6 +203,39 @@
$ref: '../components/responses/forbidden-error.yaml'
'404':
$ref: '../components/responses/error-room-not-found.yaml'
'409':
$ref: '../components/responses/error-room-active-meeting.yaml'
'422':
$ref: '../components/responses/validation-error.yaml'
'500':
$ref: '../components/responses/internal-server-error.yaml'
/rooms/{roomId}/status:
put:
operationId: updateRoomStatus
summary: Update room status
description: >
Updates the status of an OpenVidu Meet room with the specified room ID.
This can be used to open or close the room for new participants.
tags:
- OpenVidu Meet - Rooms
security:
- apiKeyHeader: []
- accessTokenHeader: []
parameters:
- $ref: '../components/parameters/room-id-path.yaml'
requestBody:
$ref: '../components/requestBodies/update-room-status-request.yaml'
responses:
'200':
$ref: '../components/responses/success-update-room-status.yaml'
'202':
$ref: '../components/responses/success-room-schedule-closure.yaml'
'401':
$ref: '../components/responses/unauthorized-error.yaml'
'403':
$ref: '../components/responses/forbidden-error.yaml'
'404':
$ref: '../components/responses/error-room-not-found.yaml'
'422':
$ref: '../components/responses/validation-error.yaml'
'500':

View File

@ -4,15 +4,19 @@
description: Operations related to managing OpenVidu Meet recordings
- name: Internal API - Authentication
description: Authentication operations
- name: Internal API - API Keys
description: Operations related to managing API keys in OpenVidu Meet
- name: Internal API - Analytics
description: Operations related to usage analytics in OpenVidu Meet
- name: Internal API - Users
description: Operations related to managing users in OpenVidu Meet
- name: Internal API - Global Config
description: Operations related to managing global config in OpenVidu Meet
- name: Internal API - Rooms
description: Operations related to managing OpenVidu Meet rooms
- name: Internal API - Participant
description: Operations related to managing participants in OpenVidu Meet rooms
- name: Internal API - Meetings
description: Operations related to managing meetings in OpenVidu Meet rooms
- name: Internal API - AI Assistants
description: High-level operations to manage AI assistance capabilities in meetings
- name: Internal API - Recordings
description: Operations related to managing OpenVidu Meet recordings

View File

@ -1,6 +1,6 @@
{
"name": "@openvidu-meet/backend",
"version": "3.4.1",
"version": "3.6.0",
"description": "OpenVidu Meet Backend",
"author": "OpenVidu",
"license": "Apache-2.0",
@ -27,7 +27,7 @@
"package.json"
],
"scripts": {
"build": "tsc -p tsconfig.prod.json",
"build": "tsc -p tsconfig.prod.json && pnpm run doc:api",
"build:watch": "tsc -p tsconfig.prod.json --watch",
"doc:api": "mkdir -p public/openapi && cd openapi && openapi-generate-html -i openvidu-meet-api.yaml --ui=stoplight --theme=light --title 'OpenVidu Meet REST API' --description 'OpenVidu Meet REST API' -o ../public/openapi/public.html",
"doc:internal-api": "mkdir -p public/openapi && cd openapi && openapi-generate-html -i openvidu-meet-internal-api.yaml --ui=stoplight --theme=dark --title 'OpenVidu Meet Internal REST API' --description 'OpenVidu Meet Internal REST API' -o ../public/openapi/internal.html",
@ -35,23 +35,29 @@
"start:dev": "NODE_ENV=development concurrently -k -n server,typecheck -c cyan,yellow \"pnpm tsx watch --clear-screen=false --include src ./src/server.ts\" \"pnpm run dev:typecheck\"",
"dev:typecheck": "node ../../scripts/dev/backend-type-checker.mjs",
"package:build": "pnpm run build:prod && pnpm pack",
"test:integration-rooms": "node --experimental-vm-modules ../../node_modules/jest/bin/jest.js --runInBand --forceExit --testPathPattern 'tests/integration/api/rooms' --ci --reporters=default --reporters=jest-junit",
"test:integration-recordings": "node --experimental-vm-modules ../../node_modules/.bin/jest --maxWorkers=1 --maxConcurrency=1 --forceExit --testPathPattern \"tests/integration/api/recordings\" --ci --reporters=default --reporters=jest-junit",
"test:integration-webhooks": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/webhooks\" --ci --reporters=default --reporters=jest-junit",
"test:integration-security": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/security\" --ci --reporters=default --reporters=jest-junit",
"test:integration-global-config": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/global-config\" --ci --reporters=default --reporters=jest-junit",
"test:integration-participants": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/participants\" --ci --reporters=default --reporters=jest-junit",
"test:integration-room-management": "node --experimental-vm-modules ../../node_modules/jest/bin/jest.js --runInBand --forceExit --testPathPattern \"tests/integration/api/(rooms|meetings)\" --ci --reporters=default --reporters=jest-junit",
"test:integration-rooms": "node --experimental-vm-modules ../../node_modules/jest/bin/jest.js --runInBand --forceExit --testPathPattern 'tests/integration/api/rooms' --ci --reporters=default --reporters=jest-junit",
"test:integration-meetings": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/meetings\" --ci --reporters=default --reporters=jest-junit",
"test:integration-webhooks": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/webhooks\" --ci --reporters=default --reporters=jest-junit",
"test:integration-auth-security": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/(security|auth|api-keys|users)\" --ci --reporters=default --reporters=jest-junit",
"test:integration-security": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/security\" --ci --reporters=default --reporters=jest-junit",
"test:integration-auth": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/auth\" --ci --reporters=default --reporters=jest-junit",
"test:integration-api-keys": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/api-keys\" --ci --reporters=default --reporters=jest-junit",
"test:integration-users": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/users\" --ci --reporters=default --reporters=jest-junit",
"test:integration-config-analytics": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/(global-config|analytics)\" --ci --reporters=default --reporters=jest-junit",
"test:integration-global-config": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/global-config\" --ci --reporters=default --reporters=jest-junit",
"test:integration-analytics": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/analytics\" --ci --reporters=default --reporters=jest-junit",
"test:integration-recordings": "node --experimental-vm-modules ../../node_modules/.bin/jest --maxWorkers=1 --maxConcurrency=1 --forceExit --testPathPattern \"tests/integration/api/recordings\" --ci --reporters=default --reporters=jest-junit",
"test:unit": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/unit\" --ci --reporters=default --reporters=jest-junit",
"lint:fix": "eslint src --fix",
"format:code": "prettier --ignore-path .gitignore --write '**/*.{ts,js,json,md}'"
"format:code": "prettier --ignore-path .gitignore --write '**/*.{ts,js,json,md}'",
"clean": "rm -rf node_modules dist public test-results"
},
"dependencies": {
"@openvidu-meet/typings": "workspace:*",
"@aws-sdk/client-s3": "3.846.0",
"@azure/storage-blob": "12.27.0",
"@google-cloud/storage": "7.17.1",
"@google-cloud/storage": "7.17.3",
"@openvidu-meet/typings": "workspace:*",
"@sesamecare-oss/redlock": "1.4.0",
"archiver": "7.0.1",
"bcrypt": "5.1.1",
@ -59,14 +65,16 @@
"chalk": "5.6.2",
"cookie-parser": "1.4.7",
"cors": "2.8.5",
"cron": "4.3.3",
"cron": "4.3.5",
"dotenv": "16.6.1",
"express": "4.21.2",
"express-rate-limit": "7.5.1",
"inversify": "6.2.2",
"ioredis": "5.6.1",
"jwt-decode": "4.0.0",
"livekit-server-sdk": "2.13.1",
"livekit-server-sdk": "2.13.3",
"lodash.merge": "4.6.2",
"mongoose": "8.19.4",
"ms": "2.1.3",
"uid": "2.0.2",
"winston": "3.18.3",
@ -74,14 +82,15 @@
"zod": "3.25.76"
},
"devDependencies": {
"@types/archiver": "6.0.3",
"@types/archiver": "6.0.4",
"@types/bcrypt": "5.0.2",
"@types/cookie-parser": "1.4.9",
"@types/cors": "2.8.19",
"@types/express": "4.17.23",
"@types/express": "4.17.25",
"@types/jest": "29.5.14",
"@types/lodash.merge": "4.6.9",
"@types/ms": "2.1.0",
"@types/node": "22.16.4",
"@types/node": "22.16.5",
"@types/supertest": "6.0.3",
"@types/unzipper": "0.10.11",
"@types/validator": "13.15.2",
@ -90,7 +99,7 @@
"@typescript-eslint/parser": "6.21.0",
"cross-env": "7.0.3",
"eslint": "8.57.1",
"eslint-config-prettier": "9.1.0",
"eslint-config-prettier": "9.1.2",
"jest": "29.7.0",
"jest-fetch-mock": "3.0.3",
"jest-junit": "16.0.0",
@ -100,7 +109,7 @@
"supertest": "7.1.3",
"ts-jest": "29.4.0",
"ts-jest-resolver": "2.0.1",
"tsx": "4.20.3",
"tsx": "4.20.6",
"typescript": "5.9.2",
"unzipper": "0.12.3"
},

View File

@ -1,14 +0,0 @@
import { ParticipantRole, User } from '@openvidu-meet/typings';
import { ClaimGrants } from 'livekit-server-sdk';
// Override the Express Request type to include a session object with user and token properties
// This will allow controllers to access the user and token information from the request object in a type-safe manner
declare module 'express' {
interface Request {
session?: {
user?: User;
tokenClaims?: ClaimGrants;
participantRole?: ParticipantRole;
};
}
}

View File

@ -1,35 +1,60 @@
import { Container } from 'inversify';
import { MEET_BLOB_STORAGE_MODE } from '../environment.js';
import {
ABSService,
ABSStorageProvider,
AuthService,
DistributedEventService,
FrontendEventService,
GCSService,
GCSStorageProvider,
HttpContextService,
LiveKitService,
LivekitWebhookService,
LoggerService,
MeetStorageService,
MutexService,
OpenViduWebhookService,
ParticipantNameService,
ParticipantService,
RecordingService,
RedisService,
RoomService,
S3KeyBuilder,
S3Service,
S3StorageProvider,
StorageFactory,
StorageKeyBuilder,
StorageProvider,
TaskSchedulerService,
TokenService,
UserService
} from '../services/index.js';
import { MEET_ENV } from '../environment.js';
import { ApiKeyRepository } from '../repositories/api-key.repository.js';
import { BaseRepository } from '../repositories/base.repository.js';
import { GlobalConfigRepository } from '../repositories/global-config.repository.js';
import { MigrationRepository } from '../repositories/migration.repository.js';
import { RecordingRepository } from '../repositories/recording.repository.js';
import { RoomRepository } from '../repositories/room.repository.js';
import { UserRepository } from '../repositories/user.repository.js';
/*
* Services should be imported in order of use, starting with services
* without dependencies and then the services that depend on others. This
* helps avoid dependency cycles and ensures constructors receive the
* dependencies already registered in the container.
*/
import { LoggerService } from '../services/logger.service.js';
import { RedisService } from '../services/redis.service.js';
import { DistributedEventService } from '../services/distributed-event.service.js';
import { MutexService } from '../services/mutex.service.js';
import { TaskSchedulerService } from '../services/task-scheduler.service.js';
import { BaseUrlService } from '../services/base-url.service.js';
import { RequestSessionService } from '../services/request-session.service.js';
import { TokenService } from '../services/token.service.js';
import { UserService } from '../services/user.service.js';
import { ApiKeyService } from '../services/api-key.service.js';
import { GlobalConfigService } from '../services/global-config.service.js';
import { S3Service } from '../services/storage/providers/s3/s3.service.js';
import { S3KeyBuilder } from '../services/storage/providers/s3/s3-storage-key.builder.js';
import { S3StorageProvider } from '../services/storage/providers/s3/s3-storage.provider.js';
import { ABSService } from '../services/storage/providers/abs/abs.service.js';
import { ABSStorageProvider } from '../services/storage/providers/abs/abs-storage.provider.js';
import { GCSService } from '../services/storage/providers/gcp/gcs.service.js';
import { GCSStorageProvider } from '../services/storage/providers/gcp/gcs-storage.provider.js';
import { MongoDBService } from '../services/storage/mongodb.service.js';
import { StorageInitService } from '../services/storage/storage-init.service.js';
import { StorageKeyBuilder, StorageProvider } from '../services/storage/storage.interface.js';
import { StorageFactory } from '../services/storage/storage.factory.js';
import { BlobStorageService } from '../services/storage/blob-storage.service.js';
import { MigrationService } from '../services/migration.service.js';
import { LiveKitService } from '../services/livekit.service.js';
import { FrontendEventService } from '../services/frontend-event.service.js';
import { RecordingService } from '../services/recording.service.js';
import { RoomService } from '../services/room.service.js';
import { ParticipantNameService } from '../services/participant-name.service.js';
import { RoomMemberService } from '../services/room-member.service.js';
import { OpenViduWebhookService } from '../services/openvidu-webhook.service.js';
import { LivekitWebhookService } from '../services/livekit-webhook.service.js';
import { RoomScheduledTasksService } from '../services/room-scheduled-tasks.service.js';
import { RecordingScheduledTasksService } from '../services/recording-scheduled-tasks.service.js';
import { AnalyticsService } from '../services/analytics.service.js';
import { AiAssistantService } from '../services/ai-assistant.service.js';
export const container: Container = new Container();
@ -53,24 +78,43 @@ export const registerDependencies = () => {
container.bind(DistributedEventService).toSelf().inSingletonScope();
container.bind(MutexService).toSelf().inSingletonScope();
container.bind(TaskSchedulerService).toSelf().inSingletonScope();
container.bind(HttpContextService).toSelf().inSingletonScope();
container.bind(BaseUrlService).toSelf().inSingletonScope();
// RequestSessionService uses AsyncLocalStorage for request isolation
// It's a singleton but provides per-request data isolation automatically
container.bind(RequestSessionService).toSelf().inSingletonScope();
configureStorage(MEET_BLOB_STORAGE_MODE);
container.bind(StorageFactory).toSelf().inSingletonScope();
container.bind(MeetStorageService).toSelf().inSingletonScope();
container.bind(MongoDBService).toSelf().inSingletonScope();
container.bind(BaseRepository).toSelf().inSingletonScope();
container.bind(RoomRepository).toSelf().inSingletonScope();
container.bind(UserRepository).toSelf().inSingletonScope();
container.bind(ApiKeyRepository).toSelf().inSingletonScope();
container.bind(GlobalConfigRepository).toSelf().inSingletonScope();
container.bind(RecordingRepository).toSelf().inSingletonScope();
container.bind(MigrationRepository).toSelf().inSingletonScope();
container.bind(TokenService).toSelf().inSingletonScope();
container.bind(UserService).toSelf().inSingletonScope();
container.bind(AuthService).toSelf().inSingletonScope();
container.bind(ApiKeyService).toSelf().inSingletonScope();
container.bind(GlobalConfigService).toSelf().inSingletonScope();
configureStorage(MEET_ENV.BLOB_STORAGE_MODE);
container.bind(StorageFactory).toSelf().inSingletonScope();
container.bind(BlobStorageService).toSelf().inSingletonScope();
container.bind(StorageInitService).toSelf().inSingletonScope();
container.bind(MigrationService).toSelf().inSingletonScope();
container.bind(FrontendEventService).toSelf().inSingletonScope();
container.bind(LiveKitService).toSelf().inSingletonScope();
container.bind(RecordingService).toSelf().inSingletonScope();
container.bind(RoomService).toSelf().inSingletonScope();
container.bind(ParticipantNameService).toSelf().inSingletonScope();
container.bind(ParticipantService).toSelf().inSingletonScope();
container.bind(RoomMemberService).toSelf().inSingletonScope();
container.bind(OpenViduWebhookService).toSelf().inSingletonScope();
container.bind(LivekitWebhookService).toSelf().inSingletonScope();
container.bind(RoomScheduledTasksService).toSelf().inSingletonScope();
container.bind(RecordingScheduledTasksService).toSelf().inSingletonScope();
container.bind(AnalyticsService).toSelf().inSingletonScope();
container.bind(AiAssistantService).toSelf().inSingletonScope();
};
const configureStorage = (storageMode: string) => {
@ -100,13 +144,24 @@ const configureStorage = (storageMode: string) => {
};
export const initializeEagerServices = async () => {
// Force the creation of services that need to be initialized at startup
container.get(RecordingService);
// Connect to MongoDB and check health
const mongoService = container.get(MongoDBService);
await mongoService.connect();
await mongoService.checkHealth();
// Perform comprehensive health checks before initializing other services
const storageService = container.get(MeetStorageService);
await storageService.checkStartupHealth();
// Perform blob storage health check
const blobStorageService = container.get(BlobStorageService);
await blobStorageService.checkHealth();
// Initialize storage after health checks pass
await storageService.initializeStorage();
// Run migrations
const migrationService = container.get(MigrationService);
await migrationService.runMigrations();
// Initialize storage
const storageInitService = container.get(StorageInitService);
await storageInitService.initializeStorage();
// Initialize scheduled tasks services to register their cron jobs
container.get(RecordingScheduledTasksService);
container.get(RoomScheduledTasksService);
};

View File

@ -1,33 +1,21 @@
import { StringValue } from 'ms';
import { SchemaVersion } from '../models/migration.model.js';
export const INTERNAL_CONFIG = {
// Base paths for the API
API_BASE_PATH_V1: '/api/v1',
INTERNAL_API_BASE_PATH_V1: '/internal-api/v1',
// Cookie names
ACCESS_TOKEN_COOKIE_NAME: 'OvMeetAccessToken',
REFRESH_TOKEN_COOKIE_NAME: 'OvMeetRefreshToken',
PARTICIPANT_TOKEN_COOKIE_NAME: 'OvMeetParticipantToken',
RECORDING_TOKEN_COOKIE_NAME: 'OvMeetRecordingToken',
// Headers names
API_KEY_HEADER: 'x-api-key',
ACCESS_TOKEN_HEADER: 'authorization',
REFRESH_TOKEN_HEADER: 'x-refresh-token',
PARTICIPANT_TOKEN_HEADER: 'x-participant-token',
PARTICIPANT_ROLE_HEADER: 'x-participant-role',
RECORDING_TOKEN_HEADER: 'x-recording-token',
ROOM_MEMBER_TOKEN_HEADER: 'x-room-member-token',
// Token expiration times
ACCESS_TOKEN_EXPIRATION: '2h',
REFRESH_TOKEN_EXPIRATION: '1d',
PARTICIPANT_TOKEN_EXPIRATION: '2h',
RECORDING_TOKEN_EXPIRATION: '2h',
// Participant name reservations
PARTICIPANT_MAX_CONCURRENT_NAME_REQUESTS: '20', // Maximum number of request by the same name at the same time allowed
PARTICIPANT_NAME_RESERVATION_TTL: '12h' as StringValue, // Time-to-live for participant name reservations
ROOM_MEMBER_TOKEN_EXPIRATION: '2h',
// Authentication usernames
ANONYMOUS_USER: 'anonymous',
@ -36,25 +24,43 @@ export const INTERNAL_CONFIG = {
// S3 configuration
S3_MAX_RETRIES_ATTEMPTS_ON_SAVE_ERROR: '5',
S3_INITIAL_RETRY_DELAY_MS: '100',
S3_ROOMS_PREFIX: 'rooms',
S3_RECORDINGS_PREFIX: 'recordings',
S3_USERS_PREFIX: 'users',
S3_API_KEYS_PREFIX: 'api_keys',
// Garbage collection and recording intervals
ROOM_GC_INTERVAL: '1h' as StringValue, // e.g. garbage collector interval for rooms
RECORDING_LOCK_TTL: '6h' as StringValue, // TTL for recording lock in Redis
RECORDING_STARTED_TIMEOUT: '20s' as StringValue, // Timeout for recording start
RECORDING_LOCK_GC_INTERVAL: '30m' as StringValue, // Garbage collection interval for recording locks
RECORDING_ORPHANED_LOCK_GRACE_PERIOD: '1m' as StringValue, // Grace period for orphaned recording locks
RECORDING_STALE_CLEANUP_INTERVAL: '15m' as StringValue, // Cleanup interval for stale recordings
RECORDING_STALE_AFTER: '5m' as StringValue, // Maximum allowed time since the last recording update before marking as stale
// Cron job configuration
CRON_JOB_LOCK_TTL: '59s' as StringValue, // Default TTL for cron job locks to avoid overlapping executions
// Timing and cleanup settings for room lifecycle management
ROOM_EXPIRED_GC_INTERVAL: '1h' as StringValue, // Interval for processing and deleting expired rooms
ROOM_ACTIVE_VERIFICATION_GC_INTERVAL: '15m' as StringValue, // Interval for checking room 'active_meeting' status consistency
// Timing and cleanup settings for recording lifecycle management
RECORDING_STARTED_TIMEOUT: '20s' as StringValue, // Timeout for recording to be marked as started
RECORDING_ACTIVE_LOCK_TTL: '7d' as StringValue, // Redis Lock TTL for active recording in a room
RECORDING_ACTIVE_LOCK_GC_INTERVAL: '15m' as StringValue, // Interval for cleaning up stale active recording locks
RECORDING_ORPHANED_ACTIVE_LOCK_GRACE_PERIOD: '30s' as StringValue, // Grace period to consider an active recording lock as orphaned (should be greater than RECORDING_STARTED_TIMEOUT)
RECORDING_STALE_GC_INTERVAL: '14m' as StringValue, // Interval for cleaning up stale recordings (not updated recently)
RECORDING_STALE_GRACE_PERIOD: '5m' as StringValue, // Maximum allowed time since the last recording update before marking it as stale
CRON_JOB_MIN_LOCK_TTL: '59s' as StringValue, // Minimum TTL for cron job locks
// Additional intervals
MIN_FUTURE_TIME_FOR_ROOM_AUTODELETION_DATE: '1h' as StringValue, // Minimum time for room auto-deletion date
MEETING_EMPTY_TIMEOUT: '' as StringValue, // Seconds to keep the meeting (LK room) open until the first participant joins
MEETING_DEPARTURE_TIMEOUT: '' as StringValue // Seconds to keep the meeting (LK room) open after the last participant leaves
MIN_ROOM_AUTO_DELETE_DURATION: '1h' as StringValue, // Minimum duration before a room can be auto-deleted
MEETING_EMPTY_TIMEOUT: (process.env.MEETING_EMPTY_TIMEOUT || '20s') as StringValue, // Seconds to keep the meeting (LK room) open until the first participant joins
MEETING_DEPARTURE_TIMEOUT: (process.env.MEETING_DEPARTURE_TIMEOUT || '20s') as StringValue, // Seconds to keep the meeting (LK room) open after the last participant leaves
// Participant name reservation
PARTICIPANT_MAX_CONCURRENT_NAME_REQUESTS: '20', // Maximum number of request by the same name at the same time allowed
PARTICIPANT_NAME_RESERVATION_TTL: '12h' as StringValue, // Time-to-live for participant name reservations
CAPTIONS_AGENT_NAME: 'speech-processing',
// MongoDB Schema Versions
// These define the current schema version for each collection
// Increment when making breaking changes to the schema structure
// IMPORTANT: whenever you increment a schema version, update the MIGRATION_REV timestamp too.
// This helps surface merge conflicts when multiple branches create schema migrations concurrently.
GLOBAL_CONFIG_SCHEMA_VERSION: 1 as SchemaVersion, // MIGRATION_REV: 1771328577054
USER_SCHEMA_VERSION: 1 as SchemaVersion, // MIGRATION_REV: 1771328577054
API_KEY_SCHEMA_VERSION: 1 as SchemaVersion, // MIGRATION_REV: 1771328577054
ROOM_SCHEMA_VERSION: 2 as SchemaVersion, // MIGRATION_REV: 1771328577054
RECORDING_SCHEMA_VERSION: 2 as SchemaVersion // MIGRATION_REV: 1771328577054
};
// This function is used to set private configuration values for testing purposes.

View File

@ -0,0 +1,69 @@
import { Request, Response } from 'express';
import { container } from '../config/dependency-injector.config.js';
import { handleError } from '../models/error.model.js';
import { AiAssistantService } from '../services/ai-assistant.service.js';
import { LoggerService } from '../services/logger.service.js';
import { RequestSessionService } from '../services/request-session.service.js';
import { TokenService } from '../services/token.service.js';
import { getRoomMemberToken } from '../utils/token.utils.js';
const getRoomMemberIdentityFromRequest = async (req: Request): Promise<string> => {
const tokenService = container.get(TokenService);
const token = getRoomMemberToken(req);
if (!token) {
throw new Error('Room member token not found');
}
const claims = await tokenService.verifyToken(token);
if (!claims.sub) {
throw new Error('Room member token does not include participant identity');
}
return claims.sub;
};
export const createAssistant = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const requestSessionService = container.get(RequestSessionService);
const aiAssistantService = container.get(AiAssistantService);
// const payload: MeetCreateAssistantRequest = req.body;
const roomId = requestSessionService.getRoomIdFromToken();
if (!roomId) {
return handleError(res, new Error('Could not resolve room from token'), 'creating assistant');
}
try {
const participantIdentity = await getRoomMemberIdentityFromRequest(req);
logger.verbose(`Creating assistant for participant '${participantIdentity}' in room '${roomId}'`);
const assistant = await aiAssistantService.createLiveCaptionsAssistant(roomId, participantIdentity);
return res.status(200).json(assistant);
} catch (error) {
handleError(res, error, `creating assistant in room '${roomId}'`);
}
};
export const cancelAssistant = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const requestSessionService = container.get(RequestSessionService);
const aiAssistantService = container.get(AiAssistantService);
const { assistantId } = req.params;
const roomId = requestSessionService.getRoomIdFromToken();
if (!roomId) {
return handleError(res, new Error('Could not resolve room from token'), 'canceling assistant');
}
try {
const participantIdentity = await getRoomMemberIdentityFromRequest(req);
logger.verbose(
`Canceling assistant '${assistantId}' for participant '${participantIdentity}' in room '${roomId}'`
);
await aiAssistantService.cancelAssistant(assistantId, roomId, participantIdentity);
return res.status(204).send();
} catch (error) {
handleError(res, error, `canceling assistant '${assistantId}' in room '${roomId}'`);
}
};

View File

@ -0,0 +1,18 @@
import { Request, Response } from 'express';
import { container } from '../config/dependency-injector.config.js';
import { handleError } from '../models/error.model.js';
import { AnalyticsService } from '../services/analytics.service.js';
import { LoggerService } from '../services/logger.service.js';
export const getAnalytics = async (req: Request, res: Response): Promise<void> => {
const logger = container.get(LoggerService);
logger.verbose('Analytics request received');
try {
const analyticsService = container.get(AnalyticsService);
const analytics = await analyticsService.getAnalytics();
res.status(200).json(analytics);
} catch (error) {
handleError(res, error, 'getting analytics');
}
};

View File

@ -0,0 +1,47 @@
import { Request, Response } from 'express';
import { container } from '../config/dependency-injector.config.js';
import { handleError } from '../models/error.model.js';
import { ApiKeyService } from '../services/api-key.service.js';
import { LoggerService } from '../services/logger.service.js';
export const createApiKey = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Create API key request received');
const apiKeyService = container.get(ApiKeyService);
try {
const apiKey = await apiKeyService.createApiKey();
return res.status(201).json(apiKey);
} catch (error) {
handleError(res, error, 'creating API key');
}
};
export const getApiKeys = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Get API keys request received');
const apiKeyService = container.get(ApiKeyService);
try {
const apiKeys = await apiKeyService.getApiKeys();
return res.status(200).json(apiKeys);
} catch (error) {
handleError(res, error, 'getting API keys');
}
};
export const deleteApiKeys = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Delete API keys request received');
const apiKeyService = container.get(ApiKeyService);
try {
await apiKeyService.deleteApiKeys();
return res.status(200).json({ message: 'API keys deleted successfully' });
} catch (error) {
handleError(res, error, 'deleting API keys');
}
};

View File

@ -1,8 +1,6 @@
import { AuthTransportMode } from '@openvidu-meet/typings';
import { Request, Response } from 'express';
import { ClaimGrants } from 'livekit-server-sdk';
import { container } from '../config/index.js';
import { INTERNAL_CONFIG } from '../config/internal-config.js';
import { container } from '../config/dependency-injector.config.js';
import {
errorInvalidCredentials,
errorInvalidRefreshToken,
@ -11,16 +9,18 @@ import {
handleError,
rejectRequestFromMeetError
} from '../models/error.model.js';
import { AuthService, LoggerService, TokenService, UserService } from '../services/index.js';
import { getAuthTransportMode, getCookieOptions, getRefreshToken } from '../utils/index.js';
import { LoggerService } from '../services/logger.service.js';
import { TokenService } from '../services/token.service.js';
import { UserService } from '../services/user.service.js';
import { getRefreshToken } from '../utils/token.utils.js';
export const login = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Login request received');
const { username, password } = req.body as { username: string; password: string };
const authService = container.get(AuthService);
const user = await authService.authenticateUser(username, password);
const userService = container.get(UserService);
const user = await userService.authenticateUser(username, password);
if (!user) {
logger.warn('Login failed');
@ -34,49 +34,19 @@ export const login = async (req: Request, res: Response) => {
const refreshToken = await tokenService.generateRefreshToken(user);
logger.info(`Login succeeded for user '${username}'`);
const transportMode = await getAuthTransportMode();
if (transportMode === AuthTransportMode.HEADER) {
// Send tokens in response body for header mode
return res.status(200).json({
message: `User '${username}' logged in successfully`,
accessToken,
refreshToken
});
} else {
// Send tokens as cookies for cookie mode
res.cookie(
INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME,
accessToken,
getCookieOptions('/', INTERNAL_CONFIG.ACCESS_TOKEN_EXPIRATION)
);
res.cookie(
INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME,
refreshToken,
getCookieOptions(
`${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/auth`,
INTERNAL_CONFIG.REFRESH_TOKEN_EXPIRATION
)
);
return res.status(200).json({ message: `User '${username}' logged in successfully` });
}
return res.status(200).json({
message: `User '${username}' logged in successfully`,
accessToken,
refreshToken
});
} catch (error) {
handleError(res, error, 'generating access and refresh tokens');
}
};
export const logout = async (_req: Request, res: Response) => {
const transportMode = await getAuthTransportMode();
if (transportMode === AuthTransportMode.COOKIE) {
// Clear cookies only in cookie mode
res.clearCookie(INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
res.clearCookie(INTERNAL_CONFIG.REFRESH_TOKEN_COOKIE_NAME, {
path: `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/auth`
});
}
// In header mode, the client is responsible for clearing localStorage
// The client is responsible for clearing tokens from localStorage,
// so just respond with success
return res.status(200).json({ message: 'Logout successful' });
};
@ -118,66 +88,11 @@ export const refreshToken = async (req: Request, res: Response) => {
const accessToken = await tokenService.generateAccessToken(user);
logger.info(`Access token refreshed for user '${username}'`);
const transportMode = await getAuthTransportMode();
if (transportMode === AuthTransportMode.HEADER) {
// Send access token in response body for header mode
return res.status(200).json({
message: `Access token for user '${username}' successfully refreshed`,
accessToken
});
} else {
// Send access token as cookie for cookie mode
res.cookie(
INTERNAL_CONFIG.ACCESS_TOKEN_COOKIE_NAME,
accessToken,
getCookieOptions('/', INTERNAL_CONFIG.ACCESS_TOKEN_EXPIRATION)
);
return res.status(200).json({ message: `Access token for user '${username}' successfully refreshed` });
}
return res.status(200).json({
message: `Access token for user '${username}' successfully refreshed`,
accessToken
});
} catch (error) {
handleError(res, error, 'refreshing token');
}
};
export const createApiKey = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Create API key request received');
const authService = container.get(AuthService);
try {
const apiKey = await authService.createApiKey();
return res.status(201).json(apiKey);
} catch (error) {
handleError(res, error, 'creating API key');
}
};
export const getApiKeys = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Get API keys request received');
const authService = container.get(AuthService);
try {
const apiKeys = await authService.getApiKeys();
return res.status(200).json(apiKeys);
} catch (error) {
handleError(res, error, 'getting API keys');
}
};
export const deleteApiKeys = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Delete API keys request received');
const authService = container.get(AuthService);
try {
await authService.deleteApiKeys();
return res.status(200).json({ message: 'API keys deleted successfully' });
} catch (error) {
handleError(res, error, 'deleting API keys');
}
};

View File

@ -0,0 +1,124 @@
import { MeetAppearanceConfig, SecurityConfig, WebhookConfig } from '@openvidu-meet/typings';
import { Request, Response } from 'express';
import { container } from '../config/dependency-injector.config.js';
import { MEET_ENV } from '../environment.js';
import { handleError } from '../models/error.model.js';
import { GlobalConfigService } from '../services/global-config.service.js';
import { LoggerService } from '../services/logger.service.js';
import { OpenViduWebhookService } from '../services/openvidu-webhook.service.js';
export const updateWebhookConfig = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const configService = container.get(GlobalConfigService);
logger.info(`Updating webhooks config: ${JSON.stringify(req.body)}`);
const webhookConfig = req.body as WebhookConfig;
try {
await configService.updateWebhookConfig(webhookConfig);
return res.status(200).json({ message: 'Webhooks config updated successfully' });
} catch (error) {
handleError(res, error, 'updating webhooks config');
}
};
export const getWebhookConfig = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
const configService = container.get(GlobalConfigService);
logger.verbose('Getting webhooks config');
try {
const webhookConfig = await configService.getWebhookConfig();
return res.status(200).json(webhookConfig);
} catch (error) {
handleError(res, error, 'getting webhooks config');
}
};
export const testWebhook = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const webhookService = container.get(OpenViduWebhookService);
logger.verbose(`Testing webhook URL: ${req.body.url}`);
const url = req.body.url;
try {
await webhookService.testWebhookUrl(url);
logger.info(`Webhook URL '${url}' is valid`);
return res.status(200).json({ message: 'Webhook URL is valid' });
} catch (error) {
handleError(res, error, 'testing webhook URL');
}
};
export const updateSecurityConfig = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const configService = container.get(GlobalConfigService);
logger.verbose(`Updating security config: ${JSON.stringify(req.body)}`);
const securityConfig = req.body as SecurityConfig;
try {
await configService.updateSecurityConfig(securityConfig);
return res.status(200).json({ message: 'Security config updated successfully' });
} catch (error) {
handleError(res, error, 'updating security config');
}
};
export const getSecurityConfig = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
const configService = container.get(GlobalConfigService);
logger.verbose('Getting security config');
try {
const securityConfig = await configService.getSecurityConfig();
return res.status(200).json(securityConfig);
} catch (error) {
handleError(res, error, 'getting security config');
}
};
export const updateRoomsAppearanceConfig = async (req: Request, res: Response) => {
const logger = container.get(LoggerService);
const configService = container.get(GlobalConfigService);
logger.verbose(`Updating rooms appearance config: ${JSON.stringify(req.body)}`);
const appearanceConfig = req.body as { appearance: MeetAppearanceConfig };
try {
await configService.updateRoomsAppearanceConfig(appearanceConfig);
return res.status(200).json({ message: 'Rooms appearance config updated successfully' });
} catch (error) {
handleError(res, error, 'updating rooms appearance config');
}
};
export const getRoomsAppearanceConfig = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
const configService = container.get(GlobalConfigService);
logger.verbose(`Getting rooms appearance config`);
try {
const appearanceConfig = await configService.getRoomsAppearanceConfig();
return res.status(200).json(appearanceConfig);
} catch (error) {
handleError(res, error, 'getting rooms appearance config');
}
};
export const getCaptionsConfig = async (_req: Request, res: Response) => {
const logger = container.get(LoggerService);
logger.verbose('Getting captions config');
try {
const captionsEnabled = MEET_ENV.CAPTIONS_ENABLED === 'true';
return res.status(200).json({ enabled: captionsEnabled });
} catch (error) {
handleError(res, error, 'getting captions config');
}
};

Some files were not shown because too many files have changed in this diff Show More