From b83fbc5f77a7fb7f3f1f5ae18f93ddf3781fe57f Mon Sep 17 00:00:00 2001
From: Bob Burningham
Date: Sun, 12 Nov 2023 23:30:59 -0800
Subject: [PATCH] added live video. seem broken without ssl
---
.../[serverId]/channels/[channelId]/page.tsx | 69 ++-
.../conversations/[memberId]/page.tsx | 62 ++-
app/api/livekit/route.ts | 35 ++
components/chat/chat-header.tsx | 4 +
components/chat/chat-video-button.tsx | 39 ++
components/media-room.tsx | 67 +++
package-lock.json | 424 +++++++++++++++++-
package.json | 4 +
8 files changed, 656 insertions(+), 48 deletions(-)
create mode 100644 app/api/livekit/route.ts
create mode 100644 components/chat/chat-video-button.tsx
create mode 100644 components/media-room.tsx
diff --git a/app/(main)/(routes)/servers/[serverId]/channels/[channelId]/page.tsx b/app/(main)/(routes)/servers/[serverId]/channels/[channelId]/page.tsx
index 2e30741..99f21e5 100644
--- a/app/(main)/(routes)/servers/[serverId]/channels/[channelId]/page.tsx
+++ b/app/(main)/(routes)/servers/[serverId]/channels/[channelId]/page.tsx
@@ -5,6 +5,8 @@ import { redirect } from "next/navigation";
import { ChatHeader } from "@/components/chat/chat-header";
import { ChatInput } from "@/components/chat/chat-input";
import { ChatMessages } from "@/components/chat/chat-messages";
+import { ChannelType } from "@prisma/client";
+import { MediaRoom } from "@/components/media-room";
interface ChannelIdPageProps {
params: {
@@ -42,29 +44,52 @@ const ChannelIdPage = async ({
return (
-
-
-
+ {channel.type === ChannelType.TEXT && (
+ <>
+
+
+ >
+ )}
+ {channel.type === ChannelType.AUDIO && (
+
+ )}
+ {channel.type === ChannelType.VIDEO && (
+
+ )}
+
)
}
diff --git a/app/(main)/(routes)/servers/[serverId]/conversations/[memberId]/page.tsx b/app/(main)/(routes)/servers/[serverId]/conversations/[memberId]/page.tsx
index 07640f3..9752bd3 100644
--- a/app/(main)/(routes)/servers/[serverId]/conversations/[memberId]/page.tsx
+++ b/app/(main)/(routes)/servers/[serverId]/conversations/[memberId]/page.tsx
@@ -1,6 +1,7 @@
import { ChatHeader } from "@/components/chat/chat-header";
import { ChatInput } from "@/components/chat/chat-input";
import { ChatMessages } from "@/components/chat/chat-messages";
+import { MediaRoom } from "@/components/media-room";
import { getOrCreateConversation } from "@/lib/conversation";
import { currentProfile } from "@/lib/current-profile";
import { db } from "@/lib/db";
@@ -11,11 +12,15 @@ interface MemberIdPageProps{
params: {
serverId: string;
memberId: string;
+ },
+ searchParams: {
+ video?: boolean;
}
}
const MemberIdPage = async ({
- params
+ params,
+ searchParams,
}: MemberIdPageProps) => {
const profile = await currentProfile();
@@ -49,33 +54,44 @@ const MemberIdPage = async ({
return (
-
-
-
+ {searchParams.video && (
+
+ )}
+ {!searchParams.video && (
+ <>
+
+
+ >
+ )}
)
}
diff --git a/app/api/livekit/route.ts b/app/api/livekit/route.ts
new file mode 100644
index 0000000..22f05c1
--- /dev/null
+++ b/app/api/livekit/route.ts
@@ -0,0 +1,35 @@
+import { AccessToken } from "livekit-server-sdk";
+import { NextRequest, NextResponse } from "next/server";
+
+export async function GET(req: NextRequest) {
+ const room = req.nextUrl.searchParams.get("room");
+ const username = req.nextUrl.searchParams.get("username");
+ if (!room) {
+ return NextResponse.json(
+ { error: 'Missing "room" query parameter' },
+ { status: 400 }
+ );
+ } else if (!username) {
+ return NextResponse.json(
+ { error: 'Missing "username" query parameter' },
+ { status: 400 }
+ );
+ }
+
+ const apiKey = process.env.LIVEKIT_API_KEY;
+ const apiSecret = process.env.LIVEKIT_API_SECRET;
+ const wsUrl = process.env.NEXT_PUBLIC_LIVEKIT_URL;
+
+ if (!apiKey || !apiSecret || !wsUrl) {
+ return NextResponse.json(
+ { error: "Server misconfigured" },
+ { status: 500 }
+ );
+ }
+
+ const at = new AccessToken(apiKey, apiSecret, { identity: username });
+
+ at.addGrant({ room, roomJoin: true, canPublish: true, canSubscribe: true });
+
+ return NextResponse.json({ token: at.toJwt() });
+}
\ No newline at end of file
diff --git a/components/chat/chat-header.tsx b/components/chat/chat-header.tsx
index 2e59ee7..9312b40 100644
--- a/components/chat/chat-header.tsx
+++ b/components/chat/chat-header.tsx
@@ -2,6 +2,7 @@ import { Hash, Menu } from "lucide-react"
import { MobileToggle } from "@/components/mobile-toggle";
import { UserAvatar } from "@/components/user-avatar";
import { SocketIndicator } from "@/components/socket-indicator";
+import { ChatVideoButton } from "./chat-video-button";
interface ChatHeaderProps {
serverId: string;
@@ -33,6 +34,9 @@ export const ChatHeader = ({
{name}
+ {type === "conversation" && (
+
+ )}
diff --git a/components/chat/chat-video-button.tsx b/components/chat/chat-video-button.tsx
new file mode 100644
index 0000000..c994682
--- /dev/null
+++ b/components/chat/chat-video-button.tsx
@@ -0,0 +1,39 @@
+"use client";
+
+import qs from "query-string";
+import { usePathname, useRouter, useSearchParams } from "next/navigation";
+import { Video, VideoOff } from "lucide-react";
+
+import { ActionTooltip } from "@/components/action-tooltip";
+
+export const ChatVideoButton = () => {
+ const pathname = usePathname();
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const isVideo = searchParams?.get("video");
+
+ const onClick = () => {
+ const url = qs.stringifyUrl({
+ url: pathname || "",
+ query: {
+ video: isVideo ? undefined : true,
+ }
+ }, { skipNull: true});
+
+ router.push(url);
+ }
+
+ const Icon = isVideo ? VideoOff : Video;
+ const tooltiplabel = isVideo ? "End video call" : "Start video call";
+
+ return (
+
+
+
+
+ )
+
+}
\ No newline at end of file
diff --git a/components/media-room.tsx b/components/media-room.tsx
new file mode 100644
index 0000000..15f26dd
--- /dev/null
+++ b/components/media-room.tsx
@@ -0,0 +1,67 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { LiveKitRoom, VideoConference} from "@livekit/components-react"
+import "@livekit/components-styles"
+import { Channel } from "@prisma/client";
+import { useUser } from "@clerk/nextjs";
+import { Loader2 } from "lucide-react";
+
+interface MediaRoomProps {
+ chatId: string;
+ video: boolean;
+ audio: boolean;
+};
+
+export const MediaRoom = ({
+ chatId,
+ video,
+ audio
+}: MediaRoomProps) => {
+ const { user } = useUser();
+ const [token, setToken] = useState("");
+
+ useEffect(() => {
+ if (!user?.firstName || !user?.lastName) return;
+
+ const name = `${user.firstName} ${user.lastName}`;
+
+ (async () => {
+ try {
+ const resp = await fetch (`/api/livekit?room=${chatId}&username=${name}`);
+ const data = await resp.json();
+ setToken(data.token);
+
+ } catch (e) {
+ console.log(e);
+ }
+ })()
+ }, [user?.firstName, user?.lastName, chatId]);
+
+ if (!token) {
+ return (
+
+ )
+ }
+
+ return (
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 5daa93a..7f59245 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,8 @@
"@emoji-mart/data": "^1.1.2",
"@emoji-mart/react": "^1.1.1",
"@hookform/resolvers": "^3.3.1",
+ "@livekit/components-react": "^1.4.0",
+ "@livekit/components-styles": "^1.0.7",
"@prisma/client": "^5.4.1",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
@@ -37,6 +39,8 @@
"emoji-mart": "^5.5.2",
"eslint": "8.48.0",
"eslint-config-next": "13.4.19",
+ "livekit-client": "^1.14.4",
+ "livekit-server-sdk": "^1.2.7",
"lucide-react": "^0.274.0",
"next": "^13.5.4",
"next-themes": "^0.2.1",
@@ -92,6 +96,11 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@bufbuild/protobuf": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.4.2.tgz",
+ "integrity": "sha512-JyEH8Z+OD5Sc2opSg86qMHn1EM1Sa+zj/Tc0ovxdwk56ByVNONJSabuCUbLQp+eKN3rWNfrho0X+3SEqEPXIow=="
+ },
"node_modules/@clerk/backend": {
"version": "0.30.3",
"resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-0.30.3.tgz",
@@ -414,6 +423,52 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@livekit/components-core": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@livekit/components-core/-/components-core-0.8.0.tgz",
+ "integrity": "sha512-nfJO5BBKR1hvkImsErxl7EwSJMXcZ0xSpHT42sevUeL5VKVYUj5YJFuhOs/xUMx06kBSDNMGHNsjRvbYgLFv0w==",
+ "dependencies": {
+ "@floating-ui/dom": "^1.1.0",
+ "email-regex": "^5.0.0",
+ "loglevel": "^1.8.1",
+ "rxjs": "^7.8.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "livekit-client": "^1.12.0",
+ "tslib": "^2.6.2"
+ }
+ },
+ "node_modules/@livekit/components-react": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@livekit/components-react/-/components-react-1.4.0.tgz",
+ "integrity": "sha512-hcJWM/E9rqa1KH76nLVlbL6twM5W/xUwobSOGwklCxih4D575qd9XWB3hlOHqHL0h1FIvzuhOJgyJ8NXoRpucA==",
+ "dependencies": {
+ "@livekit/components-core": "0.8.0",
+ "@react-hook/latest": "^1.0.3",
+ "clsx": "^2.0.0",
+ "usehooks-ts": "^2.9.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "livekit-client": "^1.12.0",
+ "react": ">=18",
+ "react-dom": ">=18",
+ "tslib": "^2.6.2"
+ }
+ },
+ "node_modules/@livekit/components-styles": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@livekit/components-styles/-/components-styles-1.0.7.tgz",
+ "integrity": "sha512-toGyh1tx9j/pmtN6NtF0mEm/fvSJm0hv5R5pfnjALFle6PksNesGHmpuQ8zHgYxjx6AFuFGHJPJ4j1QAkCcrtw==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/@next/env": {
"version": "13.5.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.4.tgz",
@@ -662,6 +717,60 @@
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.4.1-1.2f302df92bd8945e20ad4595a73def5b96afa54f.tgz",
"integrity": "sha512-+nUQM/y8C+1GG5Ioeqcu6itFslCfxvQSAUVSMC9XM2G2Fcq0F4Afnp6m0pXF6X6iUBWen7jZBPmM9Qlq4Nr3/A=="
},
+ "node_modules/@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+ },
+ "node_modules/@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+ },
+ "node_modules/@protobufjs/codegen": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+ },
+ "node_modules/@protobufjs/eventemitter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+ },
+ "node_modules/@protobufjs/fetch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.1",
+ "@protobufjs/inquire": "^1.1.0"
+ }
+ },
+ "node_modules/@protobufjs/float": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+ },
+ "node_modules/@protobufjs/inquire": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+ },
+ "node_modules/@protobufjs/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+ },
+ "node_modules/@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+ },
+ "node_modules/@protobufjs/utf8": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+ },
"node_modules/@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@@ -1492,6 +1601,14 @@
"@babel/runtime": "^7.13.10"
}
},
+ "node_modules/@react-hook/latest": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
+ "integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
"node_modules/@rushstack/eslint-patch": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz",
@@ -2171,9 +2288,9 @@
}
},
"node_modules/axios": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
- "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
+ "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
@@ -2273,6 +2390,11 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
+ },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
@@ -2905,11 +3027,30 @@
"tslib": "^2.0.3"
}
},
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.508",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz",
"integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg=="
},
+ "node_modules/email-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/email-regex/-/email-regex-5.0.0.tgz",
+ "integrity": "sha512-he76Cm8JFxb6OGQHabLBPdsiStgPmJeAEhctmw0uhonUh1pCBsHpI6/rB62s2GNzjBb0YlhIcF/1l9Lp5AfH0Q==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/emoji-mart": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-5.5.2.tgz",
@@ -3502,6 +3643,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -4398,6 +4547,27 @@
"json5": "lib/cli.js"
}
},
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -4412,6 +4582,25 @@
"node": ">=4.0"
}
},
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
@@ -4458,6 +4647,82 @@
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
+ "node_modules/livekit-client": {
+ "version": "1.14.4",
+ "resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-1.14.4.tgz",
+ "integrity": "sha512-sXNH+qhqkmXeCVsw3hcEbUsh9QfguBIGgM3glM0v0+YW4C2LdeGWD4pQBLR7USbkwbbVMEHDmqr/iY6XvEIoeQ==",
+ "dependencies": {
+ "@bufbuild/protobuf": "^1.3.0",
+ "events": "^3.3.0",
+ "loglevel": "^1.8.0",
+ "sdp-transform": "^2.14.1",
+ "ts-debounce": "^4.0.0",
+ "typed-emitter": "^2.1.0",
+ "webrtc-adapter": "^8.1.1"
+ }
+ },
+ "node_modules/livekit-server-sdk": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/livekit-server-sdk/-/livekit-server-sdk-1.2.7.tgz",
+ "integrity": "sha512-tOhRb0vz1wBzMpTkP4ixptlC9MFME24PvG8Z/R7vBbQ1VGd6EdNr56voBSr+RCalYxaQqx0E9Gg4l+57m/Nlmw==",
+ "dependencies": {
+ "axios": "^1.3.6",
+ "camelcase-keys": "^7.0.0",
+ "jsonwebtoken": "^9.0.0",
+ "long": "^5.0.0",
+ "protobufjs": "^7.2.4"
+ }
+ },
+ "node_modules/livekit-server-sdk/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/livekit-server-sdk/node_modules/camelcase-keys": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz",
+ "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==",
+ "dependencies": {
+ "camelcase": "^6.3.0",
+ "map-obj": "^4.1.0",
+ "quick-lru": "^5.1.1",
+ "type-fest": "^1.2.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/livekit-server-sdk/node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/livekit-server-sdk/node_modules/type-fest": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
+ "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -4472,11 +4737,63 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
+ },
+ "node_modules/loglevel": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz",
+ "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==",
+ "engines": {
+ "node": ">= 0.6.0"
+ },
+ "funding": {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/loglevel"
+ }
+ },
+ "node_modules/long": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
+ "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5131,6 +5448,29 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/protobufjs": {
+ "version": "7.2.5",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz",
+ "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/node": ">=13.7.0",
+ "long": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -5465,6 +5805,14 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/rxjs": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+ "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/safe-array-concat": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz",
@@ -5482,6 +5830,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/safe-regex-test": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
@@ -5503,6 +5870,19 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/sdp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz",
+ "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
+ },
+ "node_modules/sdp-transform": {
+ "version": "2.14.1",
+ "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.1.tgz",
+ "integrity": "sha512-RjZyX3nVwJyCuTo5tGPx+PZWkDMCg7oOLpSlhjDdZfwUoNqG1mM8nyj31IGHyaPWXhjbP7cdK3qZ2bmkJ1GzRw==",
+ "bin": {
+ "sdp-verify": "checker.js"
+ }
+ },
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@@ -5981,6 +6361,11 @@
"typescript": ">=4.2.0"
}
},
+ "node_modules/ts-debounce": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/ts-debounce/-/ts-debounce-4.0.0.tgz",
+ "integrity": "sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg=="
+ },
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -6085,6 +6470,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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==",
+ "optionalDependencies": {
+ "rxjs": "*"
+ }
+ },
"node_modules/typescript": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
@@ -6209,6 +6602,19 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/usehooks-ts": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.9.1.tgz",
+ "integrity": "sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA==",
+ "engines": {
+ "node": ">=16.15.0",
+ "npm": ">=8"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -6258,6 +6664,18 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/webrtc-adapter": {
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz",
+ "integrity": "sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==",
+ "dependencies": {
+ "sdp": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=6.0.0",
+ "npm": ">=3.10.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index 45594bd..b084536 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,8 @@
"@emoji-mart/data": "^1.1.2",
"@emoji-mart/react": "^1.1.1",
"@hookform/resolvers": "^3.3.1",
+ "@livekit/components-react": "^1.4.0",
+ "@livekit/components-styles": "^1.0.7",
"@prisma/client": "^5.4.1",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
@@ -38,6 +40,8 @@
"emoji-mart": "^5.5.2",
"eslint": "8.48.0",
"eslint-config-next": "13.4.19",
+ "livekit-client": "^1.14.4",
+ "livekit-server-sdk": "^1.2.7",
"lucide-react": "^0.274.0",
"next": "^13.5.4",
"next-themes": "^0.2.1",