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 ( +
+ +

+ Loading... +

+
+ ) + } + + 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",