feat: basic livekit setup

This commit is contained in:
2024-09-19 19:39:55 +01:00
parent 1121d8d56a
commit 6bc882fd41
6 changed files with 424 additions and 16 deletions

View File

@ -4,6 +4,8 @@
"dependencies": { "dependencies": {
"@cashu/cashu-ts": "^1.0.0-rc.3", "@cashu/cashu-ts": "^1.0.0-rc.3",
"@here/maps-api-for-javascript": "^1.50.0", "@here/maps-api-for-javascript": "^1.50.0",
"@livekit/components-react": "^2.5.4",
"@livekit/protocol": "^1.22.0",
"@noble/curves": "^1.4.0", "@noble/curves": "^1.4.0",
"@noble/hashes": "^1.4.0", "@noble/hashes": "^1.4.0",
"@scure/base": "^1.1.6", "@scure/base": "^1.1.6",
@ -29,6 +31,7 @@
"highlight.js": "^11.8.0", "highlight.js": "^11.8.0",
"latlon-geohash": "^2.0.0", "latlon-geohash": "^2.0.0",
"light-bolt11-decoder": "^2.1.0", "light-bolt11-decoder": "^2.1.0",
"livekit-client": "^2.5.2",
"lottie-react": "^2.4.0", "lottie-react": "^2.4.0",
"marked": "^9.1.0", "marked": "^9.1.0",
"marked-footnote": "^1.0.0", "marked-footnote": "^1.0.0",

View File

@ -1,18 +1,35 @@
import { NostrEvent, NostrLink } from "@snort/system"; import { NostrLink, TaggedNostrEvent } from "@snort/system";
import { useState } from "react"; import { lazy, Suspense, useState } from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import Icon from "@/Components/Icons/Icon"; import Icon from "@/Components/Icons/Icon";
import { findTag } from "@/Utils"; import { findTag } from "@/Utils";
import { extractStreamInfo } from "@/Utils/stream";
import NoteAppHandler from "../Event/Note/NoteAppHandler";
import ProfileImage from "../User/ProfileImage"; import ProfileImage from "../User/ProfileImage";
const LiveKitRoom = lazy(() => import("./livekit"));
export function LiveEvent({ ev }: { ev: NostrEvent }) {
const title = findTag(ev, "title"); export function LiveEvent({ ev }: { ev: TaggedNostrEvent }) {
const status = findTag(ev, "status"); const service = ev.tags.find(a => a[0] === "streaming")?.at(1);
const starts = Number(findTag(ev, "starts")); function inner() {
const host = ev.tags.find(a => a[0] === "p" && a[3] === "host")?.[1] ?? ev.pubkey; if (service?.endsWith(".m3u8")) {
return <LiveStreamEvent ev={ev} />
} else if (service?.startsWith("wss+livekit://")) {
return <Suspense>
<LiveKitRoom ev={ev} canJoin={true} />
</Suspense>
}
return <NoteAppHandler ev={ev} />
}
return inner();
}
function LiveStreamEvent({ ev }: { ev: TaggedNostrEvent }) {
const { title, status, starts, host } = extractStreamInfo(ev);
const [play, setPlay] = useState(false); const [play, setPlay] = useState(false);
function statusLine() { function statusLine() {
@ -38,7 +55,7 @@ export function LiveEvent({ ev }: { ev: NostrEvent }) {
return ( return (
<b className="uppercase"> <b className="uppercase">
{new Intl.DateTimeFormat(undefined, { dateStyle: "full", timeStyle: "short" }).format( {new Intl.DateTimeFormat(undefined, { dateStyle: "full", timeStyle: "short" }).format(
new Date(starts * 1000), new Date(Number(starts) * 1000),
)} )}
</b> </b>
); );
@ -73,8 +90,6 @@ export function LiveEvent({ ev }: { ev: NostrEvent }) {
const link = `https://zap.stream/embed/${NostrLink.fromEvent(ev).encode()}`; const link = `https://zap.stream/embed/${NostrLink.fromEvent(ev).encode()}`;
return ( return (
<iframe <iframe
// eslint-disable-next-line react/no-unknown-property
credentialless=""
src={link} src={link}
width="100%" width="100%"
style={{ style={{
@ -86,7 +101,7 @@ export function LiveEvent({ ev }: { ev: NostrEvent }) {
return ( return (
<div className="sm:flex g12 br p24 bg-primary items-center"> <div className="sm:flex g12 br p24 bg-primary items-center">
<div> <div>
<ProfileImage pubkey={host} showUsername={false} size={56} /> <ProfileImage pubkey={host!} showUsername={false} size={56} />
</div> </div>
<div className="flex flex-col g8 grow"> <div className="flex flex-col g8 grow">
<div className="font-semibold text-3xl">{title}</div> <div className="font-semibold text-3xl">{title}</div>

View File

@ -0,0 +1,117 @@
import { LiveKitRoom as LiveKitRoomContext, RoomAudioRenderer, useParticipants } from "@livekit/components-react";
import { dedupe, unixNow } from "@snort/shared";
import { EventKind, NostrLink, RequestBuilder, TaggedNostrEvent } from "@snort/system";
import { useRequestBuilder, useUserProfile } from "@snort/system-react";
import { LocalParticipant, RemoteParticipant } from "livekit-client";
import { useEffect, useMemo, useState } from "react";
import { FormattedMessage } from "react-intl";
import useEventPublisher from "@/Hooks/useEventPublisher";
import { extractStreamInfo } from "@/Utils/stream";
import AsyncButton from "../Button/AsyncButton";
import { ProxyImg } from "../ProxyImg";
import Avatar from "../User/Avatar";
import { AvatarGroup } from "../User/AvatarGroup";
import DisplayName from "../User/DisplayName";
export default function LiveKitRoom({ ev, canJoin }: { ev: TaggedNostrEvent, canJoin?: boolean }) {
const { stream, service, id } = extractStreamInfo(ev);
const { publisher } = useEventPublisher();
const [join, setJoin] = useState(false);
const [token, setToken] = useState<string>();
async function getToken() {
if (!service || !publisher)
return;
const url = `${service}/api/v1/nests/${id}`;
const auth = await publisher.generic(eb => {
eb.kind(EventKind.HttpAuthentication);
eb.tag(["url", url]);
eb.tag(["u", url])
eb.tag(["method", "GET"]);
return eb;
});
const rsp = await fetch(url, {
headers: {
authorization: `Nostr ${window.btoa(JSON.stringify(auth))}`,
}
});
const text = await rsp.text();
if (rsp.ok) {
return JSON.parse(text) as { token: string };
}
}
useEffect(() => {
if (join && !token) {
getToken().then(t => setToken(t?.token)).catch(console.error);
}
}, [join]);
if (!join) {
return <div className="p flex flex-col gap-2">
<RoomHeader ev={ev} />
{(canJoin ?? false) && <AsyncButton onClick={() => setJoin(true)}>
<FormattedMessage defaultMessage="Join Room" />
</AsyncButton>}
</div>
}
return <LiveKitRoomContext token={token} serverUrl={stream?.replace("wss+livekit://", "wss://")} connect={true}>
<RoomAudioRenderer volume={1} />
<ParticipantList ev={ev} />
</LiveKitRoomContext>
}
function RoomHeader({ ev }: { ev: TaggedNostrEvent }) {
const { image, title } = extractStreamInfo(ev);
return <div className="relative rounded-xl h-[140px] w-full overflow-hidden">
{image ? <ProxyImg src={image} className="w-full" /> :
<div className="absolute bg-gray-dark w-full h-full" />}
<div className="absolute left-4 top-4 w-full flex justify-between pr-4">
<div className="text-2xl">
{title}
</div>
<div>
<NostrParticipants ev={ev} />
</div>
</div>
</div>
}
function ParticipantList({ ev }: { ev: TaggedNostrEvent }) {
const participants = useParticipants()
return <div className="p">
<RoomHeader ev={ev} />
<h3>
<FormattedMessage defaultMessage="Participants" />
</h3>
<div className="grid grid-cols-4">
{participants.map(a => <LiveKitUser p={a} key={a.identity} />)}
</div>
</div>
}
function NostrParticipants({ ev }: { ev: TaggedNostrEvent }) {
const link = NostrLink.fromEvent(ev);
const sub = useMemo(() => {
const sub = new RequestBuilder(`livekit-participants:${link.tagKey}`);
sub.withFilter().replyToLink([link]).kinds([10_312 as EventKind]).since(unixNow() - 600);
return sub;
}, [link.tagKey]);
const presense = useRequestBuilder(sub);
return <AvatarGroup ids={dedupe(presense.map(a => a.pubkey))} size={32} />
}
function LiveKitUser({ p }: { p: RemoteParticipant | LocalParticipant }) {
const pubkey = p.identity.startsWith("guest-") ? "anon" : p.identity
const profile = useUserProfile(pubkey);
return <div className="flex flex-col gap-2 items-center text-center">
<Avatar pubkey={pubkey} className={p.isSpeaking ? "outline" : ""} user={profile} size={48} />
<DisplayName pubkey={pubkey} user={pubkey === "anon" ? { name: "Anon" } : profile} />
</div>
}

View File

@ -3,10 +3,10 @@ import React from "react";
import ProfileImage from "@/Components/User/ProfileImage"; import ProfileImage from "@/Components/User/ProfileImage";
export function AvatarGroup({ ids, onClick }: { ids: HexKey[]; onClick?: () => void }) { export function AvatarGroup({ ids, onClick, size }: { ids: HexKey[]; onClick?: () => void, size?: number }) {
return ids.map((a, index) => ( return ids.map((a, index) => (
<div className={`inline-block ${index > 0 ? "-ml-4" : ""}`} key={a} style={{ zIndex: ids.length - index }}> <div className={`inline-block ${index > 0 ? "-ml-4" : ""}`} key={a} style={{ zIndex: ids.length - index }}>
<ProfileImage link="" onClick={onClick} showFollowDistance={false} pubkey={a} size={24} showUsername={false} /> <ProfileImage link="" onClick={onClick} showFollowDistance={false} pubkey={a} size={size ?? 24} showUsername={false} />
</div> </div>
)); ));
} }

View File

@ -0,0 +1,72 @@
import { TaggedNostrEvent } from "@snort/system";
export function getHost(ev?: TaggedNostrEvent) {
return ev?.tags.find(a => a[0] === "p" && a[3] === "host")?.[1] ?? ev?.pubkey ?? "";
}
export type StreamState = "live" | "ended" | "planned";
export interface StreamInfo {
id?: string;
title?: string;
summary?: string;
image?: string;
thumbnail?: string;
status?: StreamState;
stream?: string;
recording?: string;
contentWarning?: string;
tags: Array<string>;
goal?: string;
participants?: string;
starts?: string;
ends?: string;
service?: string;
host?: string;
gameId?: string;
}
const gameTagFormat = /^[a-z-]+:[a-z0-9-]+$/i;
export function extractStreamInfo(ev?: TaggedNostrEvent) {
const ret = {
host: getHost(ev),
} as StreamInfo;
const matchTag = (tag: Array<string>, k: string, into: (v: string) => void) => {
if (tag[0] === k) {
into(tag[1]);
}
};
for (const t of ev?.tags ?? []) {
matchTag(t, "d", v => (ret.id = v));
matchTag(t, "title", v => (ret.title = v));
matchTag(t, "summary", v => (ret.summary = v));
matchTag(t, "image", v => (ret.image = v));
matchTag(t, "thumbnail", v => (ret.thumbnail = v));
matchTag(t, "status", v => (ret.status = v as StreamState));
if (t[0] === "streaming") {
matchTag(t, "streaming", v => (ret.stream = v));
}
matchTag(t, "recording", v => (ret.recording = v));
matchTag(t, "url", v => (ret.recording = v));
matchTag(t, "content-warning", v => (ret.contentWarning = v));
matchTag(t, "current_participants", v => (ret.participants = v));
matchTag(t, "goal", v => (ret.goal = v));
matchTag(t, "starts", v => (ret.starts = v));
matchTag(t, "ends", v => (ret.ends = v));
matchTag(t, "service", v => (ret.service = v));
}
const { regularTags } = sortStreamTags(ev?.tags ?? []);
ret.tags = regularTags;
return ret;
}
export function sortStreamTags(tags: Array<string | Array<string>>) {
const plainTags = tags.filter(a => (Array.isArray(a) ? a[0] === "t" : true)).map(a => (Array.isArray(a) ? a[1] : a));
const regularTags = plainTags.filter(a => !a.match(gameTagFormat)) ?? [];
const prefixedTags = plainTags.filter(a => !regularTags.includes(a));
return { regularTags, prefixedTags };
}

207
yarn.lock
View File

@ -2640,6 +2640,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@bufbuild/protobuf@npm:^1.10.0, @bufbuild/protobuf@npm:^1.7.2":
version: 1.10.0
resolution: "@bufbuild/protobuf@npm:1.10.0"
checksum: 10/1f120f72bbb40dd3d0f8c73f1474b001cfb9be09c38b7b0292e35fec98c5184a3db380a6feff7626fb3fff108c8a8aa7fc8cfea14904dc0a1174a01c8e637cc6
languageName: node
linkType: hard
"@cashu/cashu-ts@npm:^1.0.0-rc.3": "@cashu/cashu-ts@npm:^1.0.0-rc.3":
version: 1.0.0-rc.3 version: 1.0.0-rc.3
resolution: "@cashu/cashu-ts@npm:1.0.0-rc.3" resolution: "@cashu/cashu-ts@npm:1.0.0-rc.3"
@ -3447,6 +3454,32 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@floating-ui/core@npm:^1.6.0":
version: 1.6.8
resolution: "@floating-ui/core@npm:1.6.8"
dependencies:
"@floating-ui/utils": "npm:^0.2.8"
checksum: 10/87d52989c3d2cc80373bc153b7a40814db3206ce7d0b2a2bdfb63e2ff39ffb8b999b1b0ccf28e548000ebf863bf16e2bed45eab4c4d287a5dbe974ef22368d82
languageName: node
linkType: hard
"@floating-ui/dom@npm:1.6.11":
version: 1.6.11
resolution: "@floating-ui/dom@npm:1.6.11"
dependencies:
"@floating-ui/core": "npm:^1.6.0"
"@floating-ui/utils": "npm:^0.2.8"
checksum: 10/8579392ad10151474869e7640af169b0d7fc2df48d4da27b6dcb1a57202329147ed986b2972787d4b8cd550c87897271b2d9c4633c2ec7d0b3ad37ce1da636f1
languageName: node
linkType: hard
"@floating-ui/utils@npm:^0.2.8":
version: 0.2.8
resolution: "@floating-ui/utils@npm:0.2.8"
checksum: 10/3e3ea3b2de06badc4baebdf358b3dbd77ccd9474a257a6ef237277895943db2acbae756477ec64de65a2a1436d94aea3107129a1feeef6370675bf2b161c1abc
languageName: node
linkType: hard
"@formatjs/cli@npm:^6.1.3": "@formatjs/cli@npm:^6.1.3":
version: 6.2.4 version: 6.2.4
resolution: "@formatjs/cli@npm:6.2.4" resolution: "@formatjs/cli@npm:6.2.4"
@ -4035,6 +4068,56 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@livekit/components-core@npm:0.11.5":
version: 0.11.5
resolution: "@livekit/components-core@npm:0.11.5"
dependencies:
"@floating-ui/dom": "npm:1.6.11"
loglevel: "npm:1.9.1"
rxjs: "npm:7.8.1"
peerDependencies:
"@livekit/protocol": ^1.20.1
livekit-client: ^2.4.0
tslib: ^2.6.2
checksum: 10/e3ac4f501fb2a733a2e66d0dedf690c1ef9d868ec28896508b4600034dbe7a07b012562ec4e78f94a31884fc0bd5ca1205aa63b24abf84bb87a464c2304ea127
languageName: node
linkType: hard
"@livekit/components-react@npm:^2.5.4":
version: 2.5.4
resolution: "@livekit/components-react@npm:2.5.4"
dependencies:
"@livekit/components-core": "npm:0.11.5"
clsx: "npm:2.1.1"
usehooks-ts: "npm:3.1.0"
peerDependencies:
"@livekit/protocol": ^1.20.1
livekit-client: ^2.4.0
react: ">=18"
react-dom: ">=18"
tslib: ^2.6.2
checksum: 10/0e76bc4d39fdc363ce5a28c09ee1ad146f35d5c5032dd14eb5255805106f7b895f87c1658691e52c9d52b29061b4e065d8503e8e7a656d70d0876e6140953f2a
languageName: node
linkType: hard
"@livekit/protocol@npm:1.20.1":
version: 1.20.1
resolution: "@livekit/protocol@npm:1.20.1"
dependencies:
"@bufbuild/protobuf": "npm:^1.7.2"
checksum: 10/bbc24985bb12d39eed487e8a9daca088e768b084b0860171cc72b29cd92c2ca91fce7ef899fcd8b49522ba79a8db480bdd6343c6e5ddaa8f6df9345fc4e1c515
languageName: node
linkType: hard
"@livekit/protocol@npm:^1.22.0":
version: 1.22.0
resolution: "@livekit/protocol@npm:1.22.0"
dependencies:
"@bufbuild/protobuf": "npm:^1.10.0"
checksum: 10/2ce29e2371a58921bdb3318a9f33ef09a6ca589b5abe03dc7e68f52450ca3f127191c8eec85c271b62dedeca4623ba799ccb7f52c3c2076137cfdc459588da72
languageName: node
linkType: hard
"@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1": "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1":
version: 5.1.1-v1 version: 5.1.1-v1
resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1" resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1"
@ -4639,6 +4722,8 @@ __metadata:
"@cashu/cashu-ts": "npm:^1.0.0-rc.3" "@cashu/cashu-ts": "npm:^1.0.0-rc.3"
"@formatjs/cli": "npm:^6.1.3" "@formatjs/cli": "npm:^6.1.3"
"@here/maps-api-for-javascript": "npm:^1.50.0" "@here/maps-api-for-javascript": "npm:^1.50.0"
"@livekit/components-react": "npm:^2.5.4"
"@livekit/protocol": "npm:^1.22.0"
"@noble/curves": "npm:^1.4.0" "@noble/curves": "npm:^1.4.0"
"@noble/hashes": "npm:^1.4.0" "@noble/hashes": "npm:^1.4.0"
"@scure/base": "npm:^1.1.6" "@scure/base": "npm:^1.1.6"
@ -4691,6 +4776,7 @@ __metadata:
highlight.js: "npm:^11.8.0" highlight.js: "npm:^11.8.0"
latlon-geohash: "npm:^2.0.0" latlon-geohash: "npm:^2.0.0"
light-bolt11-decoder: "npm:^2.1.0" light-bolt11-decoder: "npm:^2.1.0"
livekit-client: "npm:^2.5.2"
lottie-react: "npm:^2.4.0" lottie-react: "npm:^2.4.0"
marked: "npm:^9.1.0" marked: "npm:^9.1.0"
marked-footnote: "npm:^1.0.0" marked-footnote: "npm:^1.0.0"
@ -4752,7 +4838,7 @@ __metadata:
resolution: "@snort/system-react@workspace:packages/system-react" resolution: "@snort/system-react@workspace:packages/system-react"
dependencies: dependencies:
"@snort/shared": "npm:^1.0.17" "@snort/shared": "npm:^1.0.17"
"@snort/system": "npm:^1.5.0" "@snort/system": "npm:^1.5.1"
"@types/react": "npm:^18.2.14" "@types/react": "npm:^18.2.14"
react: "npm:^18.2.0" react: "npm:^18.2.0"
typescript: "npm:^5.2.2" typescript: "npm:^5.2.2"
@ -4787,7 +4873,7 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@snort/system@npm:^1.0.21, @snort/system@npm:^1.2.11, @snort/system@npm:^1.5.0, @snort/system@workspace:*, @snort/system@workspace:packages/system": "@snort/system@npm:^1.0.21, @snort/system@npm:^1.2.11, @snort/system@npm:^1.5.1, @snort/system@workspace:*, @snort/system@workspace:packages/system":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@snort/system@workspace:packages/system" resolution: "@snort/system@workspace:packages/system"
dependencies: dependencies:
@ -4829,7 +4915,7 @@ __metadata:
"@lightninglabs/lnc-web": "npm:^0.3.1-alpha" "@lightninglabs/lnc-web": "npm:^0.3.1-alpha"
"@scure/base": "npm:^1.1.6" "@scure/base": "npm:^1.1.6"
"@snort/shared": "npm:^1.0.17" "@snort/shared": "npm:^1.0.17"
"@snort/system": "npm:^1.5.0" "@snort/system": "npm:^1.5.1"
"@types/debug": "npm:^4.1.12" "@types/debug": "npm:^4.1.12"
"@webbtc/webln-types": "npm:^3.0.0" "@webbtc/webln-types": "npm:^3.0.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
@ -7143,6 +7229,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"clsx@npm:2.1.1":
version: 2.1.1
resolution: "clsx@npm:2.1.1"
checksum: 10/cdfb57fa6c7649bbff98d9028c2f0de2f91c86f551179541cf784b1cfdc1562dcb951955f46d54d930a3879931a980e32a46b598acaea274728dbe068deca919
languageName: node
linkType: hard
"co@npm:^4.6.0": "co@npm:^4.6.0":
version: 4.6.0 version: 4.6.0
resolution: "co@npm:4.6.0" resolution: "co@npm:4.6.0"
@ -8927,6 +9020,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"events@npm:^3.3.0":
version: 3.3.0
resolution: "events@npm:3.3.0"
checksum: 10/a3d47e285e28d324d7180f1e493961a2bbb4cad6412090e4dec114f4db1f5b560c7696ee8e758f55e23913ede856e3689cd3aa9ae13c56b5d8314cd3b3ddd1be
languageName: node
linkType: hard
"execa@npm:^5.0.0": "execa@npm:^5.0.0":
version: 5.1.1 version: 5.1.1
resolution: "execa@npm:5.1.1" resolution: "execa@npm:5.1.1"
@ -11087,6 +11187,22 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"livekit-client@npm:^2.5.2":
version: 2.5.2
resolution: "livekit-client@npm:2.5.2"
dependencies:
"@livekit/protocol": "npm:1.20.1"
events: "npm:^3.3.0"
loglevel: "npm:^1.8.0"
sdp-transform: "npm:^2.14.1"
ts-debounce: "npm:^4.0.0"
tslib: "npm:2.7.0"
typed-emitter: "npm:^2.1.0"
webrtc-adapter: "npm:^9.0.0"
checksum: 10/d1be5b6969c7b8261eb74199ce1bee8a0204d0b38bc445563e9a11423bb002ed376a236fc9276378f7f5d4c8ec792222caa2963956dc506e1b4c090512898ab5
languageName: node
linkType: hard
"local-pkg@npm:^0.4.3": "local-pkg@npm:^0.4.3":
version: 0.4.3 version: 0.4.3
resolution: "local-pkg@npm:0.4.3" resolution: "local-pkg@npm:0.4.3"
@ -11161,6 +11277,20 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"loglevel@npm:1.9.1":
version: 1.9.1
resolution: "loglevel@npm:1.9.1"
checksum: 10/863cbbcddf850a937482c604e2d11586574a5110b746bb49c7cc04739e01f6035f6db841d25377106dd330bca7142d74995f15a97c5f3ea0af86d9472d4a99f4
languageName: node
linkType: hard
"loglevel@npm:^1.8.0":
version: 1.9.2
resolution: "loglevel@npm:1.9.2"
checksum: 10/6153d8db308323f7ee20130bc40309e7a976c30a10379d8666b596d9c6441965c3e074c8d7ee3347fe5cfc059c0375b6f3e8a10b93d5b813cc5547f5aa412a29
languageName: node
linkType: hard
"lokijs@npm:^1.5.12": "lokijs@npm:^1.5.12":
version: 1.5.12 version: 1.5.12
resolution: "lokijs@npm:1.5.12" resolution: "lokijs@npm:1.5.12"
@ -13517,6 +13647,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"rxjs@npm:*, rxjs@npm:7.8.1":
version: 7.8.1
resolution: "rxjs@npm:7.8.1"
dependencies:
tslib: "npm:^2.1.0"
checksum: 10/b10cac1a5258f885e9dd1b70d23c34daeb21b61222ee735d2ec40a8685bdca40429000703a44f0e638c27a684ac139e1c37e835d2a0dc16f6fc061a138ae3abb
languageName: node
linkType: hard
"safe-array-concat@npm:^1.0.1": "safe-array-concat@npm:^1.0.1":
version: 1.0.1 version: 1.0.1
resolution: "safe-array-concat@npm:1.0.1" resolution: "safe-array-concat@npm:1.0.1"
@ -13595,6 +13734,22 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"sdp-transform@npm:^2.14.1":
version: 2.14.2
resolution: "sdp-transform@npm:2.14.2"
bin:
sdp-verify: checker.js
checksum: 10/a6fd2eb5914dcbb80eecf887b5ff15620fbeefa41e750e69d54c5b80fdd37026e969d716f486c567a35d8ab95f33e765d27b0531b741cea2e80593a5cba8a49d
languageName: node
linkType: hard
"sdp@npm:^3.2.0":
version: 3.2.0
resolution: "sdp@npm:3.2.0"
checksum: 10/3ea337c24f91f7429c79b97f1a16c19a5abb3b6672ce7c05cc931314af1318cdf3a7a88e66ea1ee71e05bf41bf3a20d5940b1c93f3099e820cec60068ddbd9b4
languageName: node
linkType: hard
"semver@npm:^6.3.0, semver@npm:^6.3.1": "semver@npm:^6.3.0, semver@npm:^6.3.1":
version: 6.3.1 version: 6.3.1
resolution: "semver@npm:6.3.1" resolution: "semver@npm:6.3.1"
@ -14506,6 +14661,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ts-debounce@npm:^4.0.0":
version: 4.0.0
resolution: "ts-debounce@npm:4.0.0"
checksum: 10/346a5f753fd2d855befe351c29782ee998c0ecd309f7650082c438ef5833cc4e2c70d8eea5d8a277d5b42fa997a6e9ba9eab5b88edd8d1e8d292367dcd09ef8b
languageName: node
linkType: hard
"ts-interface-checker@npm:^0.1.9": "ts-interface-checker@npm:^0.1.9":
version: 0.1.13 version: 0.1.13
resolution: "ts-interface-checker@npm:0.1.13" resolution: "ts-interface-checker@npm:0.1.13"
@ -14610,6 +14772,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"tslib@npm:2.7.0, tslib@npm:^2.1.0":
version: 2.7.0
resolution: "tslib@npm:2.7.0"
checksum: 10/9a5b47ddac65874fa011c20ff76db69f97cf90c78cff5934799ab8894a5342db2d17b4e7613a087046bc1d133d21547ddff87ac558abeec31ffa929c88b7fce6
languageName: node
linkType: hard
"tslib@npm:^1.8.1": "tslib@npm:^1.8.1":
version: 1.14.1 version: 1.14.1
resolution: "tslib@npm:1.14.1" resolution: "tslib@npm:1.14.1"
@ -14778,6 +14947,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"typed-emitter@npm:^2.1.0":
version: 2.1.0
resolution: "typed-emitter@npm:2.1.0"
dependencies:
rxjs: "npm:*"
dependenciesMeta:
rxjs:
optional: true
checksum: 10/95821a9e05784b972cc9d152891fd12a56cb4b1a7c57e768c02bea6a8984da7aff8f19404a7b69eea11fae2a3b6c0c510a4c510f575f50162c759ae9059f2520
languageName: node
linkType: hard
"typedarray-to-buffer@npm:^3.1.5": "typedarray-to-buffer@npm:^3.1.5":
version: 3.1.5 version: 3.1.5
resolution: "typedarray-to-buffer@npm:3.1.5" resolution: "typedarray-to-buffer@npm:3.1.5"
@ -15050,6 +15231,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"usehooks-ts@npm:3.1.0":
version: 3.1.0
resolution: "usehooks-ts@npm:3.1.0"
dependencies:
lodash.debounce: "npm:^4.0.8"
peerDependencies:
react: ^16.8.0 || ^17 || ^18
checksum: 10/6aef8affd3c053a3040b7421816dab85eb21601c5203496a705bafc32eb973fb519a2b0ddda527962e361d248f3a1c49df130620efe871c8f89e897451ed1cc7
languageName: node
linkType: hard
"utf-8-validate@npm:^5.0.2": "utf-8-validate@npm:^5.0.2":
version: 5.0.10 version: 5.0.10
resolution: "utf-8-validate@npm:5.0.10" resolution: "utf-8-validate@npm:5.0.10"
@ -15394,6 +15586,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"webrtc-adapter@npm:^9.0.0":
version: 9.0.1
resolution: "webrtc-adapter@npm:9.0.1"
dependencies:
sdp: "npm:^3.2.0"
checksum: 10/5e73ddb6fb807e28fc4bb727bdee2717a697bcf24cfbe1e401c5a3c57d61627fa000b6185470ec3c9fcc1dca42093b67776742c7fde7002fbc14da272a020cbf
languageName: node
linkType: hard
"websocket-polyfill@npm:^0.0.3": "websocket-polyfill@npm:^0.0.3":
version: 0.0.3 version: 0.0.3
resolution: "websocket-polyfill@npm:0.0.3" resolution: "websocket-polyfill@npm:0.0.3"