From d2250be3b60a527d88db2b302663b61149c32a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 4 Mar 2026 15:56:57 +0100 Subject: [PATCH 1/2] Vibing example| --- conference-to-stream/.env.example | 14 + conference-to-stream/backend/Dockerfile | 12 + .../backend/fishjam/client.go | 181 ++ .../backend/fishjam/notifier.go | 171 + .../backend/foundry/client.go | 247 ++ conference-to-stream/backend/go.mod | 9 + conference-to-stream/backend/go.sum | 8 + .../backend/handler/handler.go | 247 ++ conference-to-stream/backend/main.go | 47 + .../proto/fishjam/notifications/shared.pb.go | 253 ++ .../proto/fishjam/server_notifications.pb.go | 2843 +++++++++++++++++ conference-to-stream/docker-compose.yml | 20 + conference-to-stream/web/.gitignore | 2 + conference-to-stream/web/Dockerfile | 11 + conference-to-stream/web/index.html | 12 + conference-to-stream/web/package-lock.json | 2522 +++++++++++++++ conference-to-stream/web/package.json | 25 + conference-to-stream/web/src/App.tsx | 26 + conference-to-stream/web/src/api.ts | 31 + .../web/src/components/Conference.tsx | 87 + .../web/src/components/JoinForm.tsx | 84 + .../web/src/components/PeerTile.tsx | 48 + .../web/src/components/WhepPlayer.tsx | 53 + conference-to-stream/web/src/index.css | 1 + conference-to-stream/web/src/main.tsx | 15 + conference-to-stream/web/src/vite-env.d.ts | 1 + conference-to-stream/web/src/whep.ts | 54 + conference-to-stream/web/tsconfig.json | 17 + conference-to-stream/web/tsconfig.tsbuildinfo | 1 + conference-to-stream/web/vite.config.ts | 7 + 30 files changed, 7049 insertions(+) create mode 100644 conference-to-stream/.env.example create mode 100644 conference-to-stream/backend/Dockerfile create mode 100644 conference-to-stream/backend/fishjam/client.go create mode 100644 conference-to-stream/backend/fishjam/notifier.go create mode 100644 conference-to-stream/backend/foundry/client.go create mode 100644 conference-to-stream/backend/go.mod create mode 100644 conference-to-stream/backend/go.sum create mode 100644 conference-to-stream/backend/handler/handler.go create mode 100644 conference-to-stream/backend/main.go create mode 100644 conference-to-stream/backend/proto/fishjam/notifications/shared.pb.go create mode 100644 conference-to-stream/backend/proto/fishjam/server_notifications.pb.go create mode 100644 conference-to-stream/docker-compose.yml create mode 100644 conference-to-stream/web/.gitignore create mode 100644 conference-to-stream/web/Dockerfile create mode 100644 conference-to-stream/web/index.html create mode 100644 conference-to-stream/web/package-lock.json create mode 100644 conference-to-stream/web/package.json create mode 100644 conference-to-stream/web/src/App.tsx create mode 100644 conference-to-stream/web/src/api.ts create mode 100644 conference-to-stream/web/src/components/Conference.tsx create mode 100644 conference-to-stream/web/src/components/JoinForm.tsx create mode 100644 conference-to-stream/web/src/components/PeerTile.tsx create mode 100644 conference-to-stream/web/src/components/WhepPlayer.tsx create mode 100644 conference-to-stream/web/src/index.css create mode 100644 conference-to-stream/web/src/main.tsx create mode 100644 conference-to-stream/web/src/vite-env.d.ts create mode 100644 conference-to-stream/web/src/whep.ts create mode 100644 conference-to-stream/web/tsconfig.json create mode 100644 conference-to-stream/web/tsconfig.tsbuildinfo create mode 100644 conference-to-stream/web/vite.config.ts diff --git a/conference-to-stream/.env.example b/conference-to-stream/.env.example new file mode 100644 index 0000000..044fba3 --- /dev/null +++ b/conference-to-stream/.env.example @@ -0,0 +1,14 @@ +# Fishjam ID or full URL (e.g. your-id or https://fishjam.io/api/v1/connect/your-id) +FISHJAM_ID=your-fishjam-id + +# Fishjam management token +FISHJAM_MANAGEMENT_TOKEN=your-management-token + +# Backend port (default: 8080) +PORT=8080 + +# Frontend: Fishjam ID passed to FishjamProvider +VITE_FISHJAM_ID=your-fishjam-id + +# Frontend: backend URL +VITE_BACKEND_URL=http://localhost:8080 diff --git a/conference-to-stream/backend/Dockerfile b/conference-to-stream/backend/Dockerfile new file mode 100644 index 0000000..968bb37 --- /dev/null +++ b/conference-to-stream/backend/Dockerfile @@ -0,0 +1,12 @@ +FROM golang:1.23-alpine AS builder +WORKDIR /app +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +RUN go build -o server . + +FROM alpine:3.20 +WORKDIR /app +COPY --from=builder /app/server . +EXPOSE 8080 +CMD ["./server"] diff --git a/conference-to-stream/backend/fishjam/client.go b/conference-to-stream/backend/fishjam/client.go new file mode 100644 index 0000000..239e76d --- /dev/null +++ b/conference-to-stream/backend/fishjam/client.go @@ -0,0 +1,181 @@ +package fishjam + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "net/url" + "strings" +) + +type Client struct { + baseURL string + managementToken string + httpClient *http.Client +} + +type RoomConfig struct { + RoomType string `json:"roomType,omitempty"` +} + +type Room struct { + ID string `json:"id"` + Config any `json:"config"` + Peers []Peer `json:"peers"` +} + +type Peer struct { + ID string `json:"id"` + Type string `json:"type"` +} + +type PeerConfig struct { + Type string `json:"type"` + Options PeerOptionsWeb `json:"options"` +} + +type PeerOptionsWeb struct { + Metadata map[string]string `json:"metadata,omitempty"` +} + +type TrackForwardingRequest struct { + CompositionURL string `json:"compositionURL"` + Selector string `json:"selector"` +} + +type createRoomResponse struct { + Data struct { + Room Room `json:"room"` + } `json:"data"` +} + +type createPeerResponse struct { + Data struct { + Peer Peer `json:"peer"` + Token string `json:"token"` + PeerWebsocketURL string `json:"peer_websocket_url"` + } `json:"data"` +} + +func NewClient(fishjamID, managementToken string) *Client { + baseURL := fishjamID + if _, err := url.ParseRequestURI(fishjamID); err != nil || !strings.HasPrefix(fishjamID, "http") { + baseURL = fmt.Sprintf("https://fishjam.io/api/v1/connect/%s", fishjamID) + } + baseURL = strings.TrimRight(baseURL, "/") + + return &Client{ + baseURL: baseURL, + managementToken: managementToken, + httpClient: &http.Client{}, + } +} + +func (c *Client) BaseURL() string { + return c.baseURL +} + +func (c *Client) ManagementToken() string { + return c.managementToken +} + +func (c *Client) CreateRoom() (*Room, error) { + body := RoomConfig{RoomType: "conference"} + resp, err := c.doJSON("POST", "/room", body) + if err != nil { + return nil, fmt.Errorf("create room: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusCreated { + return nil, readError(resp) + } + + var result createRoomResponse + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("decode create room response: %w", err) + } + return &result.Data.Room, nil +} + +func (c *Client) CreatePeer(roomID string, metadata map[string]string) (peerToken string, peerWebsocketURL string, err error) { + body := PeerConfig{ + Type: "webrtc", + Options: PeerOptionsWeb{Metadata: metadata}, + } + resp, err := c.doJSON("POST", fmt.Sprintf("/room/%s/peer", roomID), body) + if err != nil { + return "", "", fmt.Errorf("create peer: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusCreated { + return "", "", readError(resp) + } + + var result createPeerResponse + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", "", fmt.Errorf("decode create peer response: %w", err) + } + return result.Data.Token, result.Data.PeerWebsocketURL, nil +} + +func (c *Client) CreateTrackForwarding(roomID, compositionURL string) error { + body := TrackForwardingRequest{ + CompositionURL: compositionURL, + Selector: "all", + } + resp, err := c.doJSON("POST", fmt.Sprintf("/room/%s/track_forwardings", roomID), body) + if err != nil { + return fmt.Errorf("create track forwarding: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusCreated { + return readError(resp) + } + return nil +} + +func (c *Client) doJSON(method, path string, body any) (*http.Response, error) { + jsonBody, err := json.Marshal(body) + if err != nil { + log.Printf("fishjam: marshal error for %s %s: %v (body: %+v)", method, path, err, body) + return nil, fmt.Errorf("marshal request body: %w", err) + } + + fullURL := c.baseURL + path + log.Printf("fishjam: %s %s body=%s", method, fullURL, string(jsonBody)) + + req, err := http.NewRequest(method, fullURL, bytes.NewReader(jsonBody)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+c.managementToken) + + resp, err := c.httpClient.Do(req) + if err != nil { + log.Printf("fishjam: request error for %s %s: %v", method, fullURL, err) + return nil, err + } + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Printf("fishjam: failed to read response body for %s %s: %v", method, fullURL, err) + return nil, fmt.Errorf("read response body: %w", err) + } + resp.Body = io.NopCloser(bytes.NewReader(respBody)) + + log.Printf("fishjam: %s %s -> %d body=%s", method, fullURL, resp.StatusCode, string(respBody)) + + return resp, nil +} + +func readError(resp *http.Response) error { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body)) +} diff --git a/conference-to-stream/backend/fishjam/notifier.go b/conference-to-stream/backend/fishjam/notifier.go new file mode 100644 index 0000000..e14bdb5 --- /dev/null +++ b/conference-to-stream/backend/fishjam/notifier.go @@ -0,0 +1,171 @@ +package fishjam + +import ( + "fmt" + "log" + "net/url" + "strings" + + pb "conference-to-stream/proto/fishjam" + + "github.com/gorilla/websocket" + "google.golang.org/protobuf/proto" +) + +type TrackForwardingEvent struct { + RoomID string + PeerID string + CompositionURL string + InputID string +} + +type NotifierCallbacks struct { + OnTrackForwarding func(TrackForwardingEvent) + OnTrackForwardingRemoved func(TrackForwardingEvent) +} + +type Notifier struct { + conn *websocket.Conn + callbacks NotifierCallbacks + done chan struct{} +} + +func NewNotifier(fishjamBaseURL, managementToken string, callbacks NotifierCallbacks) (*Notifier, error) { + wsURL := httpToWebsocket(fishjamBaseURL) + "/socket/server/websocket" + + conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil) + if err != nil { + return nil, fmt.Errorf("dial fishjam ws: %w", err) + } + + n := &Notifier{ + conn: conn, + callbacks: callbacks, + done: make(chan struct{}), + } + + if err := n.authenticate(managementToken); err != nil { + conn.Close() + return nil, fmt.Errorf("authenticate: %w", err) + } + + if err := n.subscribe(); err != nil { + conn.Close() + return nil, fmt.Errorf("subscribe: %w", err) + } + + go n.listen() + + return n, nil +} + +func (n *Notifier) Close() { + n.conn.Close() + <-n.done +} + +func (n *Notifier) authenticate(token string) error { + msg := &pb.ServerMessage{ + Content: &pb.ServerMessage_AuthRequest_{ + AuthRequest: &pb.ServerMessage_AuthRequest{ + Token: token, + }, + }, + } + return n.sendProto(msg) +} + +func (n *Notifier) subscribe() error { + msg := &pb.ServerMessage{ + Content: &pb.ServerMessage_SubscribeRequest_{ + SubscribeRequest: &pb.ServerMessage_SubscribeRequest{ + EventType: pb.ServerMessage_EVENT_TYPE_SERVER_NOTIFICATION, + }, + }, + } + return n.sendProto(msg) +} + +func (n *Notifier) sendProto(msg *pb.ServerMessage) error { + data, err := proto.Marshal(msg) + if err != nil { + return fmt.Errorf("marshal proto: %w", err) + } + return n.conn.WriteMessage(websocket.BinaryMessage, data) +} + +func (n *Notifier) listen() { + defer close(n.done) + + for { + _, data, err := n.conn.ReadMessage() + if err != nil { + if websocket.IsCloseError(err, websocket.CloseNormalClosure) { + return + } + log.Printf("ws read error: %v", err) + return + } + + var msg pb.ServerMessage + if err := proto.Unmarshal(data, &msg); err != nil { + log.Printf("unmarshal ws message: %v", err) + continue + } + + n.dispatch(&msg) + } +} + +func (n *Notifier) dispatch(msg *pb.ServerMessage) { + switch content := msg.Content.(type) { + case *pb.ServerMessage_Authenticated_: + log.Println("fishjam: authenticated") + case *pb.ServerMessage_SubscribeResponse_: + log.Println("fishjam: subscribed to notifications") + case *pb.ServerMessage_TrackForwarding_: + tf := content.TrackForwarding + log.Printf("fishjam: track forwarding - room=%s peer=%s input=%s", tf.RoomId, tf.PeerId, tf.InputId) + if n.callbacks.OnTrackForwarding != nil { + n.callbacks.OnTrackForwarding(TrackForwardingEvent{ + RoomID: tf.RoomId, + PeerID: tf.PeerId, + CompositionURL: tf.CompositionUrl, + InputID: tf.InputId, + }) + } + case *pb.ServerMessage_TrackForwardingRemoved_: + tf := content.TrackForwardingRemoved + log.Printf("fishjam: track forwarding removed - room=%s peer=%s input=%s", tf.RoomId, tf.PeerId, tf.InputId) + if n.callbacks.OnTrackForwardingRemoved != nil { + n.callbacks.OnTrackForwardingRemoved(TrackForwardingEvent{ + RoomID: tf.RoomId, + PeerID: tf.PeerId, + CompositionURL: tf.CompositionUrl, + InputID: tf.InputId, + }) + } + case *pb.ServerMessage_PeerConnected_: + log.Printf("fishjam: peer connected - room=%s peer=%s", + content.PeerConnected.RoomId, content.PeerConnected.PeerId) + case *pb.ServerMessage_PeerDisconnected_: + log.Printf("fishjam: peer disconnected - room=%s peer=%s", + content.PeerDisconnected.RoomId, content.PeerDisconnected.PeerId) + default: + // Ignore other notification types + } +} + +func httpToWebsocket(httpURL string) string { + u, err := url.Parse(httpURL) + if err != nil { + return strings.Replace(strings.Replace(httpURL, "https://", "wss://", 1), "http://", "ws://", 1) + } + switch u.Scheme { + case "https": + u.Scheme = "wss" + case "http": + u.Scheme = "ws" + } + return u.String() +} diff --git a/conference-to-stream/backend/foundry/client.go b/conference-to-stream/backend/foundry/client.go new file mode 100644 index 0000000..0bbb487 --- /dev/null +++ b/conference-to-stream/backend/foundry/client.go @@ -0,0 +1,247 @@ +package foundry + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "net/http" +) + +const compositionBaseURL = "https://rtc.fishjam.io/api/composition" + +type Client struct { + httpClient *http.Client +} + +type createCompositionResponse struct { + CompositionURL string `json:"composition_url"` +} + +// Scene component types for JSON marshaling + +type inputStream struct { + Type string `json:"type"` + InputID string `json:"input_id"` +} + +type tilesComponent struct { + Type string `json:"type"` + BackgroundColor string `json:"background_color"` + TileAspectRatio string `json:"tile_aspect_ratio"` + Children []inputStream `json:"children"` +} + +type viewComponent struct { + Type string `json:"type"` +} + +type audioInput struct { + InputID string `json:"input_id"` + Volume float64 `json:"volume"` +} + +type videoEncoder struct { + Type string `json:"type"` + Preset string `json:"preset"` +} + +type videoResolution struct { + Width int `json:"width"` + Height int `json:"height"` +} + +type initialVideo struct { + Root any `json:"root"` +} + +type videoConfig struct { + Resolution videoResolution `json:"resolution"` + Encoder videoEncoder `json:"encoder"` + Initial initialVideo `json:"initial"` +} + +type audioEncoder struct { + Type string `json:"type"` +} + +type initialAudio struct { + Inputs []audioInput `json:"inputs"` +} + +type audioConfig struct { + Encoder audioEncoder `json:"encoder"` + Channels string `json:"channels"` + Initial initialAudio `json:"initial"` +} + +type registerOutputRequest struct { + Type string `json:"type"` + Video videoConfig `json:"video"` + Audio audioConfig `json:"audio"` +} + +type updateVideoScene struct { + Root any `json:"root"` +} + +type updateAudioScene struct { + Inputs []audioInput `json:"inputs"` +} + +type updateOutputRequest struct { + Video updateVideoScene `json:"video"` + Audio updateAudioScene `json:"audio"` +} + +func NewClient() *Client { + return &Client{httpClient: &http.Client{}} +} + +func (c *Client) CreateComposition() (string, error) { + resp, err := c.httpClient.Post(compositionBaseURL, "application/json", bytes.NewBufferString("{}")) + if err != nil { + return "", fmt.Errorf("create composition: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK { + return "", readError(resp) + } + + var result createCompositionResponse + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", fmt.Errorf("decode composition response: %w", err) + } + return result.CompositionURL, nil +} + +func (c *Client) Start(compositionURL string) error { + resp, err := c.doJSON(compositionURL+"/start", nil) + if err != nil { + return fmt.Errorf("start composition: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + return readError(resp) + } + return nil +} + +func (c *Client) RegisterWhepOutput(compositionURL, outputID string) error { + body := registerOutputRequest{ + Type: "whep_server", + Video: videoConfig{ + Resolution: videoResolution{Width: 640, Height: 360}, + Encoder: videoEncoder{Type: "ffmpeg_h264", Preset: "ultrafast"}, + Initial: initialVideo{Root: viewComponent{Type: "view"}}, + }, + Audio: audioConfig{ + Encoder: audioEncoder{Type: "opus"}, + Channels: "stereo", + Initial: initialAudio{Inputs: []audioInput{}}, + }, + } + + url := fmt.Sprintf("%s/output/%s/register", compositionURL, outputID) + resp, err := c.doJSON(url, body) + if err != nil { + return fmt.Errorf("register whep output: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return readError(resp) + } + return nil +} + +func (c *Client) UpdateOutput(compositionURL, outputID string, inputIDs []string) error { + children := make([]inputStream, 0, len(inputIDs)) + audioInputs := make([]audioInput, 0, len(inputIDs)) + + for _, id := range inputIDs { + children = append(children, inputStream{Type: "input_stream", InputID: id}) + audioInputs = append(audioInputs, audioInput{InputID: id, Volume: 1.0}) + } + + var videoRoot any + if len(children) == 0 { + videoRoot = viewComponent{Type: "view"} + } else { + videoRoot = tilesComponent{ + Type: "tiles", + BackgroundColor: "#000000FF", + TileAspectRatio: "16:9", + Children: children, + } + } + + body := updateOutputRequest{ + Video: updateVideoScene{Root: videoRoot}, + Audio: updateAudioScene{Inputs: audioInputs}, + } + + url := fmt.Sprintf("%s/output/%s/update", compositionURL, outputID) + resp, err := c.doJSON(url, body) + if err != nil { + return fmt.Errorf("update output: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + return readError(resp) + } + + return nil +} + +func (c *Client) WhepURL(compositionURL, outputID string) string { + return fmt.Sprintf("%s/whep/%s", compositionURL, outputID) +} + +func (c *Client) doJSON(url string, body any) (*http.Response, error) { + var jsonBytes []byte + if body != nil { + var err error + jsonBytes, err = json.Marshal(body) + if err != nil { + log.Printf("foundry: marshal error for %s: %v (body: %+v)", url, err, body) + return nil, fmt.Errorf("marshal request body: %w", err) + } + } else { + jsonBytes = []byte("{}") + } + + log.Printf("foundry: POST %s body=%s", url, string(jsonBytes)) + + req, err := http.NewRequest("POST", url, bytes.NewReader(jsonBytes)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := c.httpClient.Do(req) + if err != nil { + log.Printf("foundry: request error for %s: %v", url, err) + return nil, err + } + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Printf("foundry: failed to read response body for %s: %v", url, err) + return nil, fmt.Errorf("read response body: %w", err) + } + resp.Body = io.NopCloser(bytes.NewReader(respBody)) + + log.Printf("foundry: POST %s -> %d body=%s", url, resp.StatusCode, string(respBody)) + + return resp, nil +} + +func readError(resp *http.Response) error { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body)) +} diff --git a/conference-to-stream/backend/go.mod b/conference-to-stream/backend/go.mod new file mode 100644 index 0000000..5e60108 --- /dev/null +++ b/conference-to-stream/backend/go.mod @@ -0,0 +1,9 @@ +module conference-to-stream + +go 1.24.5 + +require ( + github.com/gorilla/websocket v1.5.3 + github.com/rs/cors v1.11.1 + google.golang.org/protobuf v1.36.11 +) diff --git a/conference-to-stream/backend/go.sum b/conference-to-stream/backend/go.sum new file mode 100644 index 0000000..798dbc0 --- /dev/null +++ b/conference-to-stream/backend/go.sum @@ -0,0 +1,8 @@ +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= diff --git a/conference-to-stream/backend/handler/handler.go b/conference-to-stream/backend/handler/handler.go new file mode 100644 index 0000000..a813cab --- /dev/null +++ b/conference-to-stream/backend/handler/handler.go @@ -0,0 +1,247 @@ +package handler + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "strings" + "sync" + + "conference-to-stream/fishjam" + "conference-to-stream/foundry" +) + +const whepOutputID = "whep_output" + +type RoomState struct { + RoomID string + CompositionURL string + InputIDs map[string]string // input_id → peer_id + WhepURL string + mu sync.Mutex +} + +type Handler struct { + fishjamClient *fishjam.Client + foundryClient *foundry.Client + managementToken string + + mu sync.Mutex + rooms map[string]*RoomState // room_name → state +} + +func New(fishjamClient *fishjam.Client, foundryClient *foundry.Client) *Handler { + return &Handler{ + fishjamClient: fishjamClient, + foundryClient: foundryClient, + managementToken: fishjamClient.ManagementToken(), + rooms: make(map[string]*RoomState), + } +} + +type createRoomRequest struct { + RoomName string `json:"roomName"` +} + +type createRoomResponse struct { + RoomID string `json:"roomId"` + WhepURL string `json:"whepUrl"` +} + +type createPeerRequest struct { + PeerName string `json:"peerName"` +} + +type createPeerResponse struct { + PeerToken string `json:"peerToken"` + PeerWebsocketURL string `json:"peerWebsocketUrl"` +} + +func (h *Handler) CreateRoom(w http.ResponseWriter, r *http.Request) { + var req createRoomRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + if req.RoomName == "" { + http.Error(w, "roomName is required", http.StatusBadRequest) + return + } + + // Return existing room if already created + h.mu.Lock() + if state, ok := h.rooms[req.RoomName]; ok { + h.mu.Unlock() + writeJSON(w, createRoomResponse{RoomID: state.RoomID, WhepURL: state.WhepURL}) + return + } + h.mu.Unlock() + + // Create composition + compositionURL, err := h.foundryClient.CreateComposition() + if err != nil { + log.Printf("create composition: %v", err) + http.Error(w, "failed to create composition", http.StatusInternalServerError) + return + } + log.Printf("created composition: %s", compositionURL) + + // Start composition + if err := h.foundryClient.Start(compositionURL); err != nil { + log.Printf("start composition: %v", err) + http.Error(w, "failed to start composition", http.StatusInternalServerError) + return + } + + // Register WHEP output + if err := h.foundryClient.RegisterWhepOutput(compositionURL, whepOutputID); err != nil { + log.Printf("register whep output: %v", err) + http.Error(w, "failed to register WHEP output", http.StatusInternalServerError) + return + } + + // Create Fishjam room + room, err := h.fishjamClient.CreateRoom() + if err != nil { + log.Printf("create room: %v", err) + http.Error(w, "failed to create room", http.StatusInternalServerError) + return + } + log.Printf("created room: %s", room.ID) + + // Add track forwarding + if err := h.fishjamClient.CreateTrackForwarding(room.ID, compositionURL); err != nil { + log.Printf("create track forwarding: %v", err) + http.Error(w, "failed to create track forwarding", http.StatusInternalServerError) + return + } + + whepURL := h.foundryClient.WhepURL(compositionURL, whepOutputID) + + state := &RoomState{ + RoomID: room.ID, + CompositionURL: compositionURL, + InputIDs: make(map[string]string), + WhepURL: whepURL, + } + + h.mu.Lock() + h.rooms[req.RoomName] = state + h.mu.Unlock() + + // Start WS notifier for this room + fishjamBaseURL := h.fishjamClient.BaseURL() + _, err = fishjam.NewNotifier(fishjamBaseURL, h.managementToken, fishjam.NotifierCallbacks{ + OnTrackForwarding: func(event fishjam.TrackForwardingEvent) { + if event.RoomID != room.ID { + return + } + state.mu.Lock() + state.InputIDs[event.InputID] = event.PeerID + inputIDs := collectKeys(state.InputIDs) + state.mu.Unlock() + + log.Printf("track forwarding: room=%s peer=%s input=%s (total=%d)", event.RoomID, event.PeerID, event.InputID, len(inputIDs)) + if err := h.foundryClient.UpdateOutput(compositionURL, whepOutputID, inputIDs); err != nil { + log.Printf("update output: %v", err) + } + }, + OnTrackForwardingRemoved: func(event fishjam.TrackForwardingEvent) { + if event.RoomID != room.ID { + return + } + state.mu.Lock() + delete(state.InputIDs, event.InputID) + inputIDs := collectKeys(state.InputIDs) + state.mu.Unlock() + + log.Printf("track forwarding removed: room=%s peer=%s input=%s (total=%d)", event.RoomID, event.PeerID, event.InputID, len(inputIDs)) + if err := h.foundryClient.UpdateOutput(compositionURL, whepOutputID, inputIDs); err != nil { + log.Printf("update output: %v", err) + } + }, + }) + if err != nil { + log.Printf("start notifier: %v", err) + http.Error(w, "failed to start notifier", http.StatusInternalServerError) + return + } + + writeJSON(w, createRoomResponse{RoomID: room.ID, WhepURL: whepURL}) +} + +func (h *Handler) CreatePeer(w http.ResponseWriter, r *http.Request) { + roomID := roomIDFromPath(r.URL.Path) + if roomID == "" { + http.Error(w, "room ID required", http.StatusBadRequest) + return + } + + var req createPeerRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + metadata := map[string]string{} + if req.PeerName != "" { + metadata["name"] = req.PeerName + } + + peerToken, peerWebsocketURL, err := h.fishjamClient.CreatePeer(roomID, metadata) + if err != nil { + log.Printf("create peer: %v", err) + http.Error(w, "failed to create peer", http.StatusInternalServerError) + return + } + + writeJSON(w, createPeerResponse{ + PeerToken: peerToken, + PeerWebsocketURL: peerWebsocketURL, + }) +} + +func writeJSON(w http.ResponseWriter, v any) { + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(v); err != nil { + log.Printf("encode response: %v", err) + } +} + +// roomIDFromPath extracts room ID from /api/rooms/{roomId}/peers +func roomIDFromPath(path string) string { + parts := strings.Split(strings.Trim(path, "/"), "/") + // Expected: ["api", "rooms", "", "peers"] + if len(parts) >= 3 { + return parts[2] + } + return "" +} + +func collectKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + return keys +} + +// Route registers routes on the given mux +func (h *Handler) Route(mux *http.ServeMux) { + mux.HandleFunc("/api/rooms", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, fmt.Sprintf("method %s not allowed", r.Method), http.StatusMethodNotAllowed) + return + } + h.CreateRoom(w, r) + }) + + mux.HandleFunc("/api/rooms/", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, fmt.Sprintf("method %s not allowed", r.Method), http.StatusMethodNotAllowed) + return + } + h.CreatePeer(w, r) + }) +} diff --git a/conference-to-stream/backend/main.go b/conference-to-stream/backend/main.go new file mode 100644 index 0000000..ca63449 --- /dev/null +++ b/conference-to-stream/backend/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "log" + "net/http" + "os" + + "conference-to-stream/fishjam" + "conference-to-stream/foundry" + "conference-to-stream/handler" + + "github.com/rs/cors" +) + +func main() { + fishjamID := os.Getenv("FISHJAM_ID") + if fishjamID == "" { + log.Fatal("FISHJAM_ID is required") + } + managementToken := os.Getenv("FISHJAM_MANAGEMENT_TOKEN") + if managementToken == "" { + log.Fatal("FISHJAM_MANAGEMENT_TOKEN is required") + } + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + + fishjamClient := fishjam.NewClient(fishjamID, managementToken) + foundryClient := foundry.NewClient() + h := handler.New(fishjamClient, foundryClient) + + mux := http.NewServeMux() + h.Route(mux) + + c := cors.New(cors.Options{ + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{"GET", "POST", "OPTIONS"}, + AllowedHeaders: []string{"Content-Type", "Authorization"}, + }) + + addr := ":" + port + log.Printf("starting server on %s", addr) + if err := http.ListenAndServe(addr, c.Handler(mux)); err != nil { + log.Fatal(err) + } +} diff --git a/conference-to-stream/backend/proto/fishjam/notifications/shared.pb.go b/conference-to-stream/backend/proto/fishjam/notifications/shared.pb.go new file mode 100644 index 0000000..e654f9f --- /dev/null +++ b/conference-to-stream/backend/proto/fishjam/notifications/shared.pb.go @@ -0,0 +1,253 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v6.33.1 +// source: fishjam/notifications/shared.proto + +package notifications + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Defines types of tracks being published by peers and component +type TrackType int32 + +const ( + TrackType_TRACK_TYPE_UNSPECIFIED TrackType = 0 + TrackType_TRACK_TYPE_VIDEO TrackType = 1 + TrackType_TRACK_TYPE_AUDIO TrackType = 2 +) + +// Enum value maps for TrackType. +var ( + TrackType_name = map[int32]string{ + 0: "TRACK_TYPE_UNSPECIFIED", + 1: "TRACK_TYPE_VIDEO", + 2: "TRACK_TYPE_AUDIO", + } + TrackType_value = map[string]int32{ + "TRACK_TYPE_UNSPECIFIED": 0, + "TRACK_TYPE_VIDEO": 1, + "TRACK_TYPE_AUDIO": 2, + } +) + +func (x TrackType) Enum() *TrackType { + p := new(TrackType) + *p = x + return p +} + +func (x TrackType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TrackType) Descriptor() protoreflect.EnumDescriptor { + return file_fishjam_notifications_shared_proto_enumTypes[0].Descriptor() +} + +func (TrackType) Type() protoreflect.EnumType { + return &file_fishjam_notifications_shared_proto_enumTypes[0] +} + +func (x TrackType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TrackType.Descriptor instead. +func (TrackType) EnumDescriptor() ([]byte, []int) { + return file_fishjam_notifications_shared_proto_rawDescGZIP(), []int{0} +} + +type TrackEncoding int32 + +const ( + TrackEncoding_TRACK_ENCODING_UNSPECIFIED TrackEncoding = 0 + TrackEncoding_TRACK_ENCODING_PCM16 TrackEncoding = 1 + TrackEncoding_TRACK_ENCODING_OPUS TrackEncoding = 2 +) + +// Enum value maps for TrackEncoding. +var ( + TrackEncoding_name = map[int32]string{ + 0: "TRACK_ENCODING_UNSPECIFIED", + 1: "TRACK_ENCODING_PCM16", + 2: "TRACK_ENCODING_OPUS", + } + TrackEncoding_value = map[string]int32{ + "TRACK_ENCODING_UNSPECIFIED": 0, + "TRACK_ENCODING_PCM16": 1, + "TRACK_ENCODING_OPUS": 2, + } +) + +func (x TrackEncoding) Enum() *TrackEncoding { + p := new(TrackEncoding) + *p = x + return p +} + +func (x TrackEncoding) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TrackEncoding) Descriptor() protoreflect.EnumDescriptor { + return file_fishjam_notifications_shared_proto_enumTypes[1].Descriptor() +} + +func (TrackEncoding) Type() protoreflect.EnumType { + return &file_fishjam_notifications_shared_proto_enumTypes[1] +} + +func (x TrackEncoding) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TrackEncoding.Descriptor instead. +func (TrackEncoding) EnumDescriptor() ([]byte, []int) { + return file_fishjam_notifications_shared_proto_rawDescGZIP(), []int{1} +} + +// Describes a media track +type Track struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Type TrackType `protobuf:"varint,2,opt,name=type,proto3,enum=fishjam.notifications.TrackType" json:"type,omitempty"` + Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Track) Reset() { + *x = Track{} + mi := &file_fishjam_notifications_shared_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Track) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Track) ProtoMessage() {} + +func (x *Track) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_notifications_shared_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Track.ProtoReflect.Descriptor instead. +func (*Track) Descriptor() ([]byte, []int) { + return file_fishjam_notifications_shared_proto_rawDescGZIP(), []int{0} +} + +func (x *Track) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Track) GetType() TrackType { + if x != nil { + return x.Type + } + return TrackType_TRACK_TYPE_UNSPECIFIED +} + +func (x *Track) GetMetadata() string { + if x != nil { + return x.Metadata + } + return "" +} + +var File_fishjam_notifications_shared_proto protoreflect.FileDescriptor + +const file_fishjam_notifications_shared_proto_rawDesc = "" + + "\n" + + "\"fishjam/notifications/shared.proto\x12\x15fishjam.notifications\"i\n" + + "\x05Track\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x124\n" + + "\x04type\x18\x02 \x01(\x0e2 .fishjam.notifications.TrackTypeR\x04type\x12\x1a\n" + + "\bmetadata\x18\x03 \x01(\tR\bmetadata*S\n" + + "\tTrackType\x12\x1a\n" + + "\x16TRACK_TYPE_UNSPECIFIED\x10\x00\x12\x14\n" + + "\x10TRACK_TYPE_VIDEO\x10\x01\x12\x14\n" + + "\x10TRACK_TYPE_AUDIO\x10\x02*b\n" + + "\rTrackEncoding\x12\x1e\n" + + "\x1aTRACK_ENCODING_UNSPECIFIED\x10\x00\x12\x18\n" + + "\x14TRACK_ENCODING_PCM16\x10\x01\x12\x17\n" + + "\x13TRACK_ENCODING_OPUS\x10\x02b\x06proto3" + +var ( + file_fishjam_notifications_shared_proto_rawDescOnce sync.Once + file_fishjam_notifications_shared_proto_rawDescData []byte +) + +func file_fishjam_notifications_shared_proto_rawDescGZIP() []byte { + file_fishjam_notifications_shared_proto_rawDescOnce.Do(func() { + file_fishjam_notifications_shared_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_fishjam_notifications_shared_proto_rawDesc), len(file_fishjam_notifications_shared_proto_rawDesc))) + }) + return file_fishjam_notifications_shared_proto_rawDescData +} + +var file_fishjam_notifications_shared_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_fishjam_notifications_shared_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_fishjam_notifications_shared_proto_goTypes = []any{ + (TrackType)(0), // 0: fishjam.notifications.TrackType + (TrackEncoding)(0), // 1: fishjam.notifications.TrackEncoding + (*Track)(nil), // 2: fishjam.notifications.Track +} +var file_fishjam_notifications_shared_proto_depIdxs = []int32{ + 0, // 0: fishjam.notifications.Track.type:type_name -> fishjam.notifications.TrackType + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_fishjam_notifications_shared_proto_init() } +func file_fishjam_notifications_shared_proto_init() { + if File_fishjam_notifications_shared_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_fishjam_notifications_shared_proto_rawDesc), len(file_fishjam_notifications_shared_proto_rawDesc)), + NumEnums: 2, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_fishjam_notifications_shared_proto_goTypes, + DependencyIndexes: file_fishjam_notifications_shared_proto_depIdxs, + EnumInfos: file_fishjam_notifications_shared_proto_enumTypes, + MessageInfos: file_fishjam_notifications_shared_proto_msgTypes, + }.Build() + File_fishjam_notifications_shared_proto = out.File + file_fishjam_notifications_shared_proto_goTypes = nil + file_fishjam_notifications_shared_proto_depIdxs = nil +} diff --git a/conference-to-stream/backend/proto/fishjam/server_notifications.pb.go b/conference-to-stream/backend/proto/fishjam/server_notifications.pb.go new file mode 100644 index 0000000..1cbb40c --- /dev/null +++ b/conference-to-stream/backend/proto/fishjam/server_notifications.pb.go @@ -0,0 +1,2843 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v6.33.1 +// source: fishjam/server_notifications.proto + +package fishjam + +import ( + notifications "conference-to-stream/proto/fishjam/notifications" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ServerMessage_PeerType int32 + +const ( + ServerMessage_PEER_TYPE_UNSPECIFIED ServerMessage_PeerType = 0 + ServerMessage_PEER_TYPE_WEBRTC ServerMessage_PeerType = 1 + ServerMessage_PEER_TYPE_AGENT ServerMessage_PeerType = 2 +) + +// Enum value maps for ServerMessage_PeerType. +var ( + ServerMessage_PeerType_name = map[int32]string{ + 0: "PEER_TYPE_UNSPECIFIED", + 1: "PEER_TYPE_WEBRTC", + 2: "PEER_TYPE_AGENT", + } + ServerMessage_PeerType_value = map[string]int32{ + "PEER_TYPE_UNSPECIFIED": 0, + "PEER_TYPE_WEBRTC": 1, + "PEER_TYPE_AGENT": 2, + } +) + +func (x ServerMessage_PeerType) Enum() *ServerMessage_PeerType { + p := new(ServerMessage_PeerType) + *p = x + return p +} + +func (x ServerMessage_PeerType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServerMessage_PeerType) Descriptor() protoreflect.EnumDescriptor { + return file_fishjam_server_notifications_proto_enumTypes[0].Descriptor() +} + +func (ServerMessage_PeerType) Type() protoreflect.EnumType { + return &file_fishjam_server_notifications_proto_enumTypes[0] +} + +func (x ServerMessage_PeerType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ServerMessage_PeerType.Descriptor instead. +func (ServerMessage_PeerType) EnumDescriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 0} +} + +// Defines message groups for which peer can subscribe +type ServerMessage_EventType int32 + +const ( + ServerMessage_EVENT_TYPE_UNSPECIFIED ServerMessage_EventType = 0 + ServerMessage_EVENT_TYPE_SERVER_NOTIFICATION ServerMessage_EventType = 1 +) + +// Enum value maps for ServerMessage_EventType. +var ( + ServerMessage_EventType_name = map[int32]string{ + 0: "EVENT_TYPE_UNSPECIFIED", + 1: "EVENT_TYPE_SERVER_NOTIFICATION", + } + ServerMessage_EventType_value = map[string]int32{ + "EVENT_TYPE_UNSPECIFIED": 0, + "EVENT_TYPE_SERVER_NOTIFICATION": 1, + } +) + +func (x ServerMessage_EventType) Enum() *ServerMessage_EventType { + p := new(ServerMessage_EventType) + *p = x + return p +} + +func (x ServerMessage_EventType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServerMessage_EventType) Descriptor() protoreflect.EnumDescriptor { + return file_fishjam_server_notifications_proto_enumTypes[1].Descriptor() +} + +func (ServerMessage_EventType) Type() protoreflect.EnumType { + return &file_fishjam_server_notifications_proto_enumTypes[1] +} + +func (x ServerMessage_EventType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ServerMessage_EventType.Descriptor instead. +func (ServerMessage_EventType) EnumDescriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 1} +} + +// Defines any type of message passed between FJ and server peer +type ServerMessage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Content: + // + // *ServerMessage_Authenticated_ + // *ServerMessage_AuthRequest_ + // *ServerMessage_SubscribeRequest_ + // *ServerMessage_SubscribeResponse_ + // *ServerMessage_RoomCreated_ + // *ServerMessage_RoomDeleted_ + // *ServerMessage_RoomCrashed_ + // *ServerMessage_PeerConnected_ + // *ServerMessage_PeerDisconnected_ + // *ServerMessage_PeerCrashed_ + // *ServerMessage_PeerMetadataUpdated_ + // *ServerMessage_TrackAdded_ + // *ServerMessage_TrackRemoved_ + // *ServerMessage_TrackMetadataUpdated_ + // *ServerMessage_PeerAdded_ + // *ServerMessage_PeerDeleted_ + // *ServerMessage_ChannelAdded_ + // *ServerMessage_ChannelRemoved_ + // *ServerMessage_TrackForwarding_ + // *ServerMessage_TrackForwardingRemoved_ + // *ServerMessage_ViewerConnected_ + // *ServerMessage_ViewerDisconnected_ + // *ServerMessage_StreamerConnected_ + // *ServerMessage_StreamerDisconnected_ + // *ServerMessage_StreamConnected_ + // *ServerMessage_StreamDisconnected_ + // *ServerMessage_HlsPlayable_ + // *ServerMessage_HlsUploaded_ + // *ServerMessage_HlsUploadCrashed_ + // *ServerMessage_ComponentCrashed_ + Content isServerMessage_Content `protobuf_oneof:"content"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage) Reset() { + *x = ServerMessage{} + mi := &file_fishjam_server_notifications_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage) ProtoMessage() {} + +func (x *ServerMessage) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage.ProtoReflect.Descriptor instead. +func (*ServerMessage) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0} +} + +func (x *ServerMessage) GetContent() isServerMessage_Content { + if x != nil { + return x.Content + } + return nil +} + +func (x *ServerMessage) GetAuthenticated() *ServerMessage_Authenticated { + if x != nil { + if x, ok := x.Content.(*ServerMessage_Authenticated_); ok { + return x.Authenticated + } + } + return nil +} + +func (x *ServerMessage) GetAuthRequest() *ServerMessage_AuthRequest { + if x != nil { + if x, ok := x.Content.(*ServerMessage_AuthRequest_); ok { + return x.AuthRequest + } + } + return nil +} + +func (x *ServerMessage) GetSubscribeRequest() *ServerMessage_SubscribeRequest { + if x != nil { + if x, ok := x.Content.(*ServerMessage_SubscribeRequest_); ok { + return x.SubscribeRequest + } + } + return nil +} + +func (x *ServerMessage) GetSubscribeResponse() *ServerMessage_SubscribeResponse { + if x != nil { + if x, ok := x.Content.(*ServerMessage_SubscribeResponse_); ok { + return x.SubscribeResponse + } + } + return nil +} + +func (x *ServerMessage) GetRoomCreated() *ServerMessage_RoomCreated { + if x != nil { + if x, ok := x.Content.(*ServerMessage_RoomCreated_); ok { + return x.RoomCreated + } + } + return nil +} + +func (x *ServerMessage) GetRoomDeleted() *ServerMessage_RoomDeleted { + if x != nil { + if x, ok := x.Content.(*ServerMessage_RoomDeleted_); ok { + return x.RoomDeleted + } + } + return nil +} + +func (x *ServerMessage) GetRoomCrashed() *ServerMessage_RoomCrashed { + if x != nil { + if x, ok := x.Content.(*ServerMessage_RoomCrashed_); ok { + return x.RoomCrashed + } + } + return nil +} + +func (x *ServerMessage) GetPeerConnected() *ServerMessage_PeerConnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_PeerConnected_); ok { + return x.PeerConnected + } + } + return nil +} + +func (x *ServerMessage) GetPeerDisconnected() *ServerMessage_PeerDisconnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_PeerDisconnected_); ok { + return x.PeerDisconnected + } + } + return nil +} + +func (x *ServerMessage) GetPeerCrashed() *ServerMessage_PeerCrashed { + if x != nil { + if x, ok := x.Content.(*ServerMessage_PeerCrashed_); ok { + return x.PeerCrashed + } + } + return nil +} + +func (x *ServerMessage) GetPeerMetadataUpdated() *ServerMessage_PeerMetadataUpdated { + if x != nil { + if x, ok := x.Content.(*ServerMessage_PeerMetadataUpdated_); ok { + return x.PeerMetadataUpdated + } + } + return nil +} + +func (x *ServerMessage) GetTrackAdded() *ServerMessage_TrackAdded { + if x != nil { + if x, ok := x.Content.(*ServerMessage_TrackAdded_); ok { + return x.TrackAdded + } + } + return nil +} + +func (x *ServerMessage) GetTrackRemoved() *ServerMessage_TrackRemoved { + if x != nil { + if x, ok := x.Content.(*ServerMessage_TrackRemoved_); ok { + return x.TrackRemoved + } + } + return nil +} + +func (x *ServerMessage) GetTrackMetadataUpdated() *ServerMessage_TrackMetadataUpdated { + if x != nil { + if x, ok := x.Content.(*ServerMessage_TrackMetadataUpdated_); ok { + return x.TrackMetadataUpdated + } + } + return nil +} + +func (x *ServerMessage) GetPeerAdded() *ServerMessage_PeerAdded { + if x != nil { + if x, ok := x.Content.(*ServerMessage_PeerAdded_); ok { + return x.PeerAdded + } + } + return nil +} + +func (x *ServerMessage) GetPeerDeleted() *ServerMessage_PeerDeleted { + if x != nil { + if x, ok := x.Content.(*ServerMessage_PeerDeleted_); ok { + return x.PeerDeleted + } + } + return nil +} + +func (x *ServerMessage) GetChannelAdded() *ServerMessage_ChannelAdded { + if x != nil { + if x, ok := x.Content.(*ServerMessage_ChannelAdded_); ok { + return x.ChannelAdded + } + } + return nil +} + +func (x *ServerMessage) GetChannelRemoved() *ServerMessage_ChannelRemoved { + if x != nil { + if x, ok := x.Content.(*ServerMessage_ChannelRemoved_); ok { + return x.ChannelRemoved + } + } + return nil +} + +func (x *ServerMessage) GetTrackForwarding() *ServerMessage_TrackForwarding { + if x != nil { + if x, ok := x.Content.(*ServerMessage_TrackForwarding_); ok { + return x.TrackForwarding + } + } + return nil +} + +func (x *ServerMessage) GetTrackForwardingRemoved() *ServerMessage_TrackForwardingRemoved { + if x != nil { + if x, ok := x.Content.(*ServerMessage_TrackForwardingRemoved_); ok { + return x.TrackForwardingRemoved + } + } + return nil +} + +func (x *ServerMessage) GetViewerConnected() *ServerMessage_ViewerConnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_ViewerConnected_); ok { + return x.ViewerConnected + } + } + return nil +} + +func (x *ServerMessage) GetViewerDisconnected() *ServerMessage_ViewerDisconnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_ViewerDisconnected_); ok { + return x.ViewerDisconnected + } + } + return nil +} + +func (x *ServerMessage) GetStreamerConnected() *ServerMessage_StreamerConnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_StreamerConnected_); ok { + return x.StreamerConnected + } + } + return nil +} + +func (x *ServerMessage) GetStreamerDisconnected() *ServerMessage_StreamerDisconnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_StreamerDisconnected_); ok { + return x.StreamerDisconnected + } + } + return nil +} + +// Deprecated: Marked as deprecated in fishjam/server_notifications.proto. +func (x *ServerMessage) GetStreamConnected() *ServerMessage_StreamConnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_StreamConnected_); ok { + return x.StreamConnected + } + } + return nil +} + +// Deprecated: Marked as deprecated in fishjam/server_notifications.proto. +func (x *ServerMessage) GetStreamDisconnected() *ServerMessage_StreamDisconnected { + if x != nil { + if x, ok := x.Content.(*ServerMessage_StreamDisconnected_); ok { + return x.StreamDisconnected + } + } + return nil +} + +// Deprecated: Marked as deprecated in fishjam/server_notifications.proto. +func (x *ServerMessage) GetHlsPlayable() *ServerMessage_HlsPlayable { + if x != nil { + if x, ok := x.Content.(*ServerMessage_HlsPlayable_); ok { + return x.HlsPlayable + } + } + return nil +} + +// Deprecated: Marked as deprecated in fishjam/server_notifications.proto. +func (x *ServerMessage) GetHlsUploaded() *ServerMessage_HlsUploaded { + if x != nil { + if x, ok := x.Content.(*ServerMessage_HlsUploaded_); ok { + return x.HlsUploaded + } + } + return nil +} + +// Deprecated: Marked as deprecated in fishjam/server_notifications.proto. +func (x *ServerMessage) GetHlsUploadCrashed() *ServerMessage_HlsUploadCrashed { + if x != nil { + if x, ok := x.Content.(*ServerMessage_HlsUploadCrashed_); ok { + return x.HlsUploadCrashed + } + } + return nil +} + +// Deprecated: Marked as deprecated in fishjam/server_notifications.proto. +func (x *ServerMessage) GetComponentCrashed() *ServerMessage_ComponentCrashed { + if x != nil { + if x, ok := x.Content.(*ServerMessage_ComponentCrashed_); ok { + return x.ComponentCrashed + } + } + return nil +} + +type isServerMessage_Content interface { + isServerMessage_Content() +} + +type ServerMessage_Authenticated_ struct { + Authenticated *ServerMessage_Authenticated `protobuf:"bytes,6,opt,name=authenticated,proto3,oneof"` +} + +type ServerMessage_AuthRequest_ struct { + AuthRequest *ServerMessage_AuthRequest `protobuf:"bytes,7,opt,name=auth_request,json=authRequest,proto3,oneof"` +} + +type ServerMessage_SubscribeRequest_ struct { + SubscribeRequest *ServerMessage_SubscribeRequest `protobuf:"bytes,8,opt,name=subscribe_request,json=subscribeRequest,proto3,oneof"` +} + +type ServerMessage_SubscribeResponse_ struct { + SubscribeResponse *ServerMessage_SubscribeResponse `protobuf:"bytes,9,opt,name=subscribe_response,json=subscribeResponse,proto3,oneof"` +} + +type ServerMessage_RoomCreated_ struct { + RoomCreated *ServerMessage_RoomCreated `protobuf:"bytes,10,opt,name=room_created,json=roomCreated,proto3,oneof"` +} + +type ServerMessage_RoomDeleted_ struct { + RoomDeleted *ServerMessage_RoomDeleted `protobuf:"bytes,11,opt,name=room_deleted,json=roomDeleted,proto3,oneof"` +} + +type ServerMessage_RoomCrashed_ struct { + RoomCrashed *ServerMessage_RoomCrashed `protobuf:"bytes,1,opt,name=room_crashed,json=roomCrashed,proto3,oneof"` +} + +type ServerMessage_PeerConnected_ struct { + PeerConnected *ServerMessage_PeerConnected `protobuf:"bytes,2,opt,name=peer_connected,json=peerConnected,proto3,oneof"` +} + +type ServerMessage_PeerDisconnected_ struct { + PeerDisconnected *ServerMessage_PeerDisconnected `protobuf:"bytes,3,opt,name=peer_disconnected,json=peerDisconnected,proto3,oneof"` +} + +type ServerMessage_PeerCrashed_ struct { + PeerCrashed *ServerMessage_PeerCrashed `protobuf:"bytes,4,opt,name=peer_crashed,json=peerCrashed,proto3,oneof"` +} + +type ServerMessage_PeerMetadataUpdated_ struct { + PeerMetadataUpdated *ServerMessage_PeerMetadataUpdated `protobuf:"bytes,16,opt,name=peer_metadata_updated,json=peerMetadataUpdated,proto3,oneof"` +} + +type ServerMessage_TrackAdded_ struct { + TrackAdded *ServerMessage_TrackAdded `protobuf:"bytes,17,opt,name=track_added,json=trackAdded,proto3,oneof"` +} + +type ServerMessage_TrackRemoved_ struct { + TrackRemoved *ServerMessage_TrackRemoved `protobuf:"bytes,18,opt,name=track_removed,json=trackRemoved,proto3,oneof"` +} + +type ServerMessage_TrackMetadataUpdated_ struct { + TrackMetadataUpdated *ServerMessage_TrackMetadataUpdated `protobuf:"bytes,19,opt,name=track_metadata_updated,json=trackMetadataUpdated,proto3,oneof"` +} + +type ServerMessage_PeerAdded_ struct { + PeerAdded *ServerMessage_PeerAdded `protobuf:"bytes,20,opt,name=peer_added,json=peerAdded,proto3,oneof"` +} + +type ServerMessage_PeerDeleted_ struct { + PeerDeleted *ServerMessage_PeerDeleted `protobuf:"bytes,21,opt,name=peer_deleted,json=peerDeleted,proto3,oneof"` +} + +type ServerMessage_ChannelAdded_ struct { + ChannelAdded *ServerMessage_ChannelAdded `protobuf:"bytes,28,opt,name=channel_added,json=channelAdded,proto3,oneof"` +} + +type ServerMessage_ChannelRemoved_ struct { + ChannelRemoved *ServerMessage_ChannelRemoved `protobuf:"bytes,29,opt,name=channel_removed,json=channelRemoved,proto3,oneof"` +} + +type ServerMessage_TrackForwarding_ struct { + TrackForwarding *ServerMessage_TrackForwarding `protobuf:"bytes,30,opt,name=track_forwarding,json=trackForwarding,proto3,oneof"` +} + +type ServerMessage_TrackForwardingRemoved_ struct { + TrackForwardingRemoved *ServerMessage_TrackForwardingRemoved `protobuf:"bytes,31,opt,name=track_forwarding_removed,json=trackForwardingRemoved,proto3,oneof"` +} + +type ServerMessage_ViewerConnected_ struct { + ViewerConnected *ServerMessage_ViewerConnected `protobuf:"bytes,24,opt,name=viewer_connected,json=viewerConnected,proto3,oneof"` +} + +type ServerMessage_ViewerDisconnected_ struct { + ViewerDisconnected *ServerMessage_ViewerDisconnected `protobuf:"bytes,25,opt,name=viewer_disconnected,json=viewerDisconnected,proto3,oneof"` +} + +type ServerMessage_StreamerConnected_ struct { + StreamerConnected *ServerMessage_StreamerConnected `protobuf:"bytes,26,opt,name=streamer_connected,json=streamerConnected,proto3,oneof"` +} + +type ServerMessage_StreamerDisconnected_ struct { + StreamerDisconnected *ServerMessage_StreamerDisconnected `protobuf:"bytes,27,opt,name=streamer_disconnected,json=streamerDisconnected,proto3,oneof"` +} + +type ServerMessage_StreamConnected_ struct { + // Deprecated: Marked as deprecated in fishjam/server_notifications.proto. + StreamConnected *ServerMessage_StreamConnected `protobuf:"bytes,22,opt,name=stream_connected,json=streamConnected,proto3,oneof"` +} + +type ServerMessage_StreamDisconnected_ struct { + // Deprecated: Marked as deprecated in fishjam/server_notifications.proto. + StreamDisconnected *ServerMessage_StreamDisconnected `protobuf:"bytes,23,opt,name=stream_disconnected,json=streamDisconnected,proto3,oneof"` +} + +type ServerMessage_HlsPlayable_ struct { + // Deprecated: Marked as deprecated in fishjam/server_notifications.proto. + HlsPlayable *ServerMessage_HlsPlayable `protobuf:"bytes,13,opt,name=hls_playable,json=hlsPlayable,proto3,oneof"` +} + +type ServerMessage_HlsUploaded_ struct { + // Deprecated: Marked as deprecated in fishjam/server_notifications.proto. + HlsUploaded *ServerMessage_HlsUploaded `protobuf:"bytes,14,opt,name=hls_uploaded,json=hlsUploaded,proto3,oneof"` +} + +type ServerMessage_HlsUploadCrashed_ struct { + // Deprecated: Marked as deprecated in fishjam/server_notifications.proto. + HlsUploadCrashed *ServerMessage_HlsUploadCrashed `protobuf:"bytes,15,opt,name=hls_upload_crashed,json=hlsUploadCrashed,proto3,oneof"` +} + +type ServerMessage_ComponentCrashed_ struct { + // Deprecated: Marked as deprecated in fishjam/server_notifications.proto. + ComponentCrashed *ServerMessage_ComponentCrashed `protobuf:"bytes,5,opt,name=component_crashed,json=componentCrashed,proto3,oneof"` +} + +func (*ServerMessage_Authenticated_) isServerMessage_Content() {} + +func (*ServerMessage_AuthRequest_) isServerMessage_Content() {} + +func (*ServerMessage_SubscribeRequest_) isServerMessage_Content() {} + +func (*ServerMessage_SubscribeResponse_) isServerMessage_Content() {} + +func (*ServerMessage_RoomCreated_) isServerMessage_Content() {} + +func (*ServerMessage_RoomDeleted_) isServerMessage_Content() {} + +func (*ServerMessage_RoomCrashed_) isServerMessage_Content() {} + +func (*ServerMessage_PeerConnected_) isServerMessage_Content() {} + +func (*ServerMessage_PeerDisconnected_) isServerMessage_Content() {} + +func (*ServerMessage_PeerCrashed_) isServerMessage_Content() {} + +func (*ServerMessage_PeerMetadataUpdated_) isServerMessage_Content() {} + +func (*ServerMessage_TrackAdded_) isServerMessage_Content() {} + +func (*ServerMessage_TrackRemoved_) isServerMessage_Content() {} + +func (*ServerMessage_TrackMetadataUpdated_) isServerMessage_Content() {} + +func (*ServerMessage_PeerAdded_) isServerMessage_Content() {} + +func (*ServerMessage_PeerDeleted_) isServerMessage_Content() {} + +func (*ServerMessage_ChannelAdded_) isServerMessage_Content() {} + +func (*ServerMessage_ChannelRemoved_) isServerMessage_Content() {} + +func (*ServerMessage_TrackForwarding_) isServerMessage_Content() {} + +func (*ServerMessage_TrackForwardingRemoved_) isServerMessage_Content() {} + +func (*ServerMessage_ViewerConnected_) isServerMessage_Content() {} + +func (*ServerMessage_ViewerDisconnected_) isServerMessage_Content() {} + +func (*ServerMessage_StreamerConnected_) isServerMessage_Content() {} + +func (*ServerMessage_StreamerDisconnected_) isServerMessage_Content() {} + +func (*ServerMessage_StreamConnected_) isServerMessage_Content() {} + +func (*ServerMessage_StreamDisconnected_) isServerMessage_Content() {} + +func (*ServerMessage_HlsPlayable_) isServerMessage_Content() {} + +func (*ServerMessage_HlsUploaded_) isServerMessage_Content() {} + +func (*ServerMessage_HlsUploadCrashed_) isServerMessage_Content() {} + +func (*ServerMessage_ComponentCrashed_) isServerMessage_Content() {} + +// Notification sent when a room crashes +type ServerMessage_RoomCrashed struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_RoomCrashed) Reset() { + *x = ServerMessage_RoomCrashed{} + mi := &file_fishjam_server_notifications_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_RoomCrashed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_RoomCrashed) ProtoMessage() {} + +func (x *ServerMessage_RoomCrashed) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_RoomCrashed.ProtoReflect.Descriptor instead. +func (*ServerMessage_RoomCrashed) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *ServerMessage_RoomCrashed) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +// Notification sent when a peer is added +type ServerMessage_PeerAdded struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + PeerType ServerMessage_PeerType `protobuf:"varint,3,opt,name=peer_type,json=peerType,proto3,enum=fishjam.ServerMessage_PeerType" json:"peer_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_PeerAdded) Reset() { + *x = ServerMessage_PeerAdded{} + mi := &file_fishjam_server_notifications_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_PeerAdded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_PeerAdded) ProtoMessage() {} + +func (x *ServerMessage_PeerAdded) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_PeerAdded.ProtoReflect.Descriptor instead. +func (*ServerMessage_PeerAdded) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 1} +} + +func (x *ServerMessage_PeerAdded) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_PeerAdded) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_PeerAdded) GetPeerType() ServerMessage_PeerType { + if x != nil { + return x.PeerType + } + return ServerMessage_PEER_TYPE_UNSPECIFIED +} + +// Notification sent when a peer is removed +type ServerMessage_PeerDeleted struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + PeerType ServerMessage_PeerType `protobuf:"varint,3,opt,name=peer_type,json=peerType,proto3,enum=fishjam.ServerMessage_PeerType" json:"peer_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_PeerDeleted) Reset() { + *x = ServerMessage_PeerDeleted{} + mi := &file_fishjam_server_notifications_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_PeerDeleted) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_PeerDeleted) ProtoMessage() {} + +func (x *ServerMessage_PeerDeleted) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_PeerDeleted.ProtoReflect.Descriptor instead. +func (*ServerMessage_PeerDeleted) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 2} +} + +func (x *ServerMessage_PeerDeleted) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_PeerDeleted) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_PeerDeleted) GetPeerType() ServerMessage_PeerType { + if x != nil { + return x.PeerType + } + return ServerMessage_PEER_TYPE_UNSPECIFIED +} + +// Notification sent when a peer connects +type ServerMessage_PeerConnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + PeerType ServerMessage_PeerType `protobuf:"varint,3,opt,name=peer_type,json=peerType,proto3,enum=fishjam.ServerMessage_PeerType" json:"peer_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_PeerConnected) Reset() { + *x = ServerMessage_PeerConnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_PeerConnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_PeerConnected) ProtoMessage() {} + +func (x *ServerMessage_PeerConnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_PeerConnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_PeerConnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 3} +} + +func (x *ServerMessage_PeerConnected) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_PeerConnected) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_PeerConnected) GetPeerType() ServerMessage_PeerType { + if x != nil { + return x.PeerType + } + return ServerMessage_PEER_TYPE_UNSPECIFIED +} + +// Notification sent when a peer disconnects from FJ +type ServerMessage_PeerDisconnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + PeerType ServerMessage_PeerType `protobuf:"varint,3,opt,name=peer_type,json=peerType,proto3,enum=fishjam.ServerMessage_PeerType" json:"peer_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_PeerDisconnected) Reset() { + *x = ServerMessage_PeerDisconnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_PeerDisconnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_PeerDisconnected) ProtoMessage() {} + +func (x *ServerMessage_PeerDisconnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_PeerDisconnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_PeerDisconnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 4} +} + +func (x *ServerMessage_PeerDisconnected) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_PeerDisconnected) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_PeerDisconnected) GetPeerType() ServerMessage_PeerType { + if x != nil { + return x.PeerType + } + return ServerMessage_PEER_TYPE_UNSPECIFIED +} + +// Notification sent when a peer crashes +type ServerMessage_PeerCrashed struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + PeerType ServerMessage_PeerType `protobuf:"varint,4,opt,name=peer_type,json=peerType,proto3,enum=fishjam.ServerMessage_PeerType" json:"peer_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_PeerCrashed) Reset() { + *x = ServerMessage_PeerCrashed{} + mi := &file_fishjam_server_notifications_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_PeerCrashed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_PeerCrashed) ProtoMessage() {} + +func (x *ServerMessage_PeerCrashed) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_PeerCrashed.ProtoReflect.Descriptor instead. +func (*ServerMessage_PeerCrashed) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 5} +} + +func (x *ServerMessage_PeerCrashed) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_PeerCrashed) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_PeerCrashed) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *ServerMessage_PeerCrashed) GetPeerType() ServerMessage_PeerType { + if x != nil { + return x.PeerType + } + return ServerMessage_PEER_TYPE_UNSPECIFIED +} + +// Notification sent when a component crashes +type ServerMessage_ComponentCrashed struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + ComponentId string `protobuf:"bytes,2,opt,name=component_id,json=componentId,proto3" json:"component_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_ComponentCrashed) Reset() { + *x = ServerMessage_ComponentCrashed{} + mi := &file_fishjam_server_notifications_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_ComponentCrashed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_ComponentCrashed) ProtoMessage() {} + +func (x *ServerMessage_ComponentCrashed) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_ComponentCrashed.ProtoReflect.Descriptor instead. +func (*ServerMessage_ComponentCrashed) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 6} +} + +func (x *ServerMessage_ComponentCrashed) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_ComponentCrashed) GetComponentId() string { + if x != nil { + return x.ComponentId + } + return "" +} + +// Response sent by FJ, confirming successfull authentication +type ServerMessage_Authenticated struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_Authenticated) Reset() { + *x = ServerMessage_Authenticated{} + mi := &file_fishjam_server_notifications_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_Authenticated) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_Authenticated) ProtoMessage() {} + +func (x *ServerMessage_Authenticated) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_Authenticated.ProtoReflect.Descriptor instead. +func (*ServerMessage_Authenticated) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 7} +} + +// Request sent by peer, to authenticate to FJ server +type ServerMessage_AuthRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_AuthRequest) Reset() { + *x = ServerMessage_AuthRequest{} + mi := &file_fishjam_server_notifications_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_AuthRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_AuthRequest) ProtoMessage() {} + +func (x *ServerMessage_AuthRequest) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_AuthRequest.ProtoReflect.Descriptor instead. +func (*ServerMessage_AuthRequest) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 8} +} + +func (x *ServerMessage_AuthRequest) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +// Request sent by peer to subscribe for certain message type +type ServerMessage_SubscribeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + EventType ServerMessage_EventType `protobuf:"varint,1,opt,name=event_type,json=eventType,proto3,enum=fishjam.ServerMessage_EventType" json:"event_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_SubscribeRequest) Reset() { + *x = ServerMessage_SubscribeRequest{} + mi := &file_fishjam_server_notifications_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_SubscribeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_SubscribeRequest) ProtoMessage() {} + +func (x *ServerMessage_SubscribeRequest) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_SubscribeRequest.ProtoReflect.Descriptor instead. +func (*ServerMessage_SubscribeRequest) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 9} +} + +func (x *ServerMessage_SubscribeRequest) GetEventType() ServerMessage_EventType { + if x != nil { + return x.EventType + } + return ServerMessage_EVENT_TYPE_UNSPECIFIED +} + +// Response sent by FJ, confirming subscription for message type +type ServerMessage_SubscribeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + EventType ServerMessage_EventType `protobuf:"varint,1,opt,name=event_type,json=eventType,proto3,enum=fishjam.ServerMessage_EventType" json:"event_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_SubscribeResponse) Reset() { + *x = ServerMessage_SubscribeResponse{} + mi := &file_fishjam_server_notifications_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_SubscribeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_SubscribeResponse) ProtoMessage() {} + +func (x *ServerMessage_SubscribeResponse) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_SubscribeResponse.ProtoReflect.Descriptor instead. +func (*ServerMessage_SubscribeResponse) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 10} +} + +func (x *ServerMessage_SubscribeResponse) GetEventType() ServerMessage_EventType { + if x != nil { + return x.EventType + } + return ServerMessage_EVENT_TYPE_UNSPECIFIED +} + +// Notification sent when a room is created +type ServerMessage_RoomCreated struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_RoomCreated) Reset() { + *x = ServerMessage_RoomCreated{} + mi := &file_fishjam_server_notifications_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_RoomCreated) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_RoomCreated) ProtoMessage() {} + +func (x *ServerMessage_RoomCreated) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_RoomCreated.ProtoReflect.Descriptor instead. +func (*ServerMessage_RoomCreated) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 11} +} + +func (x *ServerMessage_RoomCreated) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +// Notification sent when a room is deleted +type ServerMessage_RoomDeleted struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_RoomDeleted) Reset() { + *x = ServerMessage_RoomDeleted{} + mi := &file_fishjam_server_notifications_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_RoomDeleted) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_RoomDeleted) ProtoMessage() {} + +func (x *ServerMessage_RoomDeleted) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_RoomDeleted.ProtoReflect.Descriptor instead. +func (*ServerMessage_RoomDeleted) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 12} +} + +func (x *ServerMessage_RoomDeleted) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +// Notification sent when the HLS stream becomes available in a room +type ServerMessage_HlsPlayable struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + ComponentId string `protobuf:"bytes,2,opt,name=component_id,json=componentId,proto3" json:"component_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_HlsPlayable) Reset() { + *x = ServerMessage_HlsPlayable{} + mi := &file_fishjam_server_notifications_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_HlsPlayable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_HlsPlayable) ProtoMessage() {} + +func (x *ServerMessage_HlsPlayable) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_HlsPlayable.ProtoReflect.Descriptor instead. +func (*ServerMessage_HlsPlayable) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 13} +} + +func (x *ServerMessage_HlsPlayable) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_HlsPlayable) GetComponentId() string { + if x != nil { + return x.ComponentId + } + return "" +} + +// Notification sent when the HLS recording is successfully uploaded to AWS S3 +type ServerMessage_HlsUploaded struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_HlsUploaded) Reset() { + *x = ServerMessage_HlsUploaded{} + mi := &file_fishjam_server_notifications_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_HlsUploaded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_HlsUploaded) ProtoMessage() {} + +func (x *ServerMessage_HlsUploaded) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_HlsUploaded.ProtoReflect.Descriptor instead. +func (*ServerMessage_HlsUploaded) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 14} +} + +func (x *ServerMessage_HlsUploaded) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +// Notification sent when the upload of HLS recording to AWS S3 fails +type ServerMessage_HlsUploadCrashed struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_HlsUploadCrashed) Reset() { + *x = ServerMessage_HlsUploadCrashed{} + mi := &file_fishjam_server_notifications_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_HlsUploadCrashed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_HlsUploadCrashed) ProtoMessage() {} + +func (x *ServerMessage_HlsUploadCrashed) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_HlsUploadCrashed.ProtoReflect.Descriptor instead. +func (*ServerMessage_HlsUploadCrashed) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 15} +} + +func (x *ServerMessage_HlsUploadCrashed) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +// Notification sent when peer updates its metadata +type ServerMessage_PeerMetadataUpdated struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` + PeerType ServerMessage_PeerType `protobuf:"varint,4,opt,name=peer_type,json=peerType,proto3,enum=fishjam.ServerMessage_PeerType" json:"peer_type,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_PeerMetadataUpdated) Reset() { + *x = ServerMessage_PeerMetadataUpdated{} + mi := &file_fishjam_server_notifications_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_PeerMetadataUpdated) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_PeerMetadataUpdated) ProtoMessage() {} + +func (x *ServerMessage_PeerMetadataUpdated) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_PeerMetadataUpdated.ProtoReflect.Descriptor instead. +func (*ServerMessage_PeerMetadataUpdated) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 16} +} + +func (x *ServerMessage_PeerMetadataUpdated) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_PeerMetadataUpdated) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_PeerMetadataUpdated) GetMetadata() string { + if x != nil { + return x.Metadata + } + return "" +} + +func (x *ServerMessage_PeerMetadataUpdated) GetPeerType() ServerMessage_PeerType { + if x != nil { + return x.PeerType + } + return ServerMessage_PEER_TYPE_UNSPECIFIED +} + +// Notification sent when peer or component adds new track +type ServerMessage_TrackAdded struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + // Types that are valid to be assigned to EndpointInfo: + // + // *ServerMessage_TrackAdded_PeerId + // *ServerMessage_TrackAdded_ComponentId + EndpointInfo isServerMessage_TrackAdded_EndpointInfo `protobuf_oneof:"endpoint_info"` + Track *notifications.Track `protobuf:"bytes,4,opt,name=track,proto3" json:"track,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_TrackAdded) Reset() { + *x = ServerMessage_TrackAdded{} + mi := &file_fishjam_server_notifications_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_TrackAdded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_TrackAdded) ProtoMessage() {} + +func (x *ServerMessage_TrackAdded) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_TrackAdded.ProtoReflect.Descriptor instead. +func (*ServerMessage_TrackAdded) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 17} +} + +func (x *ServerMessage_TrackAdded) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_TrackAdded) GetEndpointInfo() isServerMessage_TrackAdded_EndpointInfo { + if x != nil { + return x.EndpointInfo + } + return nil +} + +func (x *ServerMessage_TrackAdded) GetPeerId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_TrackAdded_PeerId); ok { + return x.PeerId + } + } + return "" +} + +func (x *ServerMessage_TrackAdded) GetComponentId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_TrackAdded_ComponentId); ok { + return x.ComponentId + } + } + return "" +} + +func (x *ServerMessage_TrackAdded) GetTrack() *notifications.Track { + if x != nil { + return x.Track + } + return nil +} + +type isServerMessage_TrackAdded_EndpointInfo interface { + isServerMessage_TrackAdded_EndpointInfo() +} + +type ServerMessage_TrackAdded_PeerId struct { + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3,oneof"` +} + +type ServerMessage_TrackAdded_ComponentId struct { + ComponentId string `protobuf:"bytes,3,opt,name=component_id,json=componentId,proto3,oneof"` +} + +func (*ServerMessage_TrackAdded_PeerId) isServerMessage_TrackAdded_EndpointInfo() {} + +func (*ServerMessage_TrackAdded_ComponentId) isServerMessage_TrackAdded_EndpointInfo() {} + +// Notification sent when a track is removed +type ServerMessage_TrackRemoved struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + // Types that are valid to be assigned to EndpointInfo: + // + // *ServerMessage_TrackRemoved_PeerId + // *ServerMessage_TrackRemoved_ComponentId + EndpointInfo isServerMessage_TrackRemoved_EndpointInfo `protobuf_oneof:"endpoint_info"` + Track *notifications.Track `protobuf:"bytes,4,opt,name=track,proto3" json:"track,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_TrackRemoved) Reset() { + *x = ServerMessage_TrackRemoved{} + mi := &file_fishjam_server_notifications_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_TrackRemoved) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_TrackRemoved) ProtoMessage() {} + +func (x *ServerMessage_TrackRemoved) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_TrackRemoved.ProtoReflect.Descriptor instead. +func (*ServerMessage_TrackRemoved) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 18} +} + +func (x *ServerMessage_TrackRemoved) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_TrackRemoved) GetEndpointInfo() isServerMessage_TrackRemoved_EndpointInfo { + if x != nil { + return x.EndpointInfo + } + return nil +} + +func (x *ServerMessage_TrackRemoved) GetPeerId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_TrackRemoved_PeerId); ok { + return x.PeerId + } + } + return "" +} + +func (x *ServerMessage_TrackRemoved) GetComponentId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_TrackRemoved_ComponentId); ok { + return x.ComponentId + } + } + return "" +} + +func (x *ServerMessage_TrackRemoved) GetTrack() *notifications.Track { + if x != nil { + return x.Track + } + return nil +} + +type isServerMessage_TrackRemoved_EndpointInfo interface { + isServerMessage_TrackRemoved_EndpointInfo() +} + +type ServerMessage_TrackRemoved_PeerId struct { + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3,oneof"` +} + +type ServerMessage_TrackRemoved_ComponentId struct { + ComponentId string `protobuf:"bytes,3,opt,name=component_id,json=componentId,proto3,oneof"` +} + +func (*ServerMessage_TrackRemoved_PeerId) isServerMessage_TrackRemoved_EndpointInfo() {} + +func (*ServerMessage_TrackRemoved_ComponentId) isServerMessage_TrackRemoved_EndpointInfo() {} + +// Notification sent when metadata of a multimedia track is updated +type ServerMessage_TrackMetadataUpdated struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + // Types that are valid to be assigned to EndpointInfo: + // + // *ServerMessage_TrackMetadataUpdated_PeerId + // *ServerMessage_TrackMetadataUpdated_ComponentId + EndpointInfo isServerMessage_TrackMetadataUpdated_EndpointInfo `protobuf_oneof:"endpoint_info"` + Track *notifications.Track `protobuf:"bytes,4,opt,name=track,proto3" json:"track,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_TrackMetadataUpdated) Reset() { + *x = ServerMessage_TrackMetadataUpdated{} + mi := &file_fishjam_server_notifications_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_TrackMetadataUpdated) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_TrackMetadataUpdated) ProtoMessage() {} + +func (x *ServerMessage_TrackMetadataUpdated) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_TrackMetadataUpdated.ProtoReflect.Descriptor instead. +func (*ServerMessage_TrackMetadataUpdated) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 19} +} + +func (x *ServerMessage_TrackMetadataUpdated) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_TrackMetadataUpdated) GetEndpointInfo() isServerMessage_TrackMetadataUpdated_EndpointInfo { + if x != nil { + return x.EndpointInfo + } + return nil +} + +func (x *ServerMessage_TrackMetadataUpdated) GetPeerId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_TrackMetadataUpdated_PeerId); ok { + return x.PeerId + } + } + return "" +} + +func (x *ServerMessage_TrackMetadataUpdated) GetComponentId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_TrackMetadataUpdated_ComponentId); ok { + return x.ComponentId + } + } + return "" +} + +func (x *ServerMessage_TrackMetadataUpdated) GetTrack() *notifications.Track { + if x != nil { + return x.Track + } + return nil +} + +type isServerMessage_TrackMetadataUpdated_EndpointInfo interface { + isServerMessage_TrackMetadataUpdated_EndpointInfo() +} + +type ServerMessage_TrackMetadataUpdated_PeerId struct { + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3,oneof"` +} + +type ServerMessage_TrackMetadataUpdated_ComponentId struct { + ComponentId string `protobuf:"bytes,3,opt,name=component_id,json=componentId,proto3,oneof"` +} + +func (*ServerMessage_TrackMetadataUpdated_PeerId) isServerMessage_TrackMetadataUpdated_EndpointInfo() { +} + +func (*ServerMessage_TrackMetadataUpdated_ComponentId) isServerMessage_TrackMetadataUpdated_EndpointInfo() { +} + +// Notification sent when a peer creates a channel +type ServerMessage_ChannelAdded struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + // Types that are valid to be assigned to EndpointInfo: + // + // *ServerMessage_ChannelAdded_PeerId + // *ServerMessage_ChannelAdded_ComponentId + EndpointInfo isServerMessage_ChannelAdded_EndpointInfo `protobuf_oneof:"endpoint_info"` + ChannelId string `protobuf:"bytes,4,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_ChannelAdded) Reset() { + *x = ServerMessage_ChannelAdded{} + mi := &file_fishjam_server_notifications_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_ChannelAdded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_ChannelAdded) ProtoMessage() {} + +func (x *ServerMessage_ChannelAdded) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_ChannelAdded.ProtoReflect.Descriptor instead. +func (*ServerMessage_ChannelAdded) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 20} +} + +func (x *ServerMessage_ChannelAdded) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_ChannelAdded) GetEndpointInfo() isServerMessage_ChannelAdded_EndpointInfo { + if x != nil { + return x.EndpointInfo + } + return nil +} + +func (x *ServerMessage_ChannelAdded) GetPeerId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_ChannelAdded_PeerId); ok { + return x.PeerId + } + } + return "" +} + +func (x *ServerMessage_ChannelAdded) GetComponentId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_ChannelAdded_ComponentId); ok { + return x.ComponentId + } + } + return "" +} + +func (x *ServerMessage_ChannelAdded) GetChannelId() string { + if x != nil { + return x.ChannelId + } + return "" +} + +type isServerMessage_ChannelAdded_EndpointInfo interface { + isServerMessage_ChannelAdded_EndpointInfo() +} + +type ServerMessage_ChannelAdded_PeerId struct { + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3,oneof"` +} + +type ServerMessage_ChannelAdded_ComponentId struct { + ComponentId string `protobuf:"bytes,3,opt,name=component_id,json=componentId,proto3,oneof"` +} + +func (*ServerMessage_ChannelAdded_PeerId) isServerMessage_ChannelAdded_EndpointInfo() {} + +func (*ServerMessage_ChannelAdded_ComponentId) isServerMessage_ChannelAdded_EndpointInfo() {} + +// Notification sent when a peer deletes a channel +type ServerMessage_ChannelRemoved struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + // Types that are valid to be assigned to EndpointInfo: + // + // *ServerMessage_ChannelRemoved_PeerId + // *ServerMessage_ChannelRemoved_ComponentId + EndpointInfo isServerMessage_ChannelRemoved_EndpointInfo `protobuf_oneof:"endpoint_info"` + ChannelId string `protobuf:"bytes,4,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_ChannelRemoved) Reset() { + *x = ServerMessage_ChannelRemoved{} + mi := &file_fishjam_server_notifications_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_ChannelRemoved) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_ChannelRemoved) ProtoMessage() {} + +func (x *ServerMessage_ChannelRemoved) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_ChannelRemoved.ProtoReflect.Descriptor instead. +func (*ServerMessage_ChannelRemoved) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 21} +} + +func (x *ServerMessage_ChannelRemoved) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_ChannelRemoved) GetEndpointInfo() isServerMessage_ChannelRemoved_EndpointInfo { + if x != nil { + return x.EndpointInfo + } + return nil +} + +func (x *ServerMessage_ChannelRemoved) GetPeerId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_ChannelRemoved_PeerId); ok { + return x.PeerId + } + } + return "" +} + +func (x *ServerMessage_ChannelRemoved) GetComponentId() string { + if x != nil { + if x, ok := x.EndpointInfo.(*ServerMessage_ChannelRemoved_ComponentId); ok { + return x.ComponentId + } + } + return "" +} + +func (x *ServerMessage_ChannelRemoved) GetChannelId() string { + if x != nil { + return x.ChannelId + } + return "" +} + +type isServerMessage_ChannelRemoved_EndpointInfo interface { + isServerMessage_ChannelRemoved_EndpointInfo() +} + +type ServerMessage_ChannelRemoved_PeerId struct { + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3,oneof"` +} + +type ServerMessage_ChannelRemoved_ComponentId struct { + ComponentId string `protobuf:"bytes,3,opt,name=component_id,json=componentId,proto3,oneof"` +} + +func (*ServerMessage_ChannelRemoved_PeerId) isServerMessage_ChannelRemoved_EndpointInfo() {} + +func (*ServerMessage_ChannelRemoved_ComponentId) isServerMessage_ChannelRemoved_EndpointInfo() {} + +// Sent when there is an upsert to track forwardings from Fishjam to Foundry +type ServerMessage_TrackForwarding struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + CompositionUrl string `protobuf:"bytes,3,opt,name=composition_url,json=compositionUrl,proto3" json:"composition_url,omitempty"` + InputId string `protobuf:"bytes,4,opt,name=input_id,json=inputId,proto3" json:"input_id,omitempty"` + AudioTrack *notifications.Track `protobuf:"bytes,5,opt,name=audio_track,json=audioTrack,proto3,oneof" json:"audio_track,omitempty"` // Track has id, type, and metadata + VideoTrack *notifications.Track `protobuf:"bytes,6,opt,name=video_track,json=videoTrack,proto3,oneof" json:"video_track,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_TrackForwarding) Reset() { + *x = ServerMessage_TrackForwarding{} + mi := &file_fishjam_server_notifications_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_TrackForwarding) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_TrackForwarding) ProtoMessage() {} + +func (x *ServerMessage_TrackForwarding) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_TrackForwarding.ProtoReflect.Descriptor instead. +func (*ServerMessage_TrackForwarding) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 22} +} + +func (x *ServerMessage_TrackForwarding) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_TrackForwarding) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_TrackForwarding) GetCompositionUrl() string { + if x != nil { + return x.CompositionUrl + } + return "" +} + +func (x *ServerMessage_TrackForwarding) GetInputId() string { + if x != nil { + return x.InputId + } + return "" +} + +func (x *ServerMessage_TrackForwarding) GetAudioTrack() *notifications.Track { + if x != nil { + return x.AudioTrack + } + return nil +} + +func (x *ServerMessage_TrackForwarding) GetVideoTrack() *notifications.Track { + if x != nil { + return x.VideoTrack + } + return nil +} + +// Sent when track forwarding is removed +type ServerMessage_TrackForwardingRemoved struct { + state protoimpl.MessageState `protogen:"open.v1"` + RoomId string `protobuf:"bytes,1,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + PeerId string `protobuf:"bytes,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + CompositionUrl string `protobuf:"bytes,3,opt,name=composition_url,json=compositionUrl,proto3" json:"composition_url,omitempty"` + InputId string `protobuf:"bytes,4,opt,name=input_id,json=inputId,proto3" json:"input_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_TrackForwardingRemoved) Reset() { + *x = ServerMessage_TrackForwardingRemoved{} + mi := &file_fishjam_server_notifications_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_TrackForwardingRemoved) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_TrackForwardingRemoved) ProtoMessage() {} + +func (x *ServerMessage_TrackForwardingRemoved) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_TrackForwardingRemoved.ProtoReflect.Descriptor instead. +func (*ServerMessage_TrackForwardingRemoved) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 23} +} + +func (x *ServerMessage_TrackForwardingRemoved) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *ServerMessage_TrackForwardingRemoved) GetPeerId() string { + if x != nil { + return x.PeerId + } + return "" +} + +func (x *ServerMessage_TrackForwardingRemoved) GetCompositionUrl() string { + if x != nil { + return x.CompositionUrl + } + return "" +} + +func (x *ServerMessage_TrackForwardingRemoved) GetInputId() string { + if x != nil { + return x.InputId + } + return "" +} + +// Notification sent when streamer successfully connects +type ServerMessage_StreamConnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + StreamId string `protobuf:"bytes,1,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_StreamConnected) Reset() { + *x = ServerMessage_StreamConnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_StreamConnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_StreamConnected) ProtoMessage() {} + +func (x *ServerMessage_StreamConnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_StreamConnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_StreamConnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 24} +} + +func (x *ServerMessage_StreamConnected) GetStreamId() string { + if x != nil { + return x.StreamId + } + return "" +} + +// Notification sent when streamer disconnects +type ServerMessage_StreamDisconnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + StreamId string `protobuf:"bytes,1,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_StreamDisconnected) Reset() { + *x = ServerMessage_StreamDisconnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_StreamDisconnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_StreamDisconnected) ProtoMessage() {} + +func (x *ServerMessage_StreamDisconnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_StreamDisconnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_StreamDisconnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 25} +} + +func (x *ServerMessage_StreamDisconnected) GetStreamId() string { + if x != nil { + return x.StreamId + } + return "" +} + +// Notification sent when viewer successfully connects +type ServerMessage_ViewerConnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + StreamId string `protobuf:"bytes,1,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"` + ViewerId string `protobuf:"bytes,2,opt,name=viewer_id,json=viewerId,proto3" json:"viewer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_ViewerConnected) Reset() { + *x = ServerMessage_ViewerConnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_ViewerConnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_ViewerConnected) ProtoMessage() {} + +func (x *ServerMessage_ViewerConnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_ViewerConnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_ViewerConnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 26} +} + +func (x *ServerMessage_ViewerConnected) GetStreamId() string { + if x != nil { + return x.StreamId + } + return "" +} + +func (x *ServerMessage_ViewerConnected) GetViewerId() string { + if x != nil { + return x.ViewerId + } + return "" +} + +// Notification sent when viewer disconnects +type ServerMessage_ViewerDisconnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + StreamId string `protobuf:"bytes,1,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"` + ViewerId string `protobuf:"bytes,2,opt,name=viewer_id,json=viewerId,proto3" json:"viewer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_ViewerDisconnected) Reset() { + *x = ServerMessage_ViewerDisconnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_ViewerDisconnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_ViewerDisconnected) ProtoMessage() {} + +func (x *ServerMessage_ViewerDisconnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[28] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_ViewerDisconnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_ViewerDisconnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 27} +} + +func (x *ServerMessage_ViewerDisconnected) GetStreamId() string { + if x != nil { + return x.StreamId + } + return "" +} + +func (x *ServerMessage_ViewerDisconnected) GetViewerId() string { + if x != nil { + return x.ViewerId + } + return "" +} + +type ServerMessage_StreamerConnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + StreamId string `protobuf:"bytes,1,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"` + StreamerId string `protobuf:"bytes,2,opt,name=streamer_id,json=streamerId,proto3" json:"streamer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_StreamerConnected) Reset() { + *x = ServerMessage_StreamerConnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_StreamerConnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_StreamerConnected) ProtoMessage() {} + +func (x *ServerMessage_StreamerConnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[29] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_StreamerConnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_StreamerConnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 28} +} + +func (x *ServerMessage_StreamerConnected) GetStreamId() string { + if x != nil { + return x.StreamId + } + return "" +} + +func (x *ServerMessage_StreamerConnected) GetStreamerId() string { + if x != nil { + return x.StreamerId + } + return "" +} + +type ServerMessage_StreamerDisconnected struct { + state protoimpl.MessageState `protogen:"open.v1"` + StreamId string `protobuf:"bytes,1,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"` + StreamerId string `protobuf:"bytes,2,opt,name=streamer_id,json=streamerId,proto3" json:"streamer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServerMessage_StreamerDisconnected) Reset() { + *x = ServerMessage_StreamerDisconnected{} + mi := &file_fishjam_server_notifications_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServerMessage_StreamerDisconnected) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerMessage_StreamerDisconnected) ProtoMessage() {} + +func (x *ServerMessage_StreamerDisconnected) ProtoReflect() protoreflect.Message { + mi := &file_fishjam_server_notifications_proto_msgTypes[30] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerMessage_StreamerDisconnected.ProtoReflect.Descriptor instead. +func (*ServerMessage_StreamerDisconnected) Descriptor() ([]byte, []int) { + return file_fishjam_server_notifications_proto_rawDescGZIP(), []int{0, 29} +} + +func (x *ServerMessage_StreamerDisconnected) GetStreamId() string { + if x != nil { + return x.StreamId + } + return "" +} + +func (x *ServerMessage_StreamerDisconnected) GetStreamerId() string { + if x != nil { + return x.StreamerId + } + return "" +} + +var File_fishjam_server_notifications_proto protoreflect.FileDescriptor + +const file_fishjam_server_notifications_proto_rawDesc = "" + + "\n" + + "\"fishjam/server_notifications.proto\x12\afishjam\x1a\"fishjam/notifications/shared.proto\"\xd9-\n" + + "\rServerMessage\x12L\n" + + "\rauthenticated\x18\x06 \x01(\v2$.fishjam.ServerMessage.AuthenticatedH\x00R\rauthenticated\x12G\n" + + "\fauth_request\x18\a \x01(\v2\".fishjam.ServerMessage.AuthRequestH\x00R\vauthRequest\x12V\n" + + "\x11subscribe_request\x18\b \x01(\v2'.fishjam.ServerMessage.SubscribeRequestH\x00R\x10subscribeRequest\x12Y\n" + + "\x12subscribe_response\x18\t \x01(\v2(.fishjam.ServerMessage.SubscribeResponseH\x00R\x11subscribeResponse\x12G\n" + + "\froom_created\x18\n" + + " \x01(\v2\".fishjam.ServerMessage.RoomCreatedH\x00R\vroomCreated\x12G\n" + + "\froom_deleted\x18\v \x01(\v2\".fishjam.ServerMessage.RoomDeletedH\x00R\vroomDeleted\x12G\n" + + "\froom_crashed\x18\x01 \x01(\v2\".fishjam.ServerMessage.RoomCrashedH\x00R\vroomCrashed\x12M\n" + + "\x0epeer_connected\x18\x02 \x01(\v2$.fishjam.ServerMessage.PeerConnectedH\x00R\rpeerConnected\x12V\n" + + "\x11peer_disconnected\x18\x03 \x01(\v2'.fishjam.ServerMessage.PeerDisconnectedH\x00R\x10peerDisconnected\x12G\n" + + "\fpeer_crashed\x18\x04 \x01(\v2\".fishjam.ServerMessage.PeerCrashedH\x00R\vpeerCrashed\x12`\n" + + "\x15peer_metadata_updated\x18\x10 \x01(\v2*.fishjam.ServerMessage.PeerMetadataUpdatedH\x00R\x13peerMetadataUpdated\x12D\n" + + "\vtrack_added\x18\x11 \x01(\v2!.fishjam.ServerMessage.TrackAddedH\x00R\n" + + "trackAdded\x12J\n" + + "\rtrack_removed\x18\x12 \x01(\v2#.fishjam.ServerMessage.TrackRemovedH\x00R\ftrackRemoved\x12c\n" + + "\x16track_metadata_updated\x18\x13 \x01(\v2+.fishjam.ServerMessage.TrackMetadataUpdatedH\x00R\x14trackMetadataUpdated\x12A\n" + + "\n" + + "peer_added\x18\x14 \x01(\v2 .fishjam.ServerMessage.PeerAddedH\x00R\tpeerAdded\x12G\n" + + "\fpeer_deleted\x18\x15 \x01(\v2\".fishjam.ServerMessage.PeerDeletedH\x00R\vpeerDeleted\x12J\n" + + "\rchannel_added\x18\x1c \x01(\v2#.fishjam.ServerMessage.ChannelAddedH\x00R\fchannelAdded\x12P\n" + + "\x0fchannel_removed\x18\x1d \x01(\v2%.fishjam.ServerMessage.ChannelRemovedH\x00R\x0echannelRemoved\x12S\n" + + "\x10track_forwarding\x18\x1e \x01(\v2&.fishjam.ServerMessage.TrackForwardingH\x00R\x0ftrackForwarding\x12i\n" + + "\x18track_forwarding_removed\x18\x1f \x01(\v2-.fishjam.ServerMessage.TrackForwardingRemovedH\x00R\x16trackForwardingRemoved\x12S\n" + + "\x10viewer_connected\x18\x18 \x01(\v2&.fishjam.ServerMessage.ViewerConnectedH\x00R\x0fviewerConnected\x12\\\n" + + "\x13viewer_disconnected\x18\x19 \x01(\v2).fishjam.ServerMessage.ViewerDisconnectedH\x00R\x12viewerDisconnected\x12Y\n" + + "\x12streamer_connected\x18\x1a \x01(\v2(.fishjam.ServerMessage.StreamerConnectedH\x00R\x11streamerConnected\x12b\n" + + "\x15streamer_disconnected\x18\x1b \x01(\v2+.fishjam.ServerMessage.StreamerDisconnectedH\x00R\x14streamerDisconnected\x12W\n" + + "\x10stream_connected\x18\x16 \x01(\v2&.fishjam.ServerMessage.StreamConnectedB\x02\x18\x01H\x00R\x0fstreamConnected\x12`\n" + + "\x13stream_disconnected\x18\x17 \x01(\v2).fishjam.ServerMessage.StreamDisconnectedB\x02\x18\x01H\x00R\x12streamDisconnected\x12K\n" + + "\fhls_playable\x18\r \x01(\v2\".fishjam.ServerMessage.HlsPlayableB\x02\x18\x01H\x00R\vhlsPlayable\x12K\n" + + "\fhls_uploaded\x18\x0e \x01(\v2\".fishjam.ServerMessage.HlsUploadedB\x02\x18\x01H\x00R\vhlsUploaded\x12[\n" + + "\x12hls_upload_crashed\x18\x0f \x01(\v2'.fishjam.ServerMessage.HlsUploadCrashedB\x02\x18\x01H\x00R\x10hlsUploadCrashed\x12Z\n" + + "\x11component_crashed\x18\x05 \x01(\v2'.fishjam.ServerMessage.ComponentCrashedB\x02\x18\x01H\x00R\x10componentCrashed\x1a&\n" + + "\vRoomCrashed\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x1a{\n" + + "\tPeerAdded\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12<\n" + + "\tpeer_type\x18\x03 \x01(\x0e2\x1f.fishjam.ServerMessage.PeerTypeR\bpeerType\x1a}\n" + + "\vPeerDeleted\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12<\n" + + "\tpeer_type\x18\x03 \x01(\x0e2\x1f.fishjam.ServerMessage.PeerTypeR\bpeerType\x1a\x7f\n" + + "\rPeerConnected\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12<\n" + + "\tpeer_type\x18\x03 \x01(\x0e2\x1f.fishjam.ServerMessage.PeerTypeR\bpeerType\x1a\x82\x01\n" + + "\x10PeerDisconnected\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12<\n" + + "\tpeer_type\x18\x03 \x01(\x0e2\x1f.fishjam.ServerMessage.PeerTypeR\bpeerType\x1a\x95\x01\n" + + "\vPeerCrashed\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12\x16\n" + + "\x06reason\x18\x03 \x01(\tR\x06reason\x12<\n" + + "\tpeer_type\x18\x04 \x01(\x0e2\x1f.fishjam.ServerMessage.PeerTypeR\bpeerType\x1aN\n" + + "\x10ComponentCrashed\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12!\n" + + "\fcomponent_id\x18\x02 \x01(\tR\vcomponentId\x1a\x0f\n" + + "\rAuthenticated\x1a#\n" + + "\vAuthRequest\x12\x14\n" + + "\x05token\x18\x01 \x01(\tR\x05token\x1aS\n" + + "\x10SubscribeRequest\x12?\n" + + "\n" + + "event_type\x18\x01 \x01(\x0e2 .fishjam.ServerMessage.EventTypeR\teventType\x1aT\n" + + "\x11SubscribeResponse\x12?\n" + + "\n" + + "event_type\x18\x01 \x01(\x0e2 .fishjam.ServerMessage.EventTypeR\teventType\x1a&\n" + + "\vRoomCreated\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x1a&\n" + + "\vRoomDeleted\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x1aI\n" + + "\vHlsPlayable\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12!\n" + + "\fcomponent_id\x18\x02 \x01(\tR\vcomponentId\x1a&\n" + + "\vHlsUploaded\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x1a+\n" + + "\x10HlsUploadCrashed\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x1a\xa1\x01\n" + + "\x13PeerMetadataUpdated\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12\x1a\n" + + "\bmetadata\x18\x03 \x01(\tR\bmetadata\x12<\n" + + "\tpeer_type\x18\x04 \x01(\x0e2\x1f.fishjam.ServerMessage.PeerTypeR\bpeerType\x1a\xaa\x01\n" + + "\n" + + "TrackAdded\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x19\n" + + "\apeer_id\x18\x02 \x01(\tH\x00R\x06peerId\x12#\n" + + "\fcomponent_id\x18\x03 \x01(\tH\x00R\vcomponentId\x122\n" + + "\x05track\x18\x04 \x01(\v2\x1c.fishjam.notifications.TrackR\x05trackB\x0f\n" + + "\rendpoint_info\x1a\xac\x01\n" + + "\fTrackRemoved\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x19\n" + + "\apeer_id\x18\x02 \x01(\tH\x00R\x06peerId\x12#\n" + + "\fcomponent_id\x18\x03 \x01(\tH\x00R\vcomponentId\x122\n" + + "\x05track\x18\x04 \x01(\v2\x1c.fishjam.notifications.TrackR\x05trackB\x0f\n" + + "\rendpoint_info\x1a\xb4\x01\n" + + "\x14TrackMetadataUpdated\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x19\n" + + "\apeer_id\x18\x02 \x01(\tH\x00R\x06peerId\x12#\n" + + "\fcomponent_id\x18\x03 \x01(\tH\x00R\vcomponentId\x122\n" + + "\x05track\x18\x04 \x01(\v2\x1c.fishjam.notifications.TrackR\x05trackB\x0f\n" + + "\rendpoint_info\x1a\x97\x01\n" + + "\fChannelAdded\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x19\n" + + "\apeer_id\x18\x02 \x01(\tH\x00R\x06peerId\x12#\n" + + "\fcomponent_id\x18\x03 \x01(\tH\x00R\vcomponentId\x12\x1d\n" + + "\n" + + "channel_id\x18\x04 \x01(\tR\tchannelIdB\x0f\n" + + "\rendpoint_info\x1a\x99\x01\n" + + "\x0eChannelRemoved\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x19\n" + + "\apeer_id\x18\x02 \x01(\tH\x00R\x06peerId\x12#\n" + + "\fcomponent_id\x18\x03 \x01(\tH\x00R\vcomponentId\x12\x1d\n" + + "\n" + + "channel_id\x18\x04 \x01(\tR\tchannelIdB\x0f\n" + + "\rendpoint_info\x1a\xaf\x02\n" + + "\x0fTrackForwarding\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12'\n" + + "\x0fcomposition_url\x18\x03 \x01(\tR\x0ecompositionUrl\x12\x19\n" + + "\binput_id\x18\x04 \x01(\tR\ainputId\x12B\n" + + "\vaudio_track\x18\x05 \x01(\v2\x1c.fishjam.notifications.TrackH\x00R\n" + + "audioTrack\x88\x01\x01\x12B\n" + + "\vvideo_track\x18\x06 \x01(\v2\x1c.fishjam.notifications.TrackH\x01R\n" + + "videoTrack\x88\x01\x01B\x0e\n" + + "\f_audio_trackB\x0e\n" + + "\f_video_track\x1a\x8e\x01\n" + + "\x16TrackForwardingRemoved\x12\x17\n" + + "\aroom_id\x18\x01 \x01(\tR\x06roomId\x12\x17\n" + + "\apeer_id\x18\x02 \x01(\tR\x06peerId\x12'\n" + + "\x0fcomposition_url\x18\x03 \x01(\tR\x0ecompositionUrl\x12\x19\n" + + "\binput_id\x18\x04 \x01(\tR\ainputId\x1a.\n" + + "\x0fStreamConnected\x12\x1b\n" + + "\tstream_id\x18\x01 \x01(\tR\bstreamId\x1a1\n" + + "\x12StreamDisconnected\x12\x1b\n" + + "\tstream_id\x18\x01 \x01(\tR\bstreamId\x1aK\n" + + "\x0fViewerConnected\x12\x1b\n" + + "\tstream_id\x18\x01 \x01(\tR\bstreamId\x12\x1b\n" + + "\tviewer_id\x18\x02 \x01(\tR\bviewerId\x1aN\n" + + "\x12ViewerDisconnected\x12\x1b\n" + + "\tstream_id\x18\x01 \x01(\tR\bstreamId\x12\x1b\n" + + "\tviewer_id\x18\x02 \x01(\tR\bviewerId\x1aQ\n" + + "\x11StreamerConnected\x12\x1b\n" + + "\tstream_id\x18\x01 \x01(\tR\bstreamId\x12\x1f\n" + + "\vstreamer_id\x18\x02 \x01(\tR\n" + + "streamerId\x1aT\n" + + "\x14StreamerDisconnected\x12\x1b\n" + + "\tstream_id\x18\x01 \x01(\tR\bstreamId\x12\x1f\n" + + "\vstreamer_id\x18\x02 \x01(\tR\n" + + "streamerId\"P\n" + + "\bPeerType\x12\x19\n" + + "\x15PEER_TYPE_UNSPECIFIED\x10\x00\x12\x14\n" + + "\x10PEER_TYPE_WEBRTC\x10\x01\x12\x13\n" + + "\x0fPEER_TYPE_AGENT\x10\x02\"Q\n" + + "\tEventType\x12\x1a\n" + + "\x16EVENT_TYPE_UNSPECIFIED\x10\x00\x12\"\n" + + "\x1eEVENT_TYPE_SERVER_NOTIFICATION\x10\x01\"\x04\b\x02\x10\x02B\t\n" + + "\acontentJ\x04\b\f\x10\rb\x06proto3" + +var ( + file_fishjam_server_notifications_proto_rawDescOnce sync.Once + file_fishjam_server_notifications_proto_rawDescData []byte +) + +func file_fishjam_server_notifications_proto_rawDescGZIP() []byte { + file_fishjam_server_notifications_proto_rawDescOnce.Do(func() { + file_fishjam_server_notifications_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_fishjam_server_notifications_proto_rawDesc), len(file_fishjam_server_notifications_proto_rawDesc))) + }) + return file_fishjam_server_notifications_proto_rawDescData +} + +var file_fishjam_server_notifications_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_fishjam_server_notifications_proto_msgTypes = make([]protoimpl.MessageInfo, 31) +var file_fishjam_server_notifications_proto_goTypes = []any{ + (ServerMessage_PeerType)(0), // 0: fishjam.ServerMessage.PeerType + (ServerMessage_EventType)(0), // 1: fishjam.ServerMessage.EventType + (*ServerMessage)(nil), // 2: fishjam.ServerMessage + (*ServerMessage_RoomCrashed)(nil), // 3: fishjam.ServerMessage.RoomCrashed + (*ServerMessage_PeerAdded)(nil), // 4: fishjam.ServerMessage.PeerAdded + (*ServerMessage_PeerDeleted)(nil), // 5: fishjam.ServerMessage.PeerDeleted + (*ServerMessage_PeerConnected)(nil), // 6: fishjam.ServerMessage.PeerConnected + (*ServerMessage_PeerDisconnected)(nil), // 7: fishjam.ServerMessage.PeerDisconnected + (*ServerMessage_PeerCrashed)(nil), // 8: fishjam.ServerMessage.PeerCrashed + (*ServerMessage_ComponentCrashed)(nil), // 9: fishjam.ServerMessage.ComponentCrashed + (*ServerMessage_Authenticated)(nil), // 10: fishjam.ServerMessage.Authenticated + (*ServerMessage_AuthRequest)(nil), // 11: fishjam.ServerMessage.AuthRequest + (*ServerMessage_SubscribeRequest)(nil), // 12: fishjam.ServerMessage.SubscribeRequest + (*ServerMessage_SubscribeResponse)(nil), // 13: fishjam.ServerMessage.SubscribeResponse + (*ServerMessage_RoomCreated)(nil), // 14: fishjam.ServerMessage.RoomCreated + (*ServerMessage_RoomDeleted)(nil), // 15: fishjam.ServerMessage.RoomDeleted + (*ServerMessage_HlsPlayable)(nil), // 16: fishjam.ServerMessage.HlsPlayable + (*ServerMessage_HlsUploaded)(nil), // 17: fishjam.ServerMessage.HlsUploaded + (*ServerMessage_HlsUploadCrashed)(nil), // 18: fishjam.ServerMessage.HlsUploadCrashed + (*ServerMessage_PeerMetadataUpdated)(nil), // 19: fishjam.ServerMessage.PeerMetadataUpdated + (*ServerMessage_TrackAdded)(nil), // 20: fishjam.ServerMessage.TrackAdded + (*ServerMessage_TrackRemoved)(nil), // 21: fishjam.ServerMessage.TrackRemoved + (*ServerMessage_TrackMetadataUpdated)(nil), // 22: fishjam.ServerMessage.TrackMetadataUpdated + (*ServerMessage_ChannelAdded)(nil), // 23: fishjam.ServerMessage.ChannelAdded + (*ServerMessage_ChannelRemoved)(nil), // 24: fishjam.ServerMessage.ChannelRemoved + (*ServerMessage_TrackForwarding)(nil), // 25: fishjam.ServerMessage.TrackForwarding + (*ServerMessage_TrackForwardingRemoved)(nil), // 26: fishjam.ServerMessage.TrackForwardingRemoved + (*ServerMessage_StreamConnected)(nil), // 27: fishjam.ServerMessage.StreamConnected + (*ServerMessage_StreamDisconnected)(nil), // 28: fishjam.ServerMessage.StreamDisconnected + (*ServerMessage_ViewerConnected)(nil), // 29: fishjam.ServerMessage.ViewerConnected + (*ServerMessage_ViewerDisconnected)(nil), // 30: fishjam.ServerMessage.ViewerDisconnected + (*ServerMessage_StreamerConnected)(nil), // 31: fishjam.ServerMessage.StreamerConnected + (*ServerMessage_StreamerDisconnected)(nil), // 32: fishjam.ServerMessage.StreamerDisconnected + (*notifications.Track)(nil), // 33: fishjam.notifications.Track +} +var file_fishjam_server_notifications_proto_depIdxs = []int32{ + 10, // 0: fishjam.ServerMessage.authenticated:type_name -> fishjam.ServerMessage.Authenticated + 11, // 1: fishjam.ServerMessage.auth_request:type_name -> fishjam.ServerMessage.AuthRequest + 12, // 2: fishjam.ServerMessage.subscribe_request:type_name -> fishjam.ServerMessage.SubscribeRequest + 13, // 3: fishjam.ServerMessage.subscribe_response:type_name -> fishjam.ServerMessage.SubscribeResponse + 14, // 4: fishjam.ServerMessage.room_created:type_name -> fishjam.ServerMessage.RoomCreated + 15, // 5: fishjam.ServerMessage.room_deleted:type_name -> fishjam.ServerMessage.RoomDeleted + 3, // 6: fishjam.ServerMessage.room_crashed:type_name -> fishjam.ServerMessage.RoomCrashed + 6, // 7: fishjam.ServerMessage.peer_connected:type_name -> fishjam.ServerMessage.PeerConnected + 7, // 8: fishjam.ServerMessage.peer_disconnected:type_name -> fishjam.ServerMessage.PeerDisconnected + 8, // 9: fishjam.ServerMessage.peer_crashed:type_name -> fishjam.ServerMessage.PeerCrashed + 19, // 10: fishjam.ServerMessage.peer_metadata_updated:type_name -> fishjam.ServerMessage.PeerMetadataUpdated + 20, // 11: fishjam.ServerMessage.track_added:type_name -> fishjam.ServerMessage.TrackAdded + 21, // 12: fishjam.ServerMessage.track_removed:type_name -> fishjam.ServerMessage.TrackRemoved + 22, // 13: fishjam.ServerMessage.track_metadata_updated:type_name -> fishjam.ServerMessage.TrackMetadataUpdated + 4, // 14: fishjam.ServerMessage.peer_added:type_name -> fishjam.ServerMessage.PeerAdded + 5, // 15: fishjam.ServerMessage.peer_deleted:type_name -> fishjam.ServerMessage.PeerDeleted + 23, // 16: fishjam.ServerMessage.channel_added:type_name -> fishjam.ServerMessage.ChannelAdded + 24, // 17: fishjam.ServerMessage.channel_removed:type_name -> fishjam.ServerMessage.ChannelRemoved + 25, // 18: fishjam.ServerMessage.track_forwarding:type_name -> fishjam.ServerMessage.TrackForwarding + 26, // 19: fishjam.ServerMessage.track_forwarding_removed:type_name -> fishjam.ServerMessage.TrackForwardingRemoved + 29, // 20: fishjam.ServerMessage.viewer_connected:type_name -> fishjam.ServerMessage.ViewerConnected + 30, // 21: fishjam.ServerMessage.viewer_disconnected:type_name -> fishjam.ServerMessage.ViewerDisconnected + 31, // 22: fishjam.ServerMessage.streamer_connected:type_name -> fishjam.ServerMessage.StreamerConnected + 32, // 23: fishjam.ServerMessage.streamer_disconnected:type_name -> fishjam.ServerMessage.StreamerDisconnected + 27, // 24: fishjam.ServerMessage.stream_connected:type_name -> fishjam.ServerMessage.StreamConnected + 28, // 25: fishjam.ServerMessage.stream_disconnected:type_name -> fishjam.ServerMessage.StreamDisconnected + 16, // 26: fishjam.ServerMessage.hls_playable:type_name -> fishjam.ServerMessage.HlsPlayable + 17, // 27: fishjam.ServerMessage.hls_uploaded:type_name -> fishjam.ServerMessage.HlsUploaded + 18, // 28: fishjam.ServerMessage.hls_upload_crashed:type_name -> fishjam.ServerMessage.HlsUploadCrashed + 9, // 29: fishjam.ServerMessage.component_crashed:type_name -> fishjam.ServerMessage.ComponentCrashed + 0, // 30: fishjam.ServerMessage.PeerAdded.peer_type:type_name -> fishjam.ServerMessage.PeerType + 0, // 31: fishjam.ServerMessage.PeerDeleted.peer_type:type_name -> fishjam.ServerMessage.PeerType + 0, // 32: fishjam.ServerMessage.PeerConnected.peer_type:type_name -> fishjam.ServerMessage.PeerType + 0, // 33: fishjam.ServerMessage.PeerDisconnected.peer_type:type_name -> fishjam.ServerMessage.PeerType + 0, // 34: fishjam.ServerMessage.PeerCrashed.peer_type:type_name -> fishjam.ServerMessage.PeerType + 1, // 35: fishjam.ServerMessage.SubscribeRequest.event_type:type_name -> fishjam.ServerMessage.EventType + 1, // 36: fishjam.ServerMessage.SubscribeResponse.event_type:type_name -> fishjam.ServerMessage.EventType + 0, // 37: fishjam.ServerMessage.PeerMetadataUpdated.peer_type:type_name -> fishjam.ServerMessage.PeerType + 33, // 38: fishjam.ServerMessage.TrackAdded.track:type_name -> fishjam.notifications.Track + 33, // 39: fishjam.ServerMessage.TrackRemoved.track:type_name -> fishjam.notifications.Track + 33, // 40: fishjam.ServerMessage.TrackMetadataUpdated.track:type_name -> fishjam.notifications.Track + 33, // 41: fishjam.ServerMessage.TrackForwarding.audio_track:type_name -> fishjam.notifications.Track + 33, // 42: fishjam.ServerMessage.TrackForwarding.video_track:type_name -> fishjam.notifications.Track + 43, // [43:43] is the sub-list for method output_type + 43, // [43:43] is the sub-list for method input_type + 43, // [43:43] is the sub-list for extension type_name + 43, // [43:43] is the sub-list for extension extendee + 0, // [0:43] is the sub-list for field type_name +} + +func init() { file_fishjam_server_notifications_proto_init() } +func file_fishjam_server_notifications_proto_init() { + if File_fishjam_server_notifications_proto != nil { + return + } + file_fishjam_server_notifications_proto_msgTypes[0].OneofWrappers = []any{ + (*ServerMessage_Authenticated_)(nil), + (*ServerMessage_AuthRequest_)(nil), + (*ServerMessage_SubscribeRequest_)(nil), + (*ServerMessage_SubscribeResponse_)(nil), + (*ServerMessage_RoomCreated_)(nil), + (*ServerMessage_RoomDeleted_)(nil), + (*ServerMessage_RoomCrashed_)(nil), + (*ServerMessage_PeerConnected_)(nil), + (*ServerMessage_PeerDisconnected_)(nil), + (*ServerMessage_PeerCrashed_)(nil), + (*ServerMessage_PeerMetadataUpdated_)(nil), + (*ServerMessage_TrackAdded_)(nil), + (*ServerMessage_TrackRemoved_)(nil), + (*ServerMessage_TrackMetadataUpdated_)(nil), + (*ServerMessage_PeerAdded_)(nil), + (*ServerMessage_PeerDeleted_)(nil), + (*ServerMessage_ChannelAdded_)(nil), + (*ServerMessage_ChannelRemoved_)(nil), + (*ServerMessage_TrackForwarding_)(nil), + (*ServerMessage_TrackForwardingRemoved_)(nil), + (*ServerMessage_ViewerConnected_)(nil), + (*ServerMessage_ViewerDisconnected_)(nil), + (*ServerMessage_StreamerConnected_)(nil), + (*ServerMessage_StreamerDisconnected_)(nil), + (*ServerMessage_StreamConnected_)(nil), + (*ServerMessage_StreamDisconnected_)(nil), + (*ServerMessage_HlsPlayable_)(nil), + (*ServerMessage_HlsUploaded_)(nil), + (*ServerMessage_HlsUploadCrashed_)(nil), + (*ServerMessage_ComponentCrashed_)(nil), + } + file_fishjam_server_notifications_proto_msgTypes[18].OneofWrappers = []any{ + (*ServerMessage_TrackAdded_PeerId)(nil), + (*ServerMessage_TrackAdded_ComponentId)(nil), + } + file_fishjam_server_notifications_proto_msgTypes[19].OneofWrappers = []any{ + (*ServerMessage_TrackRemoved_PeerId)(nil), + (*ServerMessage_TrackRemoved_ComponentId)(nil), + } + file_fishjam_server_notifications_proto_msgTypes[20].OneofWrappers = []any{ + (*ServerMessage_TrackMetadataUpdated_PeerId)(nil), + (*ServerMessage_TrackMetadataUpdated_ComponentId)(nil), + } + file_fishjam_server_notifications_proto_msgTypes[21].OneofWrappers = []any{ + (*ServerMessage_ChannelAdded_PeerId)(nil), + (*ServerMessage_ChannelAdded_ComponentId)(nil), + } + file_fishjam_server_notifications_proto_msgTypes[22].OneofWrappers = []any{ + (*ServerMessage_ChannelRemoved_PeerId)(nil), + (*ServerMessage_ChannelRemoved_ComponentId)(nil), + } + file_fishjam_server_notifications_proto_msgTypes[23].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_fishjam_server_notifications_proto_rawDesc), len(file_fishjam_server_notifications_proto_rawDesc)), + NumEnums: 2, + NumMessages: 31, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_fishjam_server_notifications_proto_goTypes, + DependencyIndexes: file_fishjam_server_notifications_proto_depIdxs, + EnumInfos: file_fishjam_server_notifications_proto_enumTypes, + MessageInfos: file_fishjam_server_notifications_proto_msgTypes, + }.Build() + File_fishjam_server_notifications_proto = out.File + file_fishjam_server_notifications_proto_goTypes = nil + file_fishjam_server_notifications_proto_depIdxs = nil +} diff --git a/conference-to-stream/docker-compose.yml b/conference-to-stream/docker-compose.yml new file mode 100644 index 0000000..a53723f --- /dev/null +++ b/conference-to-stream/docker-compose.yml @@ -0,0 +1,20 @@ +services: + backend: + build: + context: ./backend + ports: + - "8080:8080" + environment: + FISHJAM_ID: ${FISHJAM_ID} + FISHJAM_MANAGEMENT_TOKEN: ${FISHJAM_MANAGEMENT_TOKEN} + PORT: 8080 + restart: unless-stopped + + web: + build: + context: ./web + ports: + - "5173:80" + depends_on: + - backend + restart: unless-stopped diff --git a/conference-to-stream/web/.gitignore b/conference-to-stream/web/.gitignore new file mode 100644 index 0000000..b947077 --- /dev/null +++ b/conference-to-stream/web/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/conference-to-stream/web/Dockerfile b/conference-to-stream/web/Dockerfile new file mode 100644 index 0000000..d1e7480 --- /dev/null +++ b/conference-to-stream/web/Dockerfile @@ -0,0 +1,11 @@ +FROM node:22-alpine AS builder +WORKDIR /app +COPY package.json ./ +RUN npm install +COPY . . +RUN npm run build + +FROM nginx:alpine +COPY --from=builder /app/dist /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/conference-to-stream/web/index.html b/conference-to-stream/web/index.html new file mode 100644 index 0000000..d6ac568 --- /dev/null +++ b/conference-to-stream/web/index.html @@ -0,0 +1,12 @@ + + + + + + Conference to Stream + + +
+ + + diff --git a/conference-to-stream/web/package-lock.json b/conference-to-stream/web/package-lock.json new file mode 100644 index 0000000..19e4e69 --- /dev/null +++ b/conference-to-stream/web/package-lock.json @@ -0,0 +1,2522 @@ +{ + "name": "conference-to-stream-web", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "conference-to-stream-web", + "version": "0.0.0", + "dependencies": { + "@fishjam-cloud/react-client": "^0.25.1", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.13", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "tailwindcss": "^4.1.13", + "typescript": "^5.9.2", + "vite": "^7.1.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@binbat/whip-whep": { + "version": "1.1.1-sdp-trickle-throw", + "resolved": "https://registry.npmjs.org/@binbat/whip-whep/-/whip-whep-1.1.1-sdp-trickle-throw.tgz", + "integrity": "sha512-JFoNBEms4ECrbDd7LG2k5XP2DpGTUMGzaiCK7tjWyHYrrn58eb5BAJAX1GNQhrwkmBCRoIlhGTXULxKo6tsFug==", + "license": "MIT" + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", + "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fishjam-cloud/react-client": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@fishjam-cloud/react-client/-/react-client-0.25.1.tgz", + "integrity": "sha512-Gg/bhpFyd7lZ0TvHPvdYue9Y70wOIvoiq3MPs0SB9maXnBxOJQl2LDO/BEXPtDB0Pz3KAVdHit/VJrVNacFaZQ==", + "license": "Apache-2.0", + "dependencies": { + "@fishjam-cloud/ts-client": "0.25.1", + "events": "3.3.0", + "lodash.isequal": "4.5.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/@fishjam-cloud/ts-client": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@fishjam-cloud/ts-client/-/ts-client-0.25.1.tgz", + "integrity": "sha512-waYluwtjSu0lnl4+8qi4tR5J04pEK04Xx/7xMKDEp5ycXh3iZoUZO9vJvEhMDGjGLiw9JZ9WsffGgP9vkT/Y2A==", + "license": "Apache-2.0", + "dependencies": { + "@binbat/whip-whep": "^1.1.1-sdp-trickle-throw", + "@bufbuild/protobuf": "^2.2.3", + "events": "^3.3.0", + "typed-emitter": "^2.1.0", + "uuid": "^11.1.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", + "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.31.1", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", + "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-x64": "4.2.1", + "@tailwindcss/oxide-freebsd-x64": "4.2.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-x64-musl": "4.2.1", + "@tailwindcss/oxide-wasm32-wasi": "4.2.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", + "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", + "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", + "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", + "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", + "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", + "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", + "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", + "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", + "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", + "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", + "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", + "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.1", + "@tailwindcss/oxide": "4.2.1", + "tailwindcss": "4.2.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", + "integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz", + "integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==", + "license": "MIT", + "optionalDependencies": { + "rxjs": "*" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/conference-to-stream/web/package.json b/conference-to-stream/web/package.json new file mode 100644 index 0000000..cc0ff7a --- /dev/null +++ b/conference-to-stream/web/package.json @@ -0,0 +1,25 @@ +{ + "name": "conference-to-stream-web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@fishjam-cloud/react-client": "^0.25.1", + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.13", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "tailwindcss": "^4.1.13", + "typescript": "^5.9.2", + "vite": "^7.1.7" + } +} diff --git a/conference-to-stream/web/src/App.tsx b/conference-to-stream/web/src/App.tsx new file mode 100644 index 0000000..55e8ada --- /dev/null +++ b/conference-to-stream/web/src/App.tsx @@ -0,0 +1,26 @@ +import { useState } from "react"; +import { Conference } from "./components/Conference"; +import { JoinForm } from "./components/JoinForm"; + +type AppState = + | { status: "idle" } + | { status: "joined"; whepUrl: string }; + +export function App() { + const [state, setState] = useState({ status: "idle" }); + + if (state.status === "joined") { + return ( + setState({ status: "idle" })} + /> + ); + } + + return ( + setState({ status: "joined", whepUrl })} + /> + ); +} diff --git a/conference-to-stream/web/src/api.ts b/conference-to-stream/web/src/api.ts new file mode 100644 index 0000000..a9d4585 --- /dev/null +++ b/conference-to-stream/web/src/api.ts @@ -0,0 +1,31 @@ +const backendUrl = (import.meta.env.VITE_BACKEND_URL as string) || "http://localhost:8080"; + +export type JoinRoomResult = { + roomId: string; + whepUrl: string; +}; + +export type JoinPeerResult = { + peerToken: string; + peerWebsocketUrl: string; +}; + +export async function createRoom(roomName: string): Promise { + const res = await fetch(`${backendUrl}/api/rooms`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ roomName }), + }); + if (!res.ok) throw new Error(`create room failed: ${await res.text()}`); + return res.json(); +} + +export async function createPeer(roomId: string, peerName: string): Promise { + const res = await fetch(`${backendUrl}/api/rooms/${roomId}/peers`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ peerName }), + }); + if (!res.ok) throw new Error(`create peer failed: ${await res.text()}`); + return res.json(); +} diff --git a/conference-to-stream/web/src/components/Conference.tsx b/conference-to-stream/web/src/components/Conference.tsx new file mode 100644 index 0000000..3489c69 --- /dev/null +++ b/conference-to-stream/web/src/components/Conference.tsx @@ -0,0 +1,87 @@ +import { + useCamera, + useConnection, + useMicrophone, + usePeers, +} from "@fishjam-cloud/react-client"; +import { PeerTile } from "./PeerTile"; +import { WhepPlayer } from "./WhepPlayer"; + +type Props = { + whepUrl: string; + onLeave: () => void; +}; + +export function Conference({ whepUrl, onLeave }: Props) { + const { leaveRoom } = useConnection(); + const { isCameraOn, toggleCamera, cameraStream } = useCamera(); + const { isMicrophoneMuted, toggleMicrophoneMute } = useMicrophone(); + const { localPeer, remotePeers } = usePeers<{ name: string }>(); + + async function handleLeave() { + await leaveRoom(); + onLeave(); + } + + return ( +
+ {/* Header */} +
+

Conference to Stream

+
+ + + +
+
+ + {/* Main content */} +
+ {/* Peer grid */} +
+

Conference

+
+ + {remotePeers.map((peer) => ( + + ))} +
+
+ + {/* WHEP preview */} +
+

Live Stream Preview

+ +

Composed stream via Foundry

+
+
+
+ ); +} diff --git a/conference-to-stream/web/src/components/JoinForm.tsx b/conference-to-stream/web/src/components/JoinForm.tsx new file mode 100644 index 0000000..46910cf --- /dev/null +++ b/conference-to-stream/web/src/components/JoinForm.tsx @@ -0,0 +1,84 @@ +import { useConnection, useInitializeDevices } from "@fishjam-cloud/react-client"; +import { useEffect, useState } from "react"; +import { createPeer, createRoom } from "../api"; + +type Props = { + onJoined: (whepUrl: string) => void; +}; + +export function JoinForm({ onJoined }: Props) { + const { joinRoom } = useConnection(); + const { initializeDevices } = useInitializeDevices(); + const [roomName, setRoomName] = useState(""); + const [peerName, setPeerName] = useState(""); + const [error, setError] = useState(""); + const [loading, setLoading] = useState(false); + + useEffect(() => { + // initializeDevices({ enableVideo: true, enableAudio: true }); + }, [initializeDevices]); + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + if (!roomName.trim() || !peerName.trim()) { + setError("Please fill in both fields."); + return; + } + setError(""); + setLoading(true); + try { + const { roomId, whepUrl } = await createRoom(roomName.trim()); + const { peerToken } = await createPeer(roomId, peerName.trim()); + await joinRoom({ peerToken, peerMetadata: { name: peerName.trim() } }); + onJoined(whepUrl); + } catch (err) { + setError(err instanceof Error ? err.message : "Something went wrong."); + } finally { + setLoading(false); + } + } + + return ( +
+
+

Conference to Stream

+ + + + + + {error &&

{error}

} + + +
+
+ ); +} diff --git a/conference-to-stream/web/src/components/PeerTile.tsx b/conference-to-stream/web/src/components/PeerTile.tsx new file mode 100644 index 0000000..ea008c9 --- /dev/null +++ b/conference-to-stream/web/src/components/PeerTile.tsx @@ -0,0 +1,48 @@ +import { useEffect, useRef } from "react"; + +type Props = { + stream?: MediaStream; + audioStream?: MediaStream; + name: string; +}; + +export function PeerTile({ stream, audioStream, name }: Props) { + const videoRef = useRef(null); + const audioRef = useRef(null); + + useEffect(() => { + if (videoRef.current && stream) { + videoRef.current.srcObject = stream; + } + }, [stream]); + + useEffect(() => { + if (audioRef.current && audioStream) { + audioRef.current.srcObject = audioStream; + } + }, [audioStream]); + + return ( +
+ {stream ? ( +
+ ); +} diff --git a/conference-to-stream/web/src/components/WhepPlayer.tsx b/conference-to-stream/web/src/components/WhepPlayer.tsx new file mode 100644 index 0000000..5a52c74 --- /dev/null +++ b/conference-to-stream/web/src/components/WhepPlayer.tsx @@ -0,0 +1,53 @@ +import { useEffect, useRef, useState } from "react"; +import { initializeWhep } from "../whep"; + +type Props = { + url: string; +}; + +export function WhepPlayer({ url }: Props) { + const videoRef = useRef(null); + const [error, setError] = useState(""); + + useEffect(() => { + let cancelled = false; + let peerConnection: RTCPeerConnection | null = null; + + initializeWhep(url) + .then(({ stream, peer }) => { + peerConnection = peer; + if (!cancelled && videoRef.current) { + videoRef.current.srcObject = stream; + } else { + peer.close(); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err instanceof Error ? err.message : "WHEP connection failed"); + } + }); + + return () => { + cancelled = true; + peerConnection?.close(); + }; + }, [url]); + + if (error) { + return ( +
+ {error} +
+ ); + } + + return ( +