Merge pull request #378 from Monadical-SAS/whereby-embedded

Whereby embedded
This commit is contained in:
2024-08-20 13:39:23 +02:00
committed by GitHub
31 changed files with 2308 additions and 12 deletions

2
server/.gitignore vendored
View File

@@ -113,7 +113,7 @@ ipython_config.py
__pypackages__/ __pypackages__/
# Celery stuff # Celery stuff
celerybeat-schedule celerybeat-schedule.db
celerybeat.pid celerybeat.pid
# SageMath parsed files # SageMath parsed files

View File

@@ -0,0 +1,26 @@
"""add meeting
Revision ID: 1340c04426b8
Revises: b9348748bbbc
Create Date: 2024-07-31 16:41:29.415218
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "1340c04426b8"
down_revision: Union[str, None] = "b9348748bbbc"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.add_column("transcript", sa.Column("meeting_id", sa.String(), nullable=True))
def downgrade() -> None:
op.drop_column("transcript", "meeting_id")

View File

@@ -11,6 +11,8 @@ from reflector.events import subscribers_shutdown, subscribers_startup
from reflector.logger import logger from reflector.logger import logger
from reflector.metrics import metrics_init from reflector.metrics import metrics_init
from reflector.settings import settings from reflector.settings import settings
from reflector.views.meetings import router as meetings_router
from reflector.views.rooms import router as rooms_router
from reflector.views.rtc_offer import router as rtc_offer_router from reflector.views.rtc_offer import router as rtc_offer_router
from reflector.views.transcripts import router as transcripts_router from reflector.views.transcripts import router as transcripts_router
from reflector.views.transcripts_audio import router as transcripts_audio_router from reflector.views.transcripts_audio import router as transcripts_audio_router
@@ -68,6 +70,8 @@ metrics_init(app, instrumentator)
# register views # register views
app.include_router(rtc_offer_router) app.include_router(rtc_offer_router)
app.include_router(meetings_router, prefix="/v1")
app.include_router(rooms_router, prefix="/v1")
app.include_router(transcripts_router, prefix="/v1") app.include_router(transcripts_router, prefix="/v1")
app.include_router(transcripts_audio_router, prefix="/v1") app.include_router(transcripts_audio_router, prefix="/v1")
app.include_router(transcripts_participants_router, prefix="/v1") app.include_router(transcripts_participants_router, prefix="/v1")

View File

@@ -7,6 +7,8 @@ database = databases.Database(settings.DATABASE_URL)
metadata = sqlalchemy.MetaData() metadata = sqlalchemy.MetaData()
# import models # import models
import reflector.db.meetings # noqa
import reflector.db.rooms # noqa
import reflector.db.transcripts # noqa import reflector.db.transcripts # noqa
engine = sqlalchemy.create_engine( engine = sqlalchemy.create_engine(

View File

@@ -0,0 +1,115 @@
from datetime import datetime, timezone
import sqlalchemy
from fastapi import HTTPException
from pydantic import BaseModel
from reflector.db import database, metadata
meetings = sqlalchemy.Table(
"meeting",
metadata,
sqlalchemy.Column("id", sqlalchemy.String, primary_key=True),
sqlalchemy.Column("room_name", sqlalchemy.String),
sqlalchemy.Column("room_url", sqlalchemy.String),
sqlalchemy.Column("host_room_url", sqlalchemy.String),
sqlalchemy.Column("viewer_room_url", sqlalchemy.String),
sqlalchemy.Column("start_date", sqlalchemy.DateTime),
sqlalchemy.Column("end_date", sqlalchemy.DateTime),
sqlalchemy.Column("user_id", sqlalchemy.String),
sqlalchemy.Column("room_id", sqlalchemy.String),
)
class Meeting(BaseModel):
id: str
room_name: str
room_url: str
host_room_url: str
viewer_room_url: str
start_date: datetime
end_date: datetime
user_id: str | None = None
room_id: str | None = None
class MeetingController:
async def create(
self,
id: str,
room_name: str,
room_url: str,
host_room_url: str,
viewer_room_url: str,
start_date: datetime,
end_date: datetime,
user_id: str,
room_id: str = None,
):
"""
Create a new meeting
"""
meeting = Meeting(
id=id,
room_name=room_name,
room_url=room_url,
host_room_url=host_room_url,
viewer_room_url=viewer_room_url,
start_date=start_date,
end_date=end_date,
user_id=user_id,
room_id=room_id,
)
query = meetings.insert().values(**meeting.model_dump())
await database.execute(query)
return meeting
async def get_by_room_name(
self,
room_name: str,
) -> Meeting:
"""
Get a meeting by room name.
"""
query = meetings.select().where(meetings.c.room_name == room_name)
result = await database.fetch_one(query)
if not result:
return None
return Meeting(**result)
async def get_latest(self, room_id: str) -> Meeting:
"""
Get latest meeting for a room.
"""
end_date = getattr(meetings.c, "end_date")
query = (
meetings.select()
.where(meetings.c.room_id == room_id)
.where(meetings.c.end_date > datetime.now(timezone.utc))
.order_by(end_date.desc())
)
result = await database.fetch_one(query)
if not result:
return None
return Meeting(**result)
async def get_by_id_for_http(self, meeting_id: str, user_id: str | None) -> Meeting:
"""
Get a meeting by ID for HTTP request.
If not found, it will raise a 404 error.
"""
query = meetings.select().where(meetings.c.id == meeting_id)
result = await database.fetch_one(query)
if not result:
raise HTTPException(status_code=404, detail="Meeting not found")
meeting = Meeting(**result)
if result["user_id"] != user_id:
meeting.host_room_url = ""
return meeting
meetings_controller = MeetingController()

View File

@@ -0,0 +1,139 @@
from datetime import datetime
import sqlalchemy
from fastapi import HTTPException
from pydantic import BaseModel, Field
from reflector.db import database, metadata
from reflector.db.transcripts import generate_uuid4
from sqlalchemy.sql import false
rooms = sqlalchemy.Table(
"room",
metadata,
sqlalchemy.Column("id", sqlalchemy.String, primary_key=True),
sqlalchemy.Column("name", sqlalchemy.String, nullable=False),
sqlalchemy.Column("user_id", sqlalchemy.String, nullable=False),
sqlalchemy.Column("created_at", sqlalchemy.DateTime, nullable=False),
sqlalchemy.Column(
"zulip_auto_post", sqlalchemy.Boolean, nullable=False, server_default=false()
),
sqlalchemy.Column("zulip_stream", sqlalchemy.String),
sqlalchemy.Column("zulip_topic", sqlalchemy.String),
)
class Room(BaseModel):
id: str = Field(default_factory=generate_uuid4)
name: str
user_id: str
created_at: datetime = Field(default_factory=datetime.utcnow)
zulip_auto_post: bool = False
zulip_stream: str = ""
zulip_topic: str = ""
class RoomController:
async def get_all(
self,
user_id: str | None = None,
order_by: str | None = None,
return_query: bool = False,
) -> list[Room]:
"""
Get all rooms
If `user_id` is specified, only return rooms that belong to the user.
Otherwise, return all rooms.
Parameters:
- `order_by`: field to order by, e.g. "-created_at"
"""
query = rooms.select()
if user_id is not None:
query = query.where(rooms.c.user_id == user_id)
if order_by is not None:
field = getattr(rooms.c, order_by[1:])
if order_by.startswith("-"):
field = field.desc()
query = query.order_by(field)
if return_query:
return query
results = await database.fetch_all(query)
return results
async def add(
self,
name: str,
user_id: str,
):
"""
Add a new room
"""
room = Room(
name=name,
user_id=user_id,
)
query = rooms.insert().values(**room.model_dump())
await database.execute(query)
return room
async def get_by_id(self, room_id: str, **kwargs) -> Room | None:
"""
Get a room by id
"""
query = rooms.select().where(rooms.c.id == room_id)
if "user_id" in kwargs:
query = query.where(rooms.c.user_id == kwargs["user_id"])
result = await database.fetch_one(query)
if not result:
return None
return Room(**result)
async def get_by_name(self, room_name: str, **kwargs) -> Room | None:
"""
Get a room by name
"""
query = rooms.select().where(rooms.c.name == room_name)
if "user_id" in kwargs:
query = query.where(rooms.c.user_id == kwargs["user_id"])
result = await database.fetch_one(query)
if not result:
return None
return Room(**result)
async def get_by_id_for_http(self, meeting_id: str, user_id: str | None) -> Room:
"""
Get a room by ID for HTTP request.
If not found, it will raise a 404 error.
"""
query = rooms.select().where(rooms.c.id == meeting_id)
result = await database.fetch_one(query)
if not result:
raise HTTPException(status_code=404, detail="Room not found")
room = Room(**result)
return room
async def remove_by_id(
self,
room_id: str,
user_id: str | None = None,
) -> None:
"""
Remove a room by id
"""
room = await self.get_by_id(room_id, user_id=user_id)
if not room:
return
if user_id is not None and room.user_id != user_id:
return
query = rooms.delete().where(rooms.c.id == room_id)
await database.execute(query)
rooms_controller = RoomController()

View File

@@ -50,6 +50,10 @@ transcripts = sqlalchemy.Table(
nullable=False, nullable=False,
server_default="private", server_default="private",
), ),
sqlalchemy.Column(
"meeting_id",
sqlalchemy.String,
),
) )
@@ -145,6 +149,7 @@ class Transcript(BaseModel):
share_mode: Literal["private", "semi-private", "public"] = "private" share_mode: Literal["private", "semi-private", "public"] = "private"
audio_location: str = "local" audio_location: str = "local"
reviewed: bool = False reviewed: bool = False
meeting_id: str | None = None
def add_event(self, event: str, data: BaseModel) -> TranscriptEvent: def add_event(self, event: str, data: BaseModel) -> TranscriptEvent:
ev = TranscriptEvent(event=event, data=data.model_dump()) ev = TranscriptEvent(event=event, data=data.model_dump())
@@ -329,6 +334,18 @@ class TranscriptController:
return None return None
return Transcript(**result) return Transcript(**result)
async def get_by_meeting_id(self, meeting_id: str, **kwargs) -> Transcript | None:
"""
Get a transcript by meeting_id
"""
query = transcripts.select().where(transcripts.c.meeting_id == meeting_id)
if "user_id" in kwargs:
query = query.where(transcripts.c.user_id == kwargs["user_id"])
result = await database.fetch_one(query)
if not result:
return None
return Transcript(**result)
async def get_by_id_for_http( async def get_by_id_for_http(
self, self,
transcript_id: str, transcript_id: str,
@@ -376,6 +393,8 @@ class TranscriptController:
source_language: str = "en", source_language: str = "en",
target_language: str = "en", target_language: str = "en",
user_id: str | None = None, user_id: str | None = None,
meeting_id: str | None = None,
share_mode: str = "private",
): ):
""" """
Add a new transcript Add a new transcript
@@ -385,6 +404,8 @@ class TranscriptController:
source_language=source_language, source_language=source_language,
target_language=target_language, target_language=target_language,
user_id=user_id, user_id=user_id,
meeting_id=meeting_id,
share_mode=share_mode,
) )
query = transcripts.insert().values(**transcript.model_dump()) query = transcripts.insert().values(**transcript.model_dump())
await database.execute(query) await database.execute(query)

View File

@@ -131,5 +131,11 @@ class Settings(BaseSettings):
# Healthcheck # Healthcheck
HEALTHCHECK_URL: str | None = None HEALTHCHECK_URL: str | None = None
AWS_PROCESS_RECORDING_QUEUE_URL: str | None = None
WHEREBY_API_URL: str = "https://api.whereby.dev/v1/meetings"
WHEREBY_API_KEY: str | None = None
settings = Settings() settings = Settings()

View File

@@ -0,0 +1,56 @@
from datetime import datetime, timedelta, timezone
from typing import Annotated, Optional
import reflector.auth as auth
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from reflector.db.meetings import meetings_controller
from reflector.whereby import create_meeting
router = APIRouter()
class GetMeeting(BaseModel):
id: str
room_name: str
room_url: str
host_room_url: str
viewer_room_url: str
start_date: datetime
end_date: datetime
@router.get("/meetings/{meeting_id}", response_model=GetMeeting)
async def meeting_get(
meeting_id: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
return await meetings_controller.get_by_id_for_http(meeting_id, user_id=user_id)
@router.post("/meetings/", response_model=GetMeeting)
async def meeting_create(
room_id: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
meeting = await meetings_controller.get_latest(room_id)
if meeting is None:
start_date = datetime.now(timezone.utc)
end_date = start_date + timedelta(hours=1)
meeting = await create_meeting("", start_date=start_date, end_date=end_date)
meeting = await meetings_controller.add(
id=meeting["meetingId"],
room_name=meeting["roomName"],
room_url=meeting["roomUrl"],
host_room_url=meeting["hostRoomUrl"],
viewer_room_url=meeting["viewerRoomUrl"],
start_date=datetime.fromisoformat(meeting["startDate"]),
end_date=datetime.fromisoformat(meeting["endDate"]),
user_id=user_id,
room_id=room_id,
)
return await meetings_controller.get_by_id_for_http(meeting.id, user_id=user_id)

View File

@@ -0,0 +1,107 @@
from datetime import datetime, timedelta, timezone
from http.client import HTTPException
from typing import Annotated, Optional
import reflector.auth as auth
from fastapi import APIRouter, Depends
from fastapi_pagination import Page
from fastapi_pagination.ext.databases import paginate
from pydantic import BaseModel
from reflector.db import database
from reflector.db.meetings import meetings_controller
from reflector.db.rooms import rooms_controller
from reflector.settings import settings
from reflector.views.meetings import GetMeeting
from reflector.whereby import create_meeting
router = APIRouter()
class Room(BaseModel):
id: str
name: str
user_id: str
created_at: datetime
class CreateRoom(BaseModel):
name: str
class DeletionStatus(BaseModel):
status: str
@router.get("/rooms", response_model=Page[Room])
async def rooms_list(
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
) -> list[Room]:
user_id = user["sub"] if user else None
if not user and not settings.PUBLIC_MODE:
raise HTTPException(status_code=401, detail="Not authenticated")
user_id = user["sub"] if user else None
return await paginate(
database,
await rooms_controller.get_all(
user_id=user_id, order_by="-created_at", return_query=True
),
)
@router.post("/rooms", response_model=Room)
async def rooms_create(
room: CreateRoom,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
return await rooms_controller.add(
name=room.name,
user_id=user_id,
)
@router.delete("/rooms/{room_id}", response_model=DeletionStatus)
async def rooms_delete(
room_id: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
room = await rooms_controller.get_by_id(room_id, user_id=user_id)
if not room:
raise HTTPException(status_code=404, detail="Room not found")
await rooms_controller.remove_by_id(room.id, user_id=user_id)
return DeletionStatus(status="ok")
@router.post("/rooms/{room_name}/meeting", response_model=GetMeeting)
async def rooms_create_meeting(
room_name: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
room = await rooms_controller.get_by_name(room_name)
if not room:
raise HTTPException(status_code=404, detail="Room not found")
meeting = await meetings_controller.get_latest(room_id=room.id)
if meeting is None:
start_date = datetime.now(timezone.utc)
end_date = start_date + timedelta(hours=1)
meeting = await create_meeting("", start_date=start_date, end_date=end_date)
meeting = await meetings_controller.create(
id=meeting["meetingId"],
room_name=meeting["roomName"],
room_url=meeting["roomUrl"],
host_room_url=meeting["hostRoomUrl"],
viewer_room_url=meeting["viewerRoomUrl"],
start_date=datetime.fromisoformat(meeting["startDate"]),
end_date=datetime.fromisoformat(meeting["endDate"]),
user_id=user_id,
room_id=room.id,
)
return meeting

View File

@@ -1,4 +1,4 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta, timezone
from typing import Annotated, Literal, Optional from typing import Annotated, Literal, Optional
import reflector.auth as auth import reflector.auth as auth
@@ -7,6 +7,7 @@ from fastapi_pagination import Page
from fastapi_pagination.ext.databases import paginate from fastapi_pagination.ext.databases import paginate
from jose import jwt from jose import jwt
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from reflector.db.meetings import meetings_controller
from reflector.db.transcripts import ( from reflector.db.transcripts import (
TranscriptParticipant, TranscriptParticipant,
TranscriptTopic, TranscriptTopic,
@@ -15,6 +16,7 @@ from reflector.db.transcripts import (
from reflector.processors.types import Transcript as ProcessorTranscript from reflector.processors.types import Transcript as ProcessorTranscript
from reflector.processors.types import Word from reflector.processors.types import Word
from reflector.settings import settings from reflector.settings import settings
from reflector.whereby import create_meeting
router = APIRouter() router = APIRouter()
@@ -51,6 +53,7 @@ class GetTranscript(BaseModel):
target_language: str | None target_language: str | None
participants: list[TranscriptParticipant] | None participants: list[TranscriptParticipant] | None
reviewed: bool reviewed: bool
meeting_id: str | None
class CreateTranscript(BaseModel): class CreateTranscript(BaseModel):
@@ -108,6 +111,37 @@ async def transcripts_create(
) )
@router.post("/transcripts/meeting", response_model=GetTranscript)
async def transcripts_create_meeting(
info: CreateTranscript,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
start_date = datetime.now(timezone.utc)
end_date = start_date + timedelta(hours=1)
meeting = await create_meeting("", start_date=start_date, end_date=end_date)
meeting = await meetings_controller.create(
id=meeting["meetingId"],
room_name=meeting["roomName"],
room_url=meeting["roomUrl"],
host_room_url=meeting["hostRoomUrl"],
viewer_room_url=meeting["viewerRoomUrl"],
start_date=datetime.fromisoformat(meeting["startDate"]),
end_date=datetime.fromisoformat(meeting["endDate"]),
user_id=user_id,
)
return await transcripts_controller.add(
"",
source_language=info.source_language,
target_language=info.target_language,
user_id=user_id,
meeting_id=meeting.id,
share_mode="public",
)
# ============================================================== # ==============================================================
# Single transcript # Single transcript
# ============================================================== # ==============================================================

View File

@@ -0,0 +1,29 @@
from datetime import datetime
import httpx
from reflector.settings import settings
async def create_meeting(
room_name_prefix: str, start_date: datetime, end_date: datetime
):
headers = {
"Content-Type": "application/json; charset=utf-8",
"Authorization": f"Bearer {settings.WHEREBY_API_KEY}",
}
data = {
"templateType": "viewerMode",
"isLocked": False,
"roomNamePrefix": room_name_prefix,
"roomNamePattern": "uuid",
"roomMode": "normal",
"startDate": start_date.isoformat(),
"endDate": end_date.isoformat(),
}
async with httpx.AsyncClient() as client:
response = await client.post(
settings.WHEREBY_API_URL, headers=headers, json=data, timeout=10
)
response.raise_for_status()
return response.json()

View File

@@ -16,11 +16,17 @@ else:
[ [
"reflector.pipelines.main_live_pipeline", "reflector.pipelines.main_live_pipeline",
"reflector.worker.healthcheck", "reflector.worker.healthcheck",
"reflector.worker.process",
] ]
) )
# crontab # crontab
app.conf.beat_schedule = {} app.conf.beat_schedule = {
"process_messages": {
"task": "reflector.worker.process.process_messages",
"schedule": 60.0,
}
}
if settings.HEALTHCHECK_URL: if settings.HEALTHCHECK_URL:
app.conf.beat_schedule["healthcheck_ping"] = { app.conf.beat_schedule["healthcheck_ping"] = {

View File

@@ -0,0 +1,104 @@
import json
import os
from urllib.parse import unquote
import av
import boto3
import structlog
from celery import shared_task
from celery.utils.log import get_task_logger
from reflector.db.meetings import meetings_controller
from reflector.db.transcripts import transcripts_controller
from reflector.pipelines.main_live_pipeline import asynctask, task_pipeline_process
from reflector.settings import settings
logger = structlog.wrap_logger(get_task_logger(__name__))
@shared_task
def process_messages():
queue_url = settings.AWS_PROCESS_RECORDING_QUEUE_URL
if not queue_url:
logger.warning("No process recording queue url")
return
try:
logger.info("Receiving messages from: %s", queue_url)
sqs = boto3.client(
"sqs",
region_name=settings.TRANSCRIPT_STORAGE_AWS_REGION,
aws_access_key_id=settings.TRANSCRIPT_STORAGE_AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.TRANSCRIPT_STORAGE_AWS_SECRET_ACCESS_KEY,
)
response = sqs.receive_message(
QueueUrl=queue_url,
AttributeNames=["SentTimestamp"],
MaxNumberOfMessages=1,
MessageAttributeNames=["All"],
VisibilityTimeout=0,
WaitTimeSeconds=0,
)
for message in response.get("Messages", []):
receipt_handle = message["ReceiptHandle"]
body = json.loads(message["Body"])
for record in body.get("Records", []):
if record["eventName"].startswith("ObjectCreated"):
bucket = record["s3"]["bucket"]["name"]
key = unquote(record["s3"]["object"]["key"])
process_recording.delay(bucket, key)
sqs.delete_message(QueueUrl=queue_url, ReceiptHandle=receipt_handle)
logger.info("Processed and deleted message: %s", message)
except Exception as e:
logger.error("process_messages", error=str(e))
@shared_task
@asynctask
async def process_recording(bucket_name: str, object_key: str):
logger.info("Processing recording: %s/%s", bucket_name, object_key)
# extract a guid from the object key
room_name = f"/{object_key[:36]}"
meeting = await meetings_controller.get_by_room_name(room_name)
transcript = await transcripts_controller.get_by_meeting_id(meeting.id)
if transcript is None:
transcript = await transcripts_controller.add(
"",
source_language="en",
target_language="en",
user_id=meeting.user_id,
meeting_id=meeting.id,
share_mode="public",
)
_, extension = os.path.splitext(object_key)
upload_filename = transcript.data_path / f"upload{extension}"
upload_filename.parent.mkdir(parents=True, exist_ok=True)
s3 = boto3.client(
"s3",
region_name=settings.TRANSCRIPT_STORAGE_AWS_REGION,
aws_access_key_id=settings.TRANSCRIPT_STORAGE_AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.TRANSCRIPT_STORAGE_AWS_SECRET_ACCESS_KEY,
)
with open(upload_filename, "wb") as f:
s3.download_fileobj(bucket_name, object_key, f)
container = av.open(upload_filename.as_posix())
try:
if not len(container.streams.audio):
raise Exception("File has no audio stream")
except Exception:
upload_filename.unlink()
raise
finally:
container.close()
await transcripts_controller.update(transcript, {"status": "uploaded"})
task_pipeline_process.delay(transcript_id=transcript.id)

View File

@@ -76,7 +76,7 @@ type LayoutProps = {
export default async function RootLayout({ children, params }: LayoutProps) { export default async function RootLayout({ children, params }: LayoutProps) {
const config = await getConfig(params.domain); const config = await getConfig(params.domain);
const { requireLogin, privacy, browse } = config.features; const { requireLogin, privacy, browse, rooms } = config.features;
const hasAuthCookie = !!cookies().get(SESSION_COOKIE_NAME); const hasAuthCookie = !!cookies().get(SESSION_COOKIE_NAME);
return ( return (
@@ -154,6 +154,21 @@ export default async function RootLayout({ children, params }: LayoutProps) {
) : ( ) : (
<></> <></>
)} )}
{rooms ? (
<>
&nbsp;·&nbsp;
<Link
href="/rooms"
as={NextLink}
className="hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
prefetch={false}
>
Rooms
</Link>
</>
) : (
<></>
)}
&nbsp;·&nbsp; &nbsp;·&nbsp;
<About buttonText="About" /> <About buttonText="About" />
{privacy ? ( {privacy ? (

View File

@@ -0,0 +1,33 @@
"use client";
import "@whereby.com/browser-sdk/embed";
import { useCallback, useEffect, useRef } from "react";
import useRoomMeeting from "../../rooms/useRoomMeeting";
export type RoomDetails = {
params: {
roomName: string;
};
};
export default function Room(details: RoomDetails) {
const wherebyRef = useRef<HTMLElement>(null);
const roomName = details.params.roomName;
const meeting = useRoomMeeting(roomName);
const roomUrl = meeting?.response?.host_room_url
? meeting?.response?.host_room_url
: meeting?.response?.room_url;
return (
<>
{roomUrl && (
<whereby-embed
ref={wherebyRef}
room={roomUrl}
style={{ width: "100%", height: "98%" }}
/>
)}
</>
);
}

View File

@@ -0,0 +1,171 @@
"use client";
import {
Box,
Button,
Card,
CardBody,
Flex,
FormControl,
FormHelperText,
FormLabel,
Grid,
Heading,
Input,
Link,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Spacer,
Spinner,
useDisclosure,
VStack,
Text,
Menu,
MenuButton,
MenuList,
MenuItem,
AlertDialog,
IconButton,
} from "@chakra-ui/react";
import NextLink from "next";
import React, { ReactNode, useState } from "react";
import { Container } from "@chakra-ui/react";
import { PlusSquareIcon } from "@chakra-ui/icons";
import useApi from "../../lib/useApi";
import useRoomList from "./useRoomList";
import { FaEllipsisVertical, FaTrash } from "react-icons/fa6";
import next from "next";
export default function RoomsList() {
const { isOpen, onOpen, onClose } = useDisclosure();
const [roomName, setRoomName] = useState("");
const api = useApi();
const [page, setPage] = useState<number>(1);
const { loading, response, refetch } = useRoomList(page);
const handleAddRoom = async () => {
try {
const response = await api?.v1RoomsCreate({
requestBody: { name: roomName },
});
setRoomName("");
refetch();
} catch (err) {}
onClose();
};
const handleDeleteRoom = async (roomId: string) => {
try {
const response = await api?.v1RoomsDelete({
roomId,
});
refetch();
} catch (err) {}
};
const handleRoomNameChange = (e) => {
setRoomName(e.target.value);
};
if (loading && !response)
return (
<Flex flexDir="column" align="center" justify="center" h="100%">
<Spinner size="xl" />
</Flex>
);
return (
<>
<Container maxW={"container.lg"}>
<Flex
flexDir="row"
justify="flex-end"
align="center"
flexWrap={"wrap-reverse"}
mb={2}
>
<Heading>Rooms</Heading>
<Spacer />
<Button colorScheme="blue" onClick={onOpen}>
Add Room
</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Add Room</ModalHeader>
<ModalCloseButton />
<ModalBody>
<FormControl>
<FormLabel>Room name</FormLabel>
<Input
placeholder="room-name"
value={roomName}
onChange={handleRoomNameChange}
/>
<FormHelperText>Please enter room name</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button variant="ghost" mr={3} onClick={onClose}>
Cancel
</Button>
<Button colorScheme="blue" onClick={handleAddRoom}>
Add
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Flex>
<VStack>
{response?.items && response.items.length > 0 ? (
response.items.map((room) => (
<Card w={"full"}>
<CardBody>
<Flex align={"center"}>
<Heading size="md">
<Link
// as={NextLink}
href={`/rooms/${room.name}`}
noOfLines={2}
>
{room.name}
</Link>
</Heading>
<Spacer />
<Menu closeOnSelect={true}>
<MenuButton
as={IconButton}
icon={<FaEllipsisVertical />}
aria-label="actions"
/>
<MenuList>
<MenuItem
onClick={() => handleDeleteRoom(room.id)}
icon={<FaTrash color={"red.500"} />}
>
Delete
</MenuItem>
</MenuList>
</Menu>
</Flex>
</CardBody>
</Card>
))
) : (
<Flex flexDir="column" align="center" justify="center" h="100%">
<Text>No rooms found</Text>
</Flex>
)}
</VStack>
</Container>
</>
);
}

View File

@@ -0,0 +1,47 @@
import { useEffect, useState } from "react";
import { useError } from "../../(errors)/errorContext";
import useApi from "../../lib/useApi";
import { Page_Room_ } from "../../api";
type RoomList = {
response: Page_Room_ | null;
loading: boolean;
error: Error | null;
refetch: () => void;
};
//always protected
const useRoomList = (page: number): RoomList => {
const [response, setResponse] = useState<Page_Room_ | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = useApi();
const [refetchCount, setRefetchCount] = useState(0);
const refetch = () => {
setLoading(true);
setRefetchCount(refetchCount + 1);
};
useEffect(() => {
if (!api) return;
setLoading(true);
api
.v1RoomsList({ page })
.then((response) => {
setResponse(response);
setLoading(false);
})
.catch((err) => {
setResponse(null);
setLoading(false);
setError(err);
setErrorState(err);
});
}, [!api, page, refetchCount]);
return { response, loading, error, refetch };
};
export default useRoomList;

View File

@@ -0,0 +1,70 @@
import { useEffect, useState } from "react";
import { useError } from "../../(errors)/errorContext";
import { GetMeeting } from "../../api";
import { shouldShowError } from "../../lib/errorUtils";
import useApi from "../../lib/useApi";
type ErrorMeeting = {
error: Error;
loading: false;
response: null;
reload: () => void;
};
type LoadingMeeting = {
response: null;
loading: true;
error: false;
reload: () => void;
};
type SuccessMeeting = {
response: GetMeeting;
loading: false;
error: null;
reload: () => void;
};
const useRoomMeeting = (
roomName: string | null | undefined,
): ErrorMeeting | LoadingMeeting | SuccessMeeting => {
const [response, setResponse] = useState<GetMeeting | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const [reload, setReload] = useState(0);
const { setError } = useError();
const api = useApi();
const reloadHandler = () => setReload((prev) => prev + 1);
useEffect(() => {
if (!roomName || !api) return;
if (!response) {
setLoading(true);
}
api
.v1RoomsCreateMeeting({ roomName })
.then((result) => {
setResponse(result);
setLoading(false);
console.debug("Meeting Loaded:", result);
})
.catch((error) => {
const shouldShowHuman = shouldShowError(error);
if (shouldShowHuman) {
setError(error, "There was an error loading the meeting");
} else {
setError(error);
}
setErrorState(error);
});
}, [roomName, !api, reload]);
return { response, loading, error, reload: reloadHandler } as
| ErrorMeeting
| LoadingMeeting
| SuccessMeeting;
};
export default useRoomMeeting;

View File

@@ -0,0 +1,34 @@
"use client";
import "@whereby.com/browser-sdk/embed";
import { useCallback, useEffect, useRef } from "react";
import useTranscript from "../../useTranscript";
import useMeeting from "../../useMeeting";
export type TranscriptDetails = {
params: {
transcriptId: string;
};
};
export default function TranscriptMeeting(details: TranscriptDetails) {
const wherebyRef = useRef<HTMLElement>(null);
const transcript = useTranscript(details.params.transcriptId);
const meeting = useMeeting(transcript?.response?.meeting_id);
const roomUrl = meeting?.response?.host_room_url
? meeting?.response?.host_room_url
: meeting?.response?.room_url;
return (
<>
{roomUrl && (
<whereby-embed
ref={wherebyRef}
room={roomUrl}
style={{ width: "100%", height: "98%" }}
/>
)}
</>
);
}

View File

@@ -9,6 +9,7 @@ type UseCreateTranscript = {
loading: boolean; loading: boolean;
error: Error | null; error: Error | null;
create: (transcriptCreationDetails: CreateTranscript) => void; create: (transcriptCreationDetails: CreateTranscript) => void;
createMeeting: (transcriptCreationDetails: CreateTranscript) => void;
}; };
const useCreateTranscript = (): UseCreateTranscript => { const useCreateTranscript = (): UseCreateTranscript => {
@@ -39,7 +40,28 @@ const useCreateTranscript = (): UseCreateTranscript => {
}); });
}; };
return { transcript, loading, error, create }; const createMeeting = (transcriptCreationDetails: CreateTranscript) => {
if (loading || !api) return;
setLoading(true);
api
.v1TranscriptsCreateMeeting({ requestBody: transcriptCreationDetails })
.then((transcript) => {
setTranscript(transcript);
setLoading(false);
})
.catch((err) => {
setError(
err,
"There was an issue creating a transcript, please try again.",
);
setErrorState(err);
setLoading(false);
});
};
return { transcript, loading, error, create, createMeeting };
}; };
export default useCreateTranscript; export default useCreateTranscript;

View File

@@ -32,6 +32,7 @@ const TranscriptCreate = () => {
const [loadingRecord, setLoadingRecord] = useState(false); const [loadingRecord, setLoadingRecord] = useState(false);
const [loadingUpload, setLoadingUpload] = useState(false); const [loadingUpload, setLoadingUpload] = useState(false);
const [loadingMeeting, setLoadingMeeting] = useState(false);
const send = () => { const send = () => {
if (loadingRecord || createTranscript.loading || permissionDenied) return; if (loadingRecord || createTranscript.loading || permissionDenied) return;
@@ -45,8 +46,17 @@ const TranscriptCreate = () => {
createTranscript.create({ name, target_language: targetLanguage }); createTranscript.create({ name, target_language: targetLanguage });
}; };
const startMeeting = () => {
if (loadingMeeting || createTranscript.loading || permissionDenied) return;
setLoadingMeeting(true);
createTranscript.createMeeting({ name, target_language: targetLanguage });
};
useEffect(() => { useEffect(() => {
const action = loadingRecord ? "record" : "upload"; let action = "record";
if (loadingUpload) action = "upload";
if (loadingMeeting) action = "meeting";
createTranscript.transcript && createTranscript.transcript &&
router.push(`/transcripts/${createTranscript.transcript.id}/${action}`); router.push(`/transcripts/${createTranscript.transcript.id}/${action}`);
}, [createTranscript.transcript]); }, [createTranscript.transcript]);
@@ -152,6 +162,23 @@ const TranscriptCreate = () => {
> >
{loadingUpload ? "Loading..." : "Upload File"} {loadingUpload ? "Loading..." : "Upload File"}
</Button> </Button>
{requireLogin && (
<>
<Text align="center" m="2">
OR
</Text>
<Button
colorScheme="blue"
onClick={startMeeting}
isDisabled={
loadingRecord || loadingUpload || loadingMeeting
}
>
{loadingUpload ? "Loading..." : "Start Whereby Meeting"}
</Button>
</>
)}
</div> </div>
)} )}
</section> </section>

View File

@@ -0,0 +1,70 @@
import { useEffect, useState } from "react";
import { useError } from "../../(errors)/errorContext";
import { GetMeeting } from "../../api";
import { shouldShowError } from "../../lib/errorUtils";
import useApi from "../../lib/useApi";
type ErrorMeeting = {
error: Error;
loading: false;
response: null;
reload: () => void;
};
type LoadingMeeting = {
response: null;
loading: true;
error: false;
reload: () => void;
};
type SuccessMeeting = {
response: GetMeeting;
loading: false;
error: null;
reload: () => void;
};
const useMeeting = (
id: string | null | undefined,
): ErrorMeeting | LoadingMeeting | SuccessMeeting => {
const [response, setResponse] = useState<GetMeeting | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const [reload, setReload] = useState(0);
const { setError } = useError();
const api = useApi();
const reloadHandler = () => setReload((prev) => prev + 1);
useEffect(() => {
if (!id || !api) return;
if (!response) {
setLoading(true);
}
api
.v1MeetingGet({ meetingId: id })
.then((result) => {
setResponse(result);
setLoading(false);
console.debug("Meeting Loaded:", result);
})
.catch((error) => {
const shouldShowHuman = shouldShowError(error);
if (shouldShowHuman) {
setError(error, "There was an error loading the meeting");
} else {
setError(error);
}
setErrorState(error);
});
}, [id, !api, reload]);
return { response, loading, error, reload: reloadHandler } as
| ErrorMeeting
| LoadingMeeting
| SuccessMeeting;
};
export default useMeeting;

View File

@@ -53,6 +53,18 @@ export const $CreateParticipant = {
title: "CreateParticipant", title: "CreateParticipant",
} as const; } as const;
export const $CreateRoom = {
properties: {
name: {
type: "string",
title: "Name",
},
},
type: "object",
required: ["name"],
title: "CreateRoom",
} as const;
export const $CreateTranscript = { export const $CreateTranscript = {
properties: { properties: {
name: { name: {
@@ -87,6 +99,52 @@ export const $DeletionStatus = {
title: "DeletionStatus", title: "DeletionStatus",
} as const; } as const;
export const $GetMeeting = {
properties: {
id: {
type: "string",
title: "Id",
},
room_name: {
type: "string",
title: "Room Name",
},
room_url: {
type: "string",
title: "Room Url",
},
host_room_url: {
type: "string",
title: "Host Room Url",
},
viewer_room_url: {
type: "string",
title: "Viewer Room Url",
},
start_date: {
type: "string",
format: "date-time",
title: "Start Date",
},
end_date: {
type: "string",
format: "date-time",
title: "End Date",
},
},
type: "object",
required: [
"id",
"room_name",
"room_url",
"host_room_url",
"viewer_room_url",
"start_date",
"end_date",
],
title: "GetMeeting",
} as const;
export const $GetTranscript = { export const $GetTranscript = {
properties: { properties: {
id: { id: {
@@ -203,6 +261,17 @@ export const $GetTranscript = {
type: "boolean", type: "boolean",
title: "Reviewed", title: "Reviewed",
}, },
meeting_id: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Meeting Id",
},
}, },
type: "object", type: "object",
required: [ required: [
@@ -220,6 +289,7 @@ export const $GetTranscript = {
"target_language", "target_language",
"participants", "participants",
"reviewed", "reviewed",
"meeting_id",
], ],
title: "GetTranscript", title: "GetTranscript",
} as const; } as const;
@@ -471,6 +541,62 @@ export const $Page_GetTranscript_ = {
title: "Page[GetTranscript]", title: "Page[GetTranscript]",
} as const; } as const;
export const $Page_Room_ = {
properties: {
items: {
items: {
$ref: "#/components/schemas/Room",
},
type: "array",
title: "Items",
},
total: {
type: "integer",
minimum: 0,
title: "Total",
},
page: {
anyOf: [
{
type: "integer",
minimum: 1,
},
{
type: "null",
},
],
title: "Page",
},
size: {
anyOf: [
{
type: "integer",
minimum: 1,
},
{
type: "null",
},
],
title: "Size",
},
pages: {
anyOf: [
{
type: "integer",
minimum: 0,
},
{
type: "null",
},
],
title: "Pages",
},
},
type: "object",
required: ["items", "total", "page", "size"],
title: "Page[Room]",
} as const;
export const $Participant = { export const $Participant = {
properties: { properties: {
id: { id: {
@@ -498,6 +624,31 @@ export const $Participant = {
title: "Participant", title: "Participant",
} as const; } as const;
export const $Room = {
properties: {
id: {
type: "string",
title: "Id",
},
name: {
type: "string",
title: "Name",
},
user_id: {
type: "string",
title: "User Id",
},
created_at: {
type: "string",
format: "date-time",
title: "Created At",
},
},
type: "object",
required: ["id", "name", "user_id", "created_at"],
title: "Room",
} as const;
export const $RtcOffer = { export const $RtcOffer = {
properties: { properties: {
sdp: { sdp: {

View File

@@ -4,10 +4,24 @@ import type { CancelablePromise } from "./core/CancelablePromise";
import type { BaseHttpRequest } from "./core/BaseHttpRequest"; import type { BaseHttpRequest } from "./core/BaseHttpRequest";
import type { import type {
MetricsResponse, MetricsResponse,
V1MeetingGetData,
V1MeetingGetResponse,
V1MeetingCreateData,
V1MeetingCreateResponse,
V1RoomsListData,
V1RoomsListResponse,
V1RoomsCreateData,
V1RoomsCreateResponse,
V1RoomsDeleteData,
V1RoomsDeleteResponse,
V1RoomsCreateMeetingData,
V1RoomsCreateMeetingResponse,
V1TranscriptsListData, V1TranscriptsListData,
V1TranscriptsListResponse, V1TranscriptsListResponse,
V1TranscriptsCreateData, V1TranscriptsCreateData,
V1TranscriptsCreateResponse, V1TranscriptsCreateResponse,
V1TranscriptsCreateMeetingData,
V1TranscriptsCreateMeetingResponse,
V1TranscriptGetData, V1TranscriptGetData,
V1TranscriptGetResponse, V1TranscriptGetResponse,
V1TranscriptUpdateData, V1TranscriptUpdateData,
@@ -67,6 +81,139 @@ export class DefaultService {
}); });
} }
/**
* Meeting Get
* @param data The data for the request.
* @param data.meetingId
* @returns GetMeeting Successful Response
* @throws ApiError
*/
public v1MeetingGet(
data: V1MeetingGetData,
): CancelablePromise<V1MeetingGetResponse> {
return this.httpRequest.request({
method: "GET",
url: "/v1/meetings/{meeting_id}",
path: {
meeting_id: data.meetingId,
},
errors: {
422: "Validation Error",
},
});
}
/**
* Meeting Create
* @param data The data for the request.
* @param data.roomId
* @returns GetMeeting Successful Response
* @throws ApiError
*/
public v1MeetingCreate(
data: V1MeetingCreateData,
): CancelablePromise<V1MeetingCreateResponse> {
return this.httpRequest.request({
method: "POST",
url: "/v1/meetings/",
query: {
room_id: data.roomId,
},
errors: {
422: "Validation Error",
},
});
}
/**
* Rooms List
* @param data The data for the request.
* @param data.page Page number
* @param data.size Page size
* @returns Page_Room_ Successful Response
* @throws ApiError
*/
public v1RoomsList(
data: V1RoomsListData = {},
): CancelablePromise<V1RoomsListResponse> {
return this.httpRequest.request({
method: "GET",
url: "/v1/rooms",
query: {
page: data.page,
size: data.size,
},
errors: {
422: "Validation Error",
},
});
}
/**
* Rooms Create
* @param data The data for the request.
* @param data.requestBody
* @returns Room Successful Response
* @throws ApiError
*/
public v1RoomsCreate(
data: V1RoomsCreateData,
): CancelablePromise<V1RoomsCreateResponse> {
return this.httpRequest.request({
method: "POST",
url: "/v1/rooms",
body: data.requestBody,
mediaType: "application/json",
errors: {
422: "Validation Error",
},
});
}
/**
* Rooms Delete
* @param data The data for the request.
* @param data.roomId
* @returns DeletionStatus Successful Response
* @throws ApiError
*/
public v1RoomsDelete(
data: V1RoomsDeleteData,
): CancelablePromise<V1RoomsDeleteResponse> {
return this.httpRequest.request({
method: "DELETE",
url: "/v1/rooms/{room_id}",
path: {
room_id: data.roomId,
},
errors: {
422: "Validation Error",
},
});
}
/**
* Rooms Create Meeting
* @param data The data for the request.
* @param data.roomName
* @returns GetMeeting Successful Response
* @throws ApiError
*/
public v1RoomsCreateMeeting(
data: V1RoomsCreateMeetingData,
): CancelablePromise<V1RoomsCreateMeetingResponse> {
return this.httpRequest.request({
method: "POST",
url: "/v1/rooms/{room_name}/meeting",
path: {
room_name: data.roomName,
},
errors: {
422: "Validation Error",
},
});
}
/** /**
* Transcripts List * Transcripts List
* @param data The data for the request. * @param data The data for the request.
@@ -112,6 +259,27 @@ export class DefaultService {
}); });
} }
/**
* Transcripts Create Meeting
* @param data The data for the request.
* @param data.requestBody
* @returns GetTranscript Successful Response
* @throws ApiError
*/
public v1TranscriptsCreateMeeting(
data: V1TranscriptsCreateMeetingData,
): CancelablePromise<V1TranscriptsCreateMeetingResponse> {
return this.httpRequest.request({
method: "POST",
url: "/v1/transcripts/meeting",
body: data.requestBody,
mediaType: "application/json",
errors: {
422: "Validation Error",
},
});
}
/** /**
* Transcript Get * Transcript Get
* @param data The data for the request. * @param data The data for the request.

View File

@@ -14,6 +14,10 @@ export type CreateParticipant = {
name: string; name: string;
}; };
export type CreateRoom = {
name: string;
};
export type CreateTranscript = { export type CreateTranscript = {
name: string; name: string;
source_language?: string; source_language?: string;
@@ -24,6 +28,16 @@ export type DeletionStatus = {
status: string; status: string;
}; };
export type GetMeeting = {
id: string;
room_name: string;
room_url: string;
host_room_url: string;
viewer_room_url: string;
start_date: string;
end_date: string;
};
export type GetTranscript = { export type GetTranscript = {
id: string; id: string;
user_id: string | null; user_id: string | null;
@@ -40,6 +54,7 @@ export type GetTranscript = {
target_language: string | null; target_language: string | null;
participants: Array<TranscriptParticipant> | null; participants: Array<TranscriptParticipant> | null;
reviewed: boolean; reviewed: boolean;
meeting_id: string | null;
}; };
export type GetTranscriptSegmentTopic = { export type GetTranscriptSegmentTopic = {
@@ -92,12 +107,27 @@ export type Page_GetTranscript_ = {
pages?: number | null; pages?: number | null;
}; };
export type Page_Room_ = {
items: Array<Room>;
total: number;
page: number | null;
size: number | null;
pages?: number | null;
};
export type Participant = { export type Participant = {
id: string; id: string;
speaker: number | null; speaker: number | null;
name: string; name: string;
}; };
export type Room = {
id: string;
name: string;
user_id: string;
created_at: string;
};
export type RtcOffer = { export type RtcOffer = {
sdp: string; sdp: string;
type: string; type: string;
@@ -167,6 +197,49 @@ export type Word = {
export type MetricsResponse = unknown; export type MetricsResponse = unknown;
export type V1MeetingGetData = {
meetingId: string;
};
export type V1MeetingGetResponse = GetMeeting;
export type V1MeetingCreateData = {
roomId: string;
};
export type V1MeetingCreateResponse = GetMeeting;
export type V1RoomsListData = {
/**
* Page number
*/
page?: number;
/**
* Page size
*/
size?: number;
};
export type V1RoomsListResponse = Page_Room_;
export type V1RoomsCreateData = {
requestBody: CreateRoom;
};
export type V1RoomsCreateResponse = Room;
export type V1RoomsDeleteData = {
roomId: string;
};
export type V1RoomsDeleteResponse = DeletionStatus;
export type V1RoomsCreateMeetingData = {
roomName: string;
};
export type V1RoomsCreateMeetingResponse = GetMeeting;
export type V1TranscriptsListData = { export type V1TranscriptsListData = {
/** /**
* Page number * Page number
@@ -186,6 +259,12 @@ export type V1TranscriptsCreateData = {
export type V1TranscriptsCreateResponse = GetTranscript; export type V1TranscriptsCreateResponse = GetTranscript;
export type V1TranscriptsCreateMeetingData = {
requestBody: CreateTranscript;
};
export type V1TranscriptsCreateMeetingResponse = GetTranscript;
export type V1TranscriptGetData = { export type V1TranscriptGetData = {
transcriptId: string; transcriptId: string;
}; };
@@ -336,6 +415,94 @@ export type $OpenApiTs = {
}; };
}; };
}; };
"/v1/meetings/{meeting_id}": {
get: {
req: V1MeetingGetData;
res: {
/**
* Successful Response
*/
200: GetMeeting;
/**
* Validation Error
*/
422: HTTPValidationError;
};
};
};
"/v1/meetings/": {
post: {
req: V1MeetingCreateData;
res: {
/**
* Successful Response
*/
200: GetMeeting;
/**
* Validation Error
*/
422: HTTPValidationError;
};
};
};
"/v1/rooms": {
get: {
req: V1RoomsListData;
res: {
/**
* Successful Response
*/
200: Page_Room_;
/**
* Validation Error
*/
422: HTTPValidationError;
};
};
post: {
req: V1RoomsCreateData;
res: {
/**
* Successful Response
*/
200: Room;
/**
* Validation Error
*/
422: HTTPValidationError;
};
};
};
"/v1/rooms/{room_id}": {
delete: {
req: V1RoomsDeleteData;
res: {
/**
* Successful Response
*/
200: DeletionStatus;
/**
* Validation Error
*/
422: HTTPValidationError;
};
};
};
"/v1/rooms/{room_name}/meeting": {
post: {
req: V1RoomsCreateMeetingData;
res: {
/**
* Successful Response
*/
200: GetMeeting;
/**
* Validation Error
*/
422: HTTPValidationError;
};
};
};
"/v1/transcripts": { "/v1/transcripts": {
get: { get: {
req: V1TranscriptsListData; req: V1TranscriptsListData;
@@ -364,6 +531,21 @@ export type $OpenApiTs = {
}; };
}; };
}; };
"/v1/transcripts/meeting": {
post: {
req: V1TranscriptsCreateMeetingData;
res: {
/**
* Successful Response
*/
200: GetTranscript;
/**
* Validation Error
*/
422: HTTPValidationError;
};
};
};
"/v1/transcripts/{transcript_id}": { "/v1/transcripts/{transcript_id}": {
get: { get: {
req: V1TranscriptGetData; req: V1TranscriptGetData;

View File

@@ -3,6 +3,12 @@
import { ChakraProvider } from "@chakra-ui/react"; import { ChakraProvider } from "@chakra-ui/react";
import theme from "./styles/theme"; import theme from "./styles/theme";
import { WherebyProvider } from "@whereby.com/browser-sdk/react";
export function Providers({ children }: { children: React.ReactNode }) { export function Providers({ children }: { children: React.ReactNode }) {
return <ChakraProvider theme={theme}>{children}</ChakraProvider>; return (
<ChakraProvider theme={theme}>
<WherebyProvider>{children}</WherebyProvider>
</ChakraProvider>
);
} }

View File

@@ -4,6 +4,7 @@ export const localConfig = {
privacy: true, privacy: true,
browse: true, browse: true,
sendToZulip: true, sendToZulip: true,
rooms: true,
}, },
api_url: "http://127.0.0.1:1250", api_url: "http://127.0.0.1:1250",
websocket_url: "ws://127.0.0.1:1250", websocket_url: "ws://127.0.0.1:1250",

View File

@@ -14,8 +14,9 @@ export async function middleware(request: NextRequest) {
) { ) {
// Feature-flag protedted paths // Feature-flag protedted paths
if ( if (
!config.features.browse && (!config.features.browse &&
request.nextUrl.pathname.startsWith("/browse") request.nextUrl.pathname.startsWith("/browse")) ||
(!config.features.rooms && request.nextUrl.pathname.startsWith("/rooms"))
) { ) {
return NextResponse.redirect(request.nextUrl.origin); return NextResponse.redirect(request.nextUrl.origin);
} }
@@ -27,7 +28,8 @@ export async function middleware(request: NextRequest) {
if ( if (
request.nextUrl.pathname == "/" || request.nextUrl.pathname == "/" ||
request.nextUrl.pathname.startsWith("/transcripts") || request.nextUrl.pathname.startsWith("/transcripts") ||
request.nextUrl.pathname.startsWith("/browse") request.nextUrl.pathname.startsWith("/browse") ||
request.nextUrl.pathname.startsWith("/rooms")
) { ) {
if (!fiefResponse.headers.get("x-middleware-rewrite")) { if (!fiefResponse.headers.get("x-middleware-rewrite")) {
fiefResponse.headers.set( fiefResponse.headers.set(

View File

@@ -24,6 +24,7 @@
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@sentry/nextjs": "^7.77.0", "@sentry/nextjs": "^7.77.0",
"@vercel/edge-config": "^0.4.1", "@vercel/edge-config": "^0.4.1",
"@whereby.com/browser-sdk": "^3.3.4",
"autoprefixer": "10.4.14", "autoprefixer": "10.4.14",
"axios": "^1.6.2", "axios": "^1.6.2",
"chakra-react-select": "^4.7.6", "chakra-react-select": "^4.7.6",
@@ -55,8 +56,8 @@
"author": "Andreas <andreas@monadical.com>", "author": "Andreas <andreas@monadical.com>",
"license": "All Rights Reserved", "license": "All Rights Reserved",
"devDependencies": { "devDependencies": {
"@types/react": "18.2.20",
"@hey-api/openapi-ts": "^0.48.0", "@hey-api/openapi-ts": "^0.48.0",
"@types/react": "18.2.20",
"prettier": "^3.0.0" "prettier": "^3.0.0"
} }
} }

View File

@@ -1064,6 +1064,21 @@
dependencies: dependencies:
"@floating-ui/utils" "^0.1.3" "@floating-ui/utils" "^0.1.3"
"@floating-ui/core@^1.6.0":
version "1.6.4"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.4.tgz#0140cf5091c8dee602bff9da5ab330840ff91df6"
integrity sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==
dependencies:
"@floating-ui/utils" "^0.2.4"
"@floating-ui/dom@^1.0.0":
version "1.6.7"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.7.tgz#85d22f731fcc5b209db504478fb1df5116a83015"
integrity sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==
dependencies:
"@floating-ui/core" "^1.6.0"
"@floating-ui/utils" "^0.2.4"
"@floating-ui/dom@^1.0.1": "@floating-ui/dom@^1.0.1":
version "1.5.3" version "1.5.3"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa" resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa"
@@ -1072,11 +1087,23 @@
"@floating-ui/core" "^1.4.2" "@floating-ui/core" "^1.4.2"
"@floating-ui/utils" "^0.1.3" "@floating-ui/utils" "^0.1.3"
"@floating-ui/react-dom@^2.0.0":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.1.tgz#cca58b6b04fc92b4c39288252e285e0422291fb0"
integrity sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==
dependencies:
"@floating-ui/dom" "^1.0.0"
"@floating-ui/utils@^0.1.3": "@floating-ui/utils@^0.1.3":
version "0.1.6" version "0.1.6"
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9"
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
"@floating-ui/utils@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.4.tgz#1d459cee5031893a08a0e064c406ad2130cced7c"
integrity sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==
"@fortawesome/fontawesome-common-types@6.4.0": "@fortawesome/fontawesome-common-types@6.4.0":
version "6.4.0" version "6.4.0"
resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz" resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz"
@@ -1277,6 +1304,180 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
"@radix-ui/primitive@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2"
integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==
"@radix-ui/react-arrow@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz#744f388182d360b86285217e43b6c63633f39e7a"
integrity sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==
dependencies:
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-compose-refs@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74"
integrity sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==
"@radix-ui/react-context@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8"
integrity sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==
"@radix-ui/react-dismissable-layer@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz#2cd0a49a732372513733754e6032d3fb7988834e"
integrity sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-escape-keydown" "1.1.0"
"@radix-ui/react-focus-guards@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz#8e9abb472a9a394f59a1b45f3dd26cfe3fc6da13"
integrity sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==
"@radix-ui/react-focus-scope@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz#ebe2891a298e0a33ad34daab2aad8dea31caf0b2"
integrity sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==
dependencies:
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-id@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.0.tgz#de47339656594ad722eb87f94a6b25f9cffae0ed"
integrity sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==
dependencies:
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-popover@^1.0.7":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.1.tgz#604b783cdb3494ed4f16a58c17f0e81e61ab7775"
integrity sha512-3y1A3isulwnWhvTTwmIreiB8CF4L+qRjZnK1wYLO7pplddzXKby/GnZ2M7OZY3qgnl6p9AodUIHRYGXNah8Y7g==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.0"
"@radix-ui/react-dismissable-layer" "1.1.0"
"@radix-ui/react-focus-guards" "1.1.0"
"@radix-ui/react-focus-scope" "1.1.0"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-popper" "1.2.0"
"@radix-ui/react-portal" "1.1.1"
"@radix-ui/react-presence" "1.1.0"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-slot" "1.1.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
aria-hidden "^1.1.1"
react-remove-scroll "2.5.7"
"@radix-ui/react-popper@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.0.tgz#a3e500193d144fe2d8f5d5e60e393d64111f2a7a"
integrity sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==
dependencies:
"@floating-ui/react-dom" "^2.0.0"
"@radix-ui/react-arrow" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.0"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-use-rect" "1.1.0"
"@radix-ui/react-use-size" "1.1.0"
"@radix-ui/rect" "1.1.0"
"@radix-ui/react-portal@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.1.tgz#1957f1eb2e1aedfb4a5475bd6867d67b50b1d15f"
integrity sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==
dependencies:
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-presence@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.0.tgz#227d84d20ca6bfe7da97104b1a8b48a833bfb478"
integrity sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==
dependencies:
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-primitive@2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz#fe05715faa9203a223ccc0be15dc44b9f9822884"
integrity sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==
dependencies:
"@radix-ui/react-slot" "1.1.0"
"@radix-ui/react-slot@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84"
integrity sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==
dependencies:
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-use-callback-ref@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz#bce938ca413675bc937944b0d01ef6f4a6dc5bf1"
integrity sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==
"@radix-ui/react-use-controllable-state@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz#1321446857bb786917df54c0d4d084877aab04b0"
integrity sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==
dependencies:
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-escape-keydown@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz#31a5b87c3b726504b74e05dac1edce7437b98754"
integrity sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==
dependencies:
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-layout-effect@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27"
integrity sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==
"@radix-ui/react-use-rect@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz#13b25b913bd3e3987cc9b073a1a164bb1cf47b88"
integrity sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==
dependencies:
"@radix-ui/rect" "1.1.0"
"@radix-ui/react-use-size@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz#b4dba7fbd3882ee09e8d2a44a3eed3a7e555246b"
integrity sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==
dependencies:
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/rect@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438"
integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
"@reduxjs/toolkit@^2.2.3":
version "2.2.6"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.2.6.tgz#4a8356dad9d0c1ab255607a555d492168e0e3bc1"
integrity sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==
dependencies:
immer "^10.0.3"
redux "^5.0.1"
redux-thunk "^3.1.0"
reselect "^5.1.0"
"@rollup/plugin-commonjs@24.0.0": "@rollup/plugin-commonjs@24.0.0":
version "24.0.0" version "24.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.0.tgz#fb7cf4a6029f07ec42b25daa535c75b05a43f75c" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.0.tgz#fb7cf4a6029f07ec42b25daa535c75b05a43f75c"
@@ -1437,6 +1638,11 @@
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
"@socket.io/component-emitter@~3.1.0":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2"
integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==
"@swc/helpers@0.5.2": "@swc/helpers@0.5.2":
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d" resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d"
@@ -1451,6 +1657,13 @@
dependencies: dependencies:
"@types/ms" "*" "@types/ms" "*"
"@types/debug@^4.1.12":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==
dependencies:
"@types/ms" "*"
"@types/estree@*", "@types/estree@^1.0.0": "@types/estree@*", "@types/estree@^1.0.0":
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194"
@@ -1521,6 +1734,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.5.tgz#9dc0a5cb1ccce4f7a731660935ab70b9c00a5d69" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.5.tgz#9dc0a5cb1ccce4f7a731660935ab70b9c00a5d69"
integrity sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg== integrity sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==
"@types/npm-events-package@npm:@types/events@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.3.tgz#a8ef894305af28d1fc6d2dfdfc98e899591ea529"
integrity sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==
"@types/parse-json@^4.0.0": "@types/parse-json@^4.0.0":
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
@@ -1566,6 +1784,11 @@
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.0.tgz#988ae8af1e5239e89f9fbb1ade4c935f4eeedf9a" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.0.tgz#988ae8af1e5239e89f9fbb1ade4c935f4eeedf9a"
integrity sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w== integrity sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w==
"@types/use-sync-external-store@^0.0.3":
version "0.0.3"
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
"@types/yargs-parser@*": "@types/yargs-parser@*":
version "21.0.0" version "21.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
@@ -1624,11 +1847,41 @@
"@typescript-eslint/types" "6.16.0" "@typescript-eslint/types" "6.16.0"
eslint-visitor-keys "^3.4.1" eslint-visitor-keys "^3.4.1"
"@ungap/create-content@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@ungap/create-content/-/create-content-0.2.0.tgz#f123a7c79f391d853600abf6dba44034a8ced58e"
integrity sha512-CvmX0Mr5PfFARDBbSef0B+SAqSeMKaHOG/twJi9nbPtp/MiNPgyBLqZndiyO3RXQ0RXy6TqwarvB6KWzTmc4MQ==
"@ungap/event@^0.2.2":
version "0.2.2"
resolved "https://registry.yarnpkg.com/@ungap/event/-/event-0.2.2.tgz#69d76a1e2c6c1cd4ec63455ee3f91082eb0c6f5e"
integrity sha512-31PwUE7asaFeXdRatnlsNYyfmO8xSEhsRAP+v7lm77hnn/oOjlpt7pJgc7C76LGlZjiEH9nGSx9vTc/5MZ6W7A==
"@ungap/import-node@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@ungap/import-node/-/import-node-0.2.0.tgz#5fd4b753a0ae52f6478f16ab669ddae461009135"
integrity sha512-VuWVBAMRjoOc63n8Cc19brS7KlhYJ+57790LF+lVw60nMRemCrz1T6HnoNx74IEW3FS+TM+vveJ70C6NyTKODQ==
"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": "@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0":
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
"@ungap/trim@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@ungap/trim/-/trim-0.2.0.tgz#71cc7998ef41a1b08ed94705c2f81f70c3cd2e10"
integrity sha512-CfsUxeZ2R/O3EGCOe+IkAU32yHOdO+mCRmtavSIQ4HZN3Jiq/ynGzq8/asyamd28U26UJmpSV/TC7+p7qELKrg==
"@ungap/weakmap@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@ungap/weakmap/-/weakmap-0.2.1.tgz#b690f139bb7aa97255182faff86777ca855c115d"
integrity sha512-GmVAWB+JuFKqSbzlofYK4qxk955gEv4Kd9/aj2hLOxneXMAm/J7OXcl5DlElS9tmkqwCcxGysSZGOrjzNvmjFQ==
"@ungap/weakset@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@ungap/weakset/-/weakset-0.2.1.tgz#4c7632241d1783b37ab07ac0866e8a9ee726a964"
integrity sha512-0tu3cD+yO4d5lGMC1DTAhIi29RZnP+tSfWc+T6WMvrMeNExO76iZ5eCciuiyUUIyBxqGDF4iNaeIXpYyJP+vcA==
"@vercel/edge-config-fs@0.1.0": "@vercel/edge-config-fs@0.1.0":
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/@vercel/edge-config-fs/-/edge-config-fs-0.1.0.tgz#cda8327f611418c1d1cbb28c6bed02d782be928b" resolved "https://registry.yarnpkg.com/@vercel/edge-config-fs/-/edge-config-fs-0.1.0.tgz#cda8327f611418c1d1cbb28c6bed02d782be928b"
@@ -1641,6 +1894,48 @@
dependencies: dependencies:
"@vercel/edge-config-fs" "0.1.0" "@vercel/edge-config-fs" "0.1.0"
"@whereby.com/browser-sdk@^3.3.4":
version "3.3.4"
resolved "https://registry.yarnpkg.com/@whereby.com/browser-sdk/-/browser-sdk-3.3.4.tgz#25b170bc2c6ea577ae4b2d7af54d70d1efa7a21d"
integrity sha512-sJfgXosf73E/TsiDc1bcnfom+po+74JD8hNcA0s46jG9jZ7pNBRq8oWrV4Qd/SEUtcWGoEuqgYjL0SImln824g==
dependencies:
"@radix-ui/react-popover" "^1.0.7"
"@reduxjs/toolkit" "^2.2.3"
"@whereby.com/core" "0.19.5"
clsx "^2.1.1"
heresy "^1.0.4"
react-redux "^9.1.1"
runes "^0.4.3"
"@whereby.com/core@0.19.5":
version "0.19.5"
resolved "https://registry.yarnpkg.com/@whereby.com/core/-/core-0.19.5.tgz#09b36962311cb717be1fcc3c8af6d124670409bd"
integrity sha512-vAsK8e/EpmS2dwWtknnZmfMgmbHLFOvuTOCOmiHwsz5yTImR1L9vsDLVkoF+ixpeY6v5fYBpU+eft5XB1E3qrw==
dependencies:
"@reduxjs/toolkit" "^2.2.3"
"@whereby.com/media" "1.6.5"
axios "^1.2.3"
btoa "^1.2.1"
events "^3.3.0"
"@whereby.com/media@1.6.5":
version "1.6.5"
resolved "https://registry.yarnpkg.com/@whereby.com/media/-/media-1.6.5.tgz#cfc3ac36b126523fe9d935532ffc1660451b85d5"
integrity sha512-q/+9+oiMU6WUNCDZjqPcYoVOA1fIeH2sqdQaW9qHCzf/hgmDuoaw95u9eeTiwoDHngW/LRcPLY9Q4tsEgm2jNg==
dependencies:
check-ip "^1.1.1"
events "^3.3.0"
ip-address "^9.0.5"
mediasoup-client "3.7.12"
rtcstats "github:whereby/rtcstats#5.4.0"
sdp "^3.2.0"
sdp-transform "^2.14.2"
socket.io-client "4.7.2"
typescript "^5.3.3"
uuid "^9.0.1"
uuid-validate "^0.0.3"
webrtc-adapter "^8.2.3"
"@zag-js/dom-query@0.16.0": "@zag-js/dom-query@0.16.0":
version "0.16.0" version "0.16.0"
resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-0.16.0.tgz#bca46bcd78f78c900064478646d95f9781ed098e" resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-0.16.0.tgz#bca46bcd78f78c900064478646d95f9781ed098e"
@@ -1732,6 +2027,13 @@ argparse@^2.0.1:
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
aria-hidden@^1.1.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.4.tgz#b78e383fdbc04d05762c78b4a25a501e736c4522"
integrity sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==
dependencies:
tslib "^2.0.0"
aria-hidden@^1.2.3: aria-hidden@^1.2.3:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954" resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954"
@@ -1847,6 +2149,14 @@ asynckit@^0.4.0:
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
augmentor@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/augmentor/-/augmentor-2.2.0.tgz#e639e0696d88a74caed840b5ee08671bab225a27"
integrity sha512-BEQAG1w74b794ec4FpWpu9AZZUZngKy5zGgb8OIhU2hcVhm8F5Y/VS0/3EAA+ExgtJDCTR+L2rvnjtIt2oo1xQ==
dependencies:
reraf "^1.1.1"
umap "^1.0.2"
autoprefixer@10.4.14: autoprefixer@10.4.14:
version "10.4.14" version "10.4.14"
resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz" resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz"
@@ -1864,11 +2174,27 @@ available-typed-arrays@^1.0.5:
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
awaitqueue@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/awaitqueue/-/awaitqueue-3.0.2.tgz#a37a212b137b784dc6bd701d1ecfa4a07ec89625"
integrity sha512-AVAtRwmf0DNSesMdyanFKKejTrOnjdKtz5LIDQFu2OTUgXvB/CRTYMrkPAF/2GCF9XBtYVxSwxDORlD41S+RyQ==
dependencies:
debug "^4.3.4"
axe-core@=4.7.0: axe-core@=4.7.0:
version "4.7.0" version "4.7.0"
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf"
integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==
axios@^1.2.3:
version "1.7.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621"
integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==
dependencies:
follow-redirects "^1.15.6"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
axios@^1.6.2: axios@^1.6.2:
version "1.6.2" version "1.6.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2"
@@ -1946,6 +2272,11 @@ browserslist@^4.21.5:
node-releases "^2.0.12" node-releases "^2.0.12"
update-browserslist-db "^1.0.11" update-browserslist-db "^1.0.11"
btoa@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73"
integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==
buffer@^6.0.3: buffer@^6.0.3:
version "6.0.3" version "6.0.3"
resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
@@ -2053,6 +2384,13 @@ character-entities@^2.0.0:
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22"
integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==
check-ip@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/check-ip/-/check-ip-1.1.1.tgz#77270efaa69a7853fec3709f143036a8e20e7ea6"
integrity sha512-LuLBA6r4aS/4B7pvOqmT4Bi+GKnNNC/V18K0zDTRFjAxNeUzGsr0wmsOfFhFH7fGjwdx6GX6wyIQBkUhFox2Pw==
dependencies:
ip-range-check "^0.0.2"
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: "chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3:
version "3.5.3" version "3.5.3"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"
@@ -2110,6 +2448,11 @@ client-only@0.0.1:
resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
clsx@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
color-convert@^1.9.0: color-convert@^1.9.0:
version "1.9.3" version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -2269,6 +2612,13 @@ debug@^3.2.7:
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"
debug@^4.3.5, debug@~4.3.1, debug@~4.3.2:
version "4.3.5"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
dependencies:
ms "2.1.2"
decode-named-character-reference@^1.0.0: decode-named-character-reference@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e"
@@ -2378,6 +2728,31 @@ dom-helpers@^5.0.1:
"@babel/runtime" "^7.8.7" "@babel/runtime" "^7.8.7"
csstype "^3.0.2" csstype "^3.0.2"
domconstants@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/domconstants/-/domconstants-0.1.2.tgz#cfb75c667e32ce69f9044b72cc31db2e06835815"
integrity sha512-sPOoOckTxtwy5t8PFf6zl11gOEhOpl1k0ZCc/NfCNmHoMw8n9HnCQCzxWKX9gdBp+qM+2DTFkst++Yw6C41izQ==
domsanitizer@^0.2.2, domsanitizer@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/domsanitizer/-/domsanitizer-0.2.3.tgz#5f7a045ba80227719388358c0f6b6549760d05ad"
integrity sha512-qglHc+5k5C2+WSEzck0WGbpa2exCKZuZKb0n4RU2Wuy7BPkpmf67mHD1BJWGxs0iJYl709f2YVeJMh06c1ILlA==
dependencies:
domconstants "^0.1.2"
domtagger@^0.7.1:
version "0.7.2"
resolved "https://registry.yarnpkg.com/domtagger/-/domtagger-0.7.2.tgz#48c91ec7af7a444239bf6922d47ffd52e49d2cb1"
integrity sha512-h7g5eduvnLwowJJPkcB5lNzo8vd/Hx4e3I4IOtLpX0qB2wBiuryGLNa61MeFre4b6gMaQIhegMIZ2I8rQCAJwQ==
dependencies:
"@ungap/create-content" "^0.2.0"
"@ungap/import-node" "^0.2.0"
"@ungap/trim" "^0.2.0"
"@ungap/weakmap" "^0.2.1"
domconstants "^0.1.2"
domsanitizer "^0.2.2"
umap "^1.0.2"
dotenv@^16.4.5: dotenv@^16.4.5:
version "16.4.5" version "16.4.5"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
@@ -2400,6 +2775,22 @@ encoding@^0.1.13:
dependencies: dependencies:
iconv-lite "^0.6.2" iconv-lite "^0.6.2"
engine.io-client@~6.5.2:
version "6.5.4"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.4.tgz#b8bc71ed3f25d0d51d587729262486b4b33bd0d0"
integrity sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
engine.io-parser "~5.2.1"
ws "~8.17.1"
xmlhttprequest-ssl "~2.0.0"
engine.io-parser@~5.2.1:
version "5.2.3"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f"
integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==
enhanced-resolve@^5.12.0: enhanced-resolve@^5.12.0:
version "5.15.0" version "5.15.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
@@ -2736,6 +3127,16 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
event-target-shim@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-6.0.2.tgz#ea5348c3618ee8b62ff1d344f01908ee2b8a2b71"
integrity sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA==
events@^3.3.0, "npm-events-package@npm:events@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
execa@^8.0.1: execa@^8.0.1:
version "8.0.1" version "8.0.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c"
@@ -2756,6 +3157,14 @@ extend@^3.0.0:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
fake-mediastreamtrack@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/fake-mediastreamtrack/-/fake-mediastreamtrack-1.2.0.tgz#11e6e0c50d36d3bc988461c034beb81debee548b"
integrity sha512-AxHtlEmka1sqNoe3Ej1H1hJc9gjjO/6vCbCPm4D4QeEXvzhjYumA+iZ7wOi2WrmkAhGElHhBgWoNgJhFccectA==
dependencies:
event-target-shim "^6.0.2"
uuid "^9.0.0"
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -2858,6 +3267,11 @@ follow-redirects@^1.15.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
follow-redirects@^1.15.6:
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
fontawesome@^5.6.3: fontawesome@^5.6.3:
version "5.6.3" version "5.6.3"
resolved "https://registry.npmjs.org/fontawesome/-/fontawesome-5.6.3.tgz" resolved "https://registry.npmjs.org/fontawesome/-/fontawesome-5.6.3.tgz"
@@ -3125,6 +3539,14 @@ graphemer@^1.4.0:
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
h264-profile-level-id@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/h264-profile-level-id/-/h264-profile-level-id-2.0.0.tgz#b7ea45badbac8f5dbb9583d34b06db09764f2535"
integrity sha512-X4CLryVbVA0CtjTExS4G5U1gb2Z4wa32AF8ukVmFuLdw2JRq2aHisor7SY5SYTUUrUSqq0KdPIO18sql6IWIQw==
dependencies:
"@types/debug" "^4.1.12"
debug "^4.3.4"
handlebars@4.7.8: handlebars@4.7.8:
version "4.7.8" version "4.7.8"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9"
@@ -3212,6 +3634,18 @@ hast-util-whitespace@^3.0.0:
dependencies: dependencies:
"@types/hast" "^3.0.0" "@types/hast" "^3.0.0"
heresy@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/heresy/-/heresy-1.0.4.tgz#45bb255379f9e9b32d32dfb0e693783f9d707565"
integrity sha512-2oLrI6lv2RXEXZPsNOTPffFdGPjpwCHrt1BZYLOBnEc7pv8fUJWdeVbLVcq9oLBpOYSy3dbP71jTRRCN5fGcuA==
dependencies:
"@ungap/event" "^0.2.2"
"@ungap/weakmap" "^0.2.1"
"@ungap/weakset" "^0.2.1"
augmentor "^2.2.0"
lighterhtml "^4.1.2"
uhyphen "^0.1.0"
hexoid@^1.0.0: hexoid@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
@@ -3242,6 +3676,11 @@ human-signals@^5.0.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28"
integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==
hyperhtml-style@^0.1.2:
version "0.1.3"
resolved "https://registry.yarnpkg.com/hyperhtml-style/-/hyperhtml-style-0.1.3.tgz#ba7f704741c6d2f84c4d67e6544c01ebbd3f21d3"
integrity sha512-IvLy8MzHTSJ0fDpSzrb8rcdnla6yROEmNBSxInEMyIFu2DQkbmpadTf6B4fHvnytN6iHL2gGwpe5/jHL3wMi+A==
iconv-lite@^0.6.2: iconv-lite@^0.6.2:
version "0.6.3" version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
@@ -3264,6 +3703,11 @@ immediate@~3.0.5:
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
immer@^10.0.3:
version "10.1.1"
resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc"
integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
immutable@^4.0.0: immutable@^4.0.0:
version "4.3.1" version "4.3.1"
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.1.tgz" resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.1.tgz"
@@ -3316,6 +3760,26 @@ invariant@^2.2.4:
dependencies: dependencies:
loose-envify "^1.0.0" loose-envify "^1.0.0"
ip-address@^9.0.5:
version "9.0.5"
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a"
integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==
dependencies:
jsbn "1.1.0"
sprintf-js "^1.1.3"
ip-range-check@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/ip-range-check/-/ip-range-check-0.0.2.tgz#605c859687aa4f18463918d46190d8b3699a293c"
integrity sha512-sHbyog8viObPK2vZFNYpBM/d2mqs51uuxOhB+0EIMSWmmrflAWne7CeXOWunb5R6bWQVOijbLx7bEY0sE05bug==
dependencies:
ipaddr.js "^1.0.1"
ipaddr.js@^1.0.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: is-array-buffer@^3.0.1, is-array-buffer@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe"
@@ -3579,6 +4043,11 @@ js-yaml@^4.1.0:
dependencies: dependencies:
argparse "^2.0.1" argparse "^2.0.1"
jsbn@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
json-buffer@3.0.1: json-buffer@3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
@@ -3650,6 +4119,21 @@ lie@3.1.1:
dependencies: dependencies:
immediate "~3.0.5" immediate "~3.0.5"
lighterhtml@^4.1.2:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lighterhtml/-/lighterhtml-4.2.0.tgz#2f7fc9071bdd82abbb8b101e187f904fcd364881"
integrity sha512-HAb+Ri17iT+vYmFtarlt45O63BltoJY/ltDZGhnf2A1s4kno2j6su5KiZAgYD4/5AjODYQqflSy9KJZFwL5VwQ==
dependencies:
"@ungap/create-content" "^0.2.0"
"@ungap/weakmap" "^0.2.1"
domsanitizer "^0.2.3"
domtagger "^0.7.1"
hyperhtml-style "^0.1.2"
udomdiff "^1.1.0"
uhandlers "^0.4.2"
umap "^1.0.2"
uwire "^1.1.0"
lilconfig@^2.0.5, lilconfig@^2.1.0: lilconfig@^2.0.5, lilconfig@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz" resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz"
@@ -3744,6 +4228,23 @@ mdast-util-to-string@^4.0.0:
dependencies: dependencies:
"@types/mdast" "^4.0.0" "@types/mdast" "^4.0.0"
mediasoup-client@3.7.12:
version "3.7.12"
resolved "https://registry.yarnpkg.com/mediasoup-client/-/mediasoup-client-3.7.12.tgz#7ea1bb5c644a7393698de62c23294e51a652cdfc"
integrity sha512-AuQ3tgKGGQf7AmzzQShHNdYKewhLDof4MDC3JTNLFKvqEGzAZDBGgRs+m1zRfqgsSlGcd9xaf79Z7hs+Wd/A3Q==
dependencies:
"@types/debug" "^4.1.12"
"@types/npm-events-package" "npm:@types/events@^3.0.3"
awaitqueue "^3.0.2"
debug "^4.3.5"
fake-mediastreamtrack "^1.2.0"
h264-profile-level-id "^2.0.0"
npm-events-package "npm:events@^3.3.0"
queue-microtask "^1.2.3"
sdp-transform "^2.14.2"
supports-color "^9.4.0"
ua-parser-js "^1.0.38"
memoize-one@^6.0.0: memoize-one@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
@@ -4583,6 +5084,14 @@ react-qr-code@^2.0.12:
prop-types "^15.8.1" prop-types "^15.8.1"
qr.js "0.0.0" qr.js "0.0.0"
react-redux@^9.1.1:
version "9.1.2"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.1.2.tgz#deba38c64c3403e9abd0c3fbeab69ffd9d8a7e4b"
integrity sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==
dependencies:
"@types/use-sync-external-store" "^0.0.3"
use-sync-external-store "^1.0.0"
react-remove-scroll-bar@^2.3.4: react-remove-scroll-bar@^2.3.4:
version "2.3.4" version "2.3.4"
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9"
@@ -4591,7 +5100,7 @@ react-remove-scroll-bar@^2.3.4:
react-style-singleton "^2.2.1" react-style-singleton "^2.2.1"
tslib "^2.0.0" tslib "^2.0.0"
react-remove-scroll@^2.5.6: react-remove-scroll@2.5.7, react-remove-scroll@^2.5.6:
version "2.5.7" version "2.5.7"
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz#15a1fd038e8497f65a695bf26a4a57970cac1ccb" resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz#15a1fd038e8497f65a695bf26a4a57970cac1ccb"
integrity sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA== integrity sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==
@@ -4671,6 +5180,16 @@ readdirp@~3.6.0:
dependencies: dependencies:
picomatch "^2.2.1" picomatch "^2.2.1"
redux-thunk@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3"
integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
redux@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b"
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
reflect.getprototypeof@^1.0.4: reflect.getprototypeof@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3"
@@ -4718,6 +5237,16 @@ remark-rehype@^11.0.0:
unified "^11.0.0" unified "^11.0.0"
vfile "^6.0.0" vfile "^6.0.0"
reraf@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/reraf/-/reraf-1.1.1.tgz#c75584660edd9b6ee3c31eeb694d938f529b7042"
integrity sha512-uwOsqdTxJAQCxqvJF4Kiz4orwO9B8OBJkGeW7/NWNirapPutgig/3xU3emruvfwUbb+t51V0zHtNw6d83RDlJQ==
reselect@^5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e"
integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==
resolve-from@^4.0.0: resolve-from@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
@@ -4765,6 +5294,10 @@ rollup@2.78.0:
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
"rtcstats@github:whereby/rtcstats#5.4.0":
version "5.4.0"
resolved "https://codeload.github.com/whereby/rtcstats/tar.gz/6f6623b4b53e9f6b41f530339793de227f34ea51"
run-parallel@^1.1.9: run-parallel@^1.1.9:
version "1.2.0" version "1.2.0"
resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
@@ -4772,6 +5305,11 @@ run-parallel@^1.1.9:
dependencies: dependencies:
queue-microtask "^1.2.2" queue-microtask "^1.2.2"
runes@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/runes/-/runes-0.4.3.tgz#32f7738844bc767b65cc68171528e3373c7bb355"
integrity sha512-K6p9y4ZyL9wPzA+PMDloNQPfoDGTiFYDvdlXznyGKgD10BJpcAosvATKrExRKOrNLgD8E7Um7WGW0lxsnOuNLg==
safe-array-concat@^1.0.1: safe-array-concat@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c"
@@ -4817,6 +5355,16 @@ scheduler@^0.23.0:
dependencies: dependencies:
loose-envify "^1.1.0" loose-envify "^1.1.0"
sdp-transform@^2.14.2:
version "2.14.2"
resolved "https://registry.yarnpkg.com/sdp-transform/-/sdp-transform-2.14.2.tgz#d2cee6a1f7abe44e6332ac6cbb94e8600f32d813"
integrity sha512-icY6jVao7MfKCieyo1AyxFYm1baiM+fA00qW/KrNNVlkxHAd34riEKuEkUe4bBb3gJwLJZM+xT60Yj1QL8rHiA==
sdp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/sdp/-/sdp-3.2.0.tgz#8961420552b36663b4d13ddba6f478d1461896a5"
integrity sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==
semver@^6.3.1: semver@^6.3.1:
version "6.3.1" version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
@@ -4892,6 +5440,24 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
socket.io-client@4.7.2:
version "4.7.2"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.2.tgz#f2f13f68058bd4e40f94f2a1541f275157ff2c08"
integrity sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.2"
engine.io-client "~6.5.2"
socket.io-parser "~4.2.4"
socket.io-parser@~4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
@@ -4912,6 +5478,11 @@ space-separated-tokens@^2.0.0:
resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f"
integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==
sprintf-js@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
stacktrace-parser@^0.1.10: stacktrace-parser@^0.1.10:
version "0.1.10" version "0.1.10"
resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a"
@@ -5277,6 +5848,26 @@ typescript@^5.1.6:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
typescript@^5.3.3:
version "5.5.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa"
integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==
ua-parser-js@^1.0.38:
version "1.0.38"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.38.tgz#66bb0c4c0e322fe48edfe6d446df6042e62f25e2"
integrity sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==
uarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/uarray/-/uarray-1.0.0.tgz#e89bf0ea2129596f4bf653b66e53246ed6562b6c"
integrity sha512-LHmiAd5QuAv7pU2vbh+Zq9YOnqVK0H764p2Ozinpfy9ka58OID4IsGLiXsitqH7n0NAIDxvax1A/kDXpii/Ckg==
udomdiff@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/udomdiff/-/udomdiff-1.1.0.tgz#1d0c4741b93a2ffd10728ca4cea15b277cc3082f"
integrity sha512-aqjTs5x/wsShZBkVagdafJkP8S3UMGhkHKszsu1cszjjZ7iOp86+Qb3QOFYh01oWjPMy5ZTuxD6hw5uTKxd+VA==
ufo@^1.5.3: ufo@^1.5.3:
version "1.5.3" version "1.5.3"
resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344"
@@ -5287,6 +5878,23 @@ uglify-js@^3.1.4:
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
uhandlers@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/uhandlers/-/uhandlers-0.4.2.tgz#3cda71eaf1bec63b079ddacc897a68a3b7f614b8"
integrity sha512-4M3yo0saEReMHiUz3yTDX/e9Z1Z+X8fVvDEywdjvWHPKqzpI6xEPJ21llrBf6Tvf7E5xaPCf9l5JXaYZRU7QRA==
dependencies:
uarray "^1.0.0"
uhyphen@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/uhyphen/-/uhyphen-0.1.0.tgz#3cc22afa790daa802b9f6789f3583108d5b4a08c"
integrity sha512-o0QVGuFg24FK765Qdd5kk0zU/U4dEsCtN/GSiwNI9i8xsSVtjIAOdTaVhLwZ1nrbWxFVMxNDDl+9fednsOMsBw==
umap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/umap/-/umap-1.0.2.tgz#2d7d4b145ad8c9f957921460798f3e221347c981"
integrity sha512-bW127HgG4H4VAD6qlqO5vCC+7bnlYvZ6A6BdwyGblkWvlEG7VYpj1bcpf3iJpvyKmkPZWDIeZDmoULz67ec7NA==
unbox-primitive@^1.0.2: unbox-primitive@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
@@ -5383,11 +5991,33 @@ use-sidecar@^1.1.2:
detect-node-es "^1.1.0" detect-node-es "^1.1.0"
tslib "^2.0.0" tslib "^2.0.0"
use-sync-external-store@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
util-deprecate@^1.0.1, util-deprecate@^1.0.2: util-deprecate@^1.0.1, util-deprecate@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
uuid-validate@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/uuid-validate/-/uuid-validate-0.0.3.tgz#e30617f75dc742a0e4f95012a11540faf9d39ab4"
integrity sha512-Fykw5U4eZESbq739BeLvEBFRuJODfrlmjx5eJux7W817LjRaq4b7/i4t2zxQmhcX+fAj4nMfRdTzO4tmwLKn0w==
uuid@^9.0.0, uuid@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
uwire@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/uwire/-/uwire-1.1.0.tgz#ae72a770a140311a0d640aebb21131a7934988ca"
integrity sha512-XJPmJnySabt8D0/wnfFFywgUOBnXszDEW32nEVIfOx1n6gLTZSp+X+70+blSnHKNiIUVSFPmmRuxOal0I/aB5g==
dependencies:
uarray "^1.0.0"
vfile-message@^4.0.0: vfile-message@^4.0.0:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181"
@@ -5428,6 +6058,13 @@ webidl-conversions@^3.0.0:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webrtc-adapter@^8.2.3:
version "8.2.3"
resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz#85e5e52ea68e808be8d6db85e338aa5c95e80022"
integrity sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==
dependencies:
sdp "^3.2.0"
whatwg-url@^5.0.0: whatwg-url@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
@@ -5503,6 +6140,16 @@ wrappy@1:
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
ws@~8.17.1:
version "8.17.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
xmlhttprequest-ssl@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==
yallist@^4.0.0: yallist@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"