diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..4942bd08 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,28 @@ +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint", "react-hooks", "react-refresh"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier", + ], + rules: { + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/consistent-type-imports": "error", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + "no-console": ["error", { allow: ["warn", "error"] }], + "react-hooks/exhaustive-deps": "error", + "react-hooks/rules-of-hooks": "error", + "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], + }, +}; diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml index cc120d49..a7767e96 100644 --- a/.github/workflows/node.yaml +++ b/.github/workflows/node.yaml @@ -29,7 +29,7 @@ jobs: run: yarn - name: Build 📦 - run: npm run build + run: yarn build - name: Run types 👮 run: yarn tsc diff --git a/examples/react-client/minimal-react/.eslintignore copy b/examples/react-client/minimal-react/.eslintignore copy new file mode 100644 index 00000000..16c5327c --- /dev/null +++ b/examples/react-client/minimal-react/.eslintignore copy @@ -0,0 +1,2 @@ +dist + diff --git a/examples/react-client/minimal-react/.eslintrc b/examples/react-client/minimal-react/.eslintrc new file mode 100644 index 00000000..3316dedb --- /dev/null +++ b/examples/react-client/minimal-react/.eslintrc @@ -0,0 +1,4 @@ +{ + "extends": ["../../../.eslintrc.js"], + "ignorePatterns": ["lib"], +} diff --git a/examples/react-client/minimal-react/package.json b/examples/react-client/minimal-react/package.json index c973fcf2..c305bcaa 100644 --- a/examples/react-client/minimal-react/package.json +++ b/examples/react-client/minimal-react/package.json @@ -8,7 +8,11 @@ "dev": "vite", "build": "tsc && vite build", "watch": "tsc --noEmit --watch", - "preview": "vite preview" + "preview": "vite preview", + "format": "prettier --write . --ignore-path ./.eslintignore", + "format:check": "prettier --check . --ignore-path ./.eslintignore", + "lint": "eslint . --ext .ts,.tsx --fix", + "lint:check": "eslint . --ext .ts,.tsx" }, "dependencies": { "@fishjam-dev/react-client": "*", diff --git a/examples/react-client/minimal-react/src/components/App.tsx b/examples/react-client/minimal-react/src/components/App.tsx index 839f3977..76dd2ad3 100644 --- a/examples/react-client/minimal-react/src/components/App.tsx +++ b/examples/react-client/minimal-react/src/components/App.tsx @@ -2,7 +2,13 @@ import VideoPlayer from "./VideoPlayer"; import type { Client } from "@fishjam-dev/react-client"; import { SCREEN_SHARING_MEDIA_CONSTRAINTS } from "@fishjam-dev/react-client"; import { useState } from "react"; -import { useConnect, useDisconnect, useClient, useStatus, useTracks } from "./client"; +import { + useConnect, + useDisconnect, + useClient, + useStatus, + useTracks, +} from "./client"; // Example metadata types for peer and track // You can define your own metadata types just make sure they are serializable @@ -26,12 +32,18 @@ export const App = () => { { // for e2e test const client = useClient(); - (window as unknown as { client: Client }).client = client!; + ( + window as unknown as { client: Client } + ).client = client!; } return (
- setToken(() => e?.target?.value)} placeholder="token" /> + setToken(() => e?.target?.value)} + placeholder="token" + />
{name} - {(devices || []).map(({ deviceId, label }) => (
@@ -184,7 +197,8 @@

type="text" id="peer-token-input" placeholder="" - class="input-bordered input-info input w-full" /> + class="input-bordered input-info input w-full" + />
@@ -195,7 +209,8 @@

type="text" id="peer-name-input" placeholder="" - class="input-bordered input-success input w-full" /> + class="input-bordered input-success input w-full" + />

@@ -234,7 +249,8 @@

Canvas track

id="local-track-video" class="w-[200px]" playsinline - muted> + muted + > diff --git a/examples/ts-client/simple-app/package.json b/examples/ts-client/simple-app/package.json index 711cb668..870bc4e4 100644 --- a/examples/ts-client/simple-app/package.json +++ b/examples/ts-client/simple-app/package.json @@ -7,7 +7,11 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "preview": "vite preview" + "preview": "vite preview", + "format": "prettier --write . --ignore-path ./.eslintignore", + "format:check": "prettier --check . --ignore-path ./.eslintignore", + "lint": "eslint . --ext .ts,.tsx --fix", + "lint:check": "eslint . --ext .ts,.tsx" }, "devDependencies": { "autoprefixer": "^10.4.17", diff --git a/examples/ts-client/simple-app/src/createMockStream.ts b/examples/ts-client/simple-app/src/createMockStream.ts index 78894c7e..c2117789 100644 --- a/examples/ts-client/simple-app/src/createMockStream.ts +++ b/examples/ts-client/simple-app/src/createMockStream.ts @@ -10,11 +10,11 @@ export const createStream: ( backgroundColor: string, framerate: number, ) => { - const canvasElement = document.createElement('canvas'); + const canvasElement = document.createElement("canvas"); canvasElement.width = canvasWidth; canvasElement.height = canvasHeight; - const ctx = canvasElement.getContext('2d'); - if (!ctx) throw 'ctx is null'; + const ctx = canvasElement.getContext("2d"); + if (!ctx) throw "ctx is null"; const fontSize = 150; let degree = 0; @@ -33,7 +33,7 @@ export const createStream: ( ctx.font = `${fontSize}px Calibri`; ctx.translate(translateX, translateY); ctx.rotate(radian); - ctx.fillStyle = '#FFFFFF'; + ctx.fillStyle = "#FFFFFF"; ctx.fillText(emoji, -fontSize / 2, +fontSize / 2); // ctx.fillStyle = "#FF00FF"; // ctx.fillRect(0, 0, 10, 10); diff --git a/examples/ts-client/simple-app/src/main.ts b/examples/ts-client/simple-app/src/main.ts index cddc6f18..13cbae04 100644 --- a/examples/ts-client/simple-app/src/main.ts +++ b/examples/ts-client/simple-app/src/main.ts @@ -1,56 +1,57 @@ -import './style.css'; +import "./style.css"; -import { createStream } from './createMockStream'; -import { FishjamClient, TrackEncoding, Peer } from '@fishjam-dev/ts-client'; +import { createStream } from "./createMockStream"; +import type { TrackEncoding, Peer } from "@fishjam-dev/ts-client"; +import { FishjamClient } from "@fishjam-dev/ts-client"; import { enumerateDevices, getUserMedia, SCREEN_SHARING_MEDIA_CONSTRAINTS, -} from '@fishjam-dev/browser-media-utils'; +} from "@fishjam-dev/browser-media-utils"; /* eslint-disable no-console */ const peerTokenInput = - document.querySelector('#peer-token-input')!; + document.querySelector("#peer-token-input")!; const peerNameInput = - document.querySelector('#peer-name-input')!; + document.querySelector("#peer-name-input")!; const connectButton = - document.querySelector('#connect-btn')!; + document.querySelector("#connect-btn")!; const disconnectButton = - document.querySelector('#disconnect-btn')!; + document.querySelector("#disconnect-btn")!; const reconnectButton = - document.querySelector('#reconnect-btn')!; + document.querySelector("#reconnect-btn")!; const forceErrorButton = - document.querySelector('#force-error-btn')!; + document.querySelector("#force-error-btn")!; const forceCloseButton = - document.querySelector('#force-close-btn')!; + document.querySelector("#force-close-btn")!; const addTrackButton = - document.querySelector('#add-track-btn')!; + document.querySelector("#add-track-btn")!; const removeTrackButton = - document.querySelector('#remove-track-btn')!; + document.querySelector("#remove-track-btn")!; const localVideo = - document.querySelector('#local-track-video')!; + document.querySelector("#local-track-video")!; const enumerateDevicesButton = document.querySelector( - '#enumerate-devices-btn', + "#enumerate-devices-btn", )!; const screenSharingContainer = document.querySelector( - '#screen-sharing-container', + "#screen-sharing-container", )!; -const templateVideoPlayer = document.querySelector('#video-player-template')!; -const ENCODINGS: TrackEncoding[] = ['l', 'm', 'h']; +const templateVideoPlayer = document.querySelector("#video-player-template")!; +const ENCODINGS: TrackEncoding[] = ["l", "m", "h"]; const elementsToShowIfConnected = - document.querySelectorAll('.show-if-connected'); -elementsToShowIfConnected.forEach((e) => e.classList.add('hidden')); + document.querySelectorAll(".show-if-connected"); +elementsToShowIfConnected.forEach((e) => e.classList.add("hidden")); const borderActiveClasses = [ - 'border-success', - 'border-4', - 'rounded-3', - 'border-solid', + "border-success", + "border-4", + "rounded-3", + "border-solid", ]; -const stream = createStream('🧪', 'black', 24).stream; +const stream = createStream("🧪", "black", 24).stream; localVideo.srcObject = stream; type Track = { @@ -71,15 +72,15 @@ localVideo.play(); const inputArray = [peerTokenInput, peerNameInput]; inputArray.forEach((input) => { - input.value = localStorage.getItem(input.id) || ''; + input.value = localStorage.getItem(input.id) || ""; // eslint-disable-next-line @typescript-eslint/no-explicit-any - input.addEventListener('input', (event: any) => { + input.addEventListener("input", (event: any) => { localStorage.setItem(input.id, event.target?.value); }); }); -const TrackTypeValues = ['screensharing', 'camera', 'audio'] as const; +const TrackTypeValues = ["screensharing", "camera", "audio"] as const; export type TrackType = (typeof TrackTypeValues)[number]; export type PeerMetadata = { @@ -92,10 +93,10 @@ export type TrackMetadata = { const isPeerMetadata = (input: unknown): input is PeerMetadata => { return ( - typeof input === 'object' && + typeof input === "object" && input !== null && - 'name' in input && - typeof input['name'] === 'string' + "name" in input && + typeof input["name"] === "string" ); }; @@ -103,22 +104,22 @@ const isTrackType = (input: unknown): input is TrackType => TrackTypeValues.includes(input as TrackType); const isTrackMetadata = (input: unknown): input is TrackMetadata => - typeof input === 'object' && + typeof input === "object" && input !== null && - 'type' in input && + "type" in input && isTrackType(input.type) && - 'active' in input && - typeof input.active === 'boolean'; + "active" in input && + typeof input.active === "boolean"; const trackMetadataParser = (input: unknown): TrackMetadata => { if (isTrackMetadata(input)) return input; - throw Error('Invalid track metadata'); + throw Error("Invalid track metadata"); }; const peerMetadataParser = (input: unknown): PeerMetadata => { if (isPeerMetadata(input)) return input; - throw Error('Invalid peer metadata'); + throw Error("Invalid peer metadata"); }; const client: FishjamClient = new FishjamClient({ @@ -129,37 +130,37 @@ const client: FishjamClient = new FishjamClient({ (window as unknown as { client: typeof client }).client = client; -client.on('socketClose', () => { - toastInfo('Socket closed'); +client.on("socketClose", () => { + toastInfo("Socket closed"); }); -client.on('socketError', () => { - toastAlert('Socket error'); +client.on("socketError", () => { + toastAlert("Socket error"); }); -client.on('authSuccess', () => { - toastSuccess('Auth success'); +client.on("authSuccess", () => { + toastSuccess("Auth success"); }); -client.on('authError', () => { - toastAlert('Auth error'); +client.on("authError", () => { + toastAlert("Auth error"); }); -client.on('disconnected', () => { - toastInfo('Disconnected'); +client.on("disconnected", () => { + toastInfo("Disconnected"); }); -client.on('trackAdded', (ctx) => { - console.log({ name: 'trackAdded', ctx }); +client.on("trackAdded", (ctx) => { + console.log({ name: "trackAdded", ctx }); }); client.on( - 'joined', + "joined", (_peerId: string, peersInRoom: Peer[]) => { - console.log('Join success!'); + console.log("Join success!"); toastSuccess(`Joined room`); - const template = document.querySelector('#remote-peer-template-card')!; - const remotePeers = document.querySelector('#remote-peers')!; + const template = document.querySelector("#remote-peer-template-card")!; + const remotePeers = document.querySelector("#remote-peers")!; (peersInRoom || []).forEach((peer: Peer) => { // @ts-ignore @@ -167,7 +168,7 @@ client.on( const card = clone.firstElementChild; card.dataset.peerId = peer.id; - const peerId = clone.querySelector('.remote-peer-template-id'); + const peerId = clone.querySelector(".remote-peer-template-id"); peerId.innerHTML = peer.id; clone.firstElementChild.dataset.peerId = peer.id; @@ -178,23 +179,23 @@ client.on( }, ); -client.on('joinError', (metadata) => { - console.log({ name: 'joinError', metadata }); - toastAlert('Join error'); +client.on("joinError", (metadata) => { + console.log({ name: "joinError", metadata }); + toastAlert("Join error"); }); -client.on('peerJoined', (peer: Peer) => { - console.log('Peer join success!'); +client.on("peerJoined", (peer: Peer) => { + console.log("Peer join success!"); - const template = document.querySelector('#remote-peer-template-card')!; - const remotePeers = document.querySelector('#remote-peers')!; + const template = document.querySelector("#remote-peer-template-card")!; + const remotePeers = document.querySelector("#remote-peers")!; // @ts-ignore const clone = template.content.cloneNode(true); const card = clone.firstElementChild; card.dataset.peerId = peer.id; - const peerId = clone.querySelector('.remote-peer-template-id'); + const peerId = clone.querySelector(".remote-peer-template-id"); peerId.innerHTML = peer.id; clone.firstElementChild.dataset.peerId = peer.id; @@ -204,9 +205,9 @@ client.on('peerJoined', (peer: Peer) => { toastInfo(`New peer joined`); }); -client.on('peerUpdated', (_peer) => {}); +client.on("peerUpdated", (_peer) => {}); -client.on('peerLeft', (peer) => { +client.on("peerLeft", (peer) => { const peerComponent = document.querySelector( `div[data-peer-id="${peer.id}"`, )!; @@ -217,7 +218,7 @@ client.on('peerLeft', (peer) => { const setupSimulcastCheckbox = ( element: DocumentFragment, trackId: string, - encoding: 'l' | 'm' | 'h', + encoding: "l" | "m" | "h", ) => { const simulcastInputL: HTMLInputElement | null = element.querySelector( @@ -225,9 +226,9 @@ const setupSimulcastCheckbox = ( ); if (!simulcastInputL) return; - simulcastInputL.setAttribute('name', `${trackId}-simulcast`); + simulcastInputL.setAttribute("name", `${trackId}-simulcast`); - simulcastInputL.addEventListener('click', () => { + simulcastInputL.addEventListener("click", () => { if (client.getRemoteTracks()[trackId]?.simulcastConfig?.enabled) { client.setTargetTrackEncoding(trackId, encoding); } else { @@ -241,17 +242,17 @@ const setupSimulcastCheckbox = ( }); }; -client.on('trackReady', (ctx) => { - console.log({ name: 'On track ready', ctx }); +client.on("trackReady", (ctx) => { + console.log({ name: "On track ready", ctx }); if (!ctx.trackId) return; const peerId = ctx.endpoint.id; const peerComponent = document.querySelector(`div[data-peer-id="${peerId}"`)!; const videoPlayerTemplate = document.querySelector( - '#remote-peer-template-video', + "#remote-peer-template-video", ); - if (!videoPlayerTemplate) throw new Error('Remote video template not found'); + if (!videoPlayerTemplate) throw new Error("Remote video template not found"); const videoWrapper = ( videoPlayerTemplate.content.cloneNode(true) @@ -259,21 +260,21 @@ client.on('trackReady', (ctx) => { const tracksContainer: HTMLDivElement | null = videoWrapper.querySelector(`.remote-track-container`); - if (!tracksContainer) throw new Error('Remote track container not found'); + if (!tracksContainer) throw new Error("Remote track container not found"); tracksContainer.dataset.trackId = ctx.trackId; const videoPlayer: HTMLVideoElement | null = videoWrapper.querySelector(`video`); - if (!videoPlayer) throw new Error('Video element not found'); + if (!videoPlayer) throw new Error("Video element not found"); - const container = peerComponent.querySelector('.remote-videos'); + const container = peerComponent.querySelector(".remote-videos"); - if (!container) throw new Error('Remote videos container not found!'); + if (!container) throw new Error("Remote videos container not found!"); const simulcastContainer: HTMLDivElement | null = videoWrapper.querySelector(`.simulcast-enabled`); - if (!simulcastContainer) throw new Error('Simulcast container not found'); + if (!simulcastContainer) throw new Error("Simulcast container not found"); simulcastContainer.innerHTML = ( ctx?.simulcastConfig?.enabled ?? false @@ -281,24 +282,24 @@ client.on('trackReady', (ctx) => { const simulcastRadios: HTMLDivElement | null = videoWrapper.querySelector(`.simulcast-radios`); - if (!simulcastRadios) throw new Error('Simulcast radios not found'); + if (!simulcastRadios) throw new Error("Simulcast radios not found"); if (!ctx?.simulcastConfig?.enabled) { - simulcastRadios.classList.add('hidden'); + simulcastRadios.classList.add("hidden"); } ENCODINGS.forEach((encoding) => { setupSimulcastCheckbox(videoWrapper, ctx.trackId, encoding); }); - const rawMetadata = videoWrapper.querySelector('.remote-track-raw-metadata'); - if (!rawMetadata) throw new Error('Raw metadata component not found'); + const rawMetadata = videoWrapper.querySelector(".remote-track-raw-metadata"); + if (!rawMetadata) throw new Error("Raw metadata component not found"); rawMetadata.innerHTML = JSON.stringify(ctx.rawMetadata, undefined, 2); const parsedMetadata = videoWrapper.querySelector( - '.remote-track-parsed-metadata', + ".remote-track-parsed-metadata", ); - if (!parsedMetadata) throw new Error('Parsed metadata component not found'); + if (!parsedMetadata) throw new Error("Parsed metadata component not found"); parsedMetadata.innerHTML = JSON.stringify(ctx.metadata, undefined, 2); container.appendChild(videoWrapper); @@ -309,81 +310,81 @@ client.on('trackReady', (ctx) => { }; }); -client.on('trackUpdated', (ctx) => { - console.log({ name: 'trackUpdated', ctx }); +client.on("trackUpdated", (ctx) => { + console.log({ name: "trackUpdated", ctx }); const videoWrapper: HTMLElement | null = document.querySelector( `div[data-track-id="${ctx.trackId}"`, )!; - const rawMetadata = videoWrapper.querySelector('.remote-track-raw-metadata'); - if (!rawMetadata) throw new Error('Raw metadata component not found'); + const rawMetadata = videoWrapper.querySelector(".remote-track-raw-metadata"); + if (!rawMetadata) throw new Error("Raw metadata component not found"); rawMetadata.innerHTML = JSON.stringify(ctx.rawMetadata, undefined, 2); const parsedMetadata = videoWrapper.querySelector( - '.remote-track-parsed-metadata', + ".remote-track-parsed-metadata", ); - if (!parsedMetadata) throw new Error('Parsed metadata component not found'); + if (!parsedMetadata) throw new Error("Parsed metadata component not found"); parsedMetadata.innerHTML = JSON.stringify(ctx.metadata, undefined, 2); }); -client.on('trackAdded', (ctx) => { - ctx.on('encodingChanged', () => { +client.on("trackAdded", (ctx) => { + ctx.on("encodingChanged", () => { const activeEncodingElement = document.querySelector( `div[data-track-id="${ctx.trackId}"] .simulcast-active-encoding`, )!; - activeEncodingElement.innerHTML = ctx.encoding ?? ''; + activeEncodingElement.innerHTML = ctx.encoding ?? ""; }); - ctx.on('voiceActivityChanged', () => {}); + ctx.on("voiceActivityChanged", () => {}); }); -client.on('trackRemoved', (ctx) => { +client.on("trackRemoved", (ctx) => { const tracksContainer: HTMLElement | null = document.querySelector( `div[data-track-id="${ctx.trackId}"`, ); tracksContainer?.remove(); }); -client.on('trackUpdated', (_ctx) => {}); +client.on("trackUpdated", (_ctx) => {}); -client.on('bandwidthEstimationChanged', (_estimation) => {}); +client.on("bandwidthEstimationChanged", (_estimation) => {}); -client.on('tracksPriorityChanged', (_enabledTracks, _disabledTracks) => {}); +client.on("tracksPriorityChanged", (_enabledTracks, _disabledTracks) => {}); -connectButton.addEventListener('click', () => { - console.log('Connect'); +connectButton.addEventListener("click", () => { + console.log("Connect"); client.connect({ - peerMetadata: { name: peerNameInput.value || '' }, + peerMetadata: { name: peerNameInput.value || "" }, token: peerTokenInput.value, }); - elementsToShowIfConnected.forEach((e) => e.classList.remove('hidden')); + elementsToShowIfConnected.forEach((e) => e.classList.remove("hidden")); }); -disconnectButton.addEventListener('click', () => { - console.log('Disconnect'); +disconnectButton.addEventListener("click", () => { + console.log("Disconnect"); client.disconnect(); - elementsToShowIfConnected.forEach((e) => e.classList.add('hidden')); + elementsToShowIfConnected.forEach((e) => e.classList.add("hidden")); }); -reconnectButton.addEventListener('click', () => { - console.log('Reconnect button'); +reconnectButton.addEventListener("click", () => { + console.log("Reconnect button"); // @ts-expect-error - client['reconnect']?.(); + client["reconnect"]?.(); }); -forceErrorButton.addEventListener('click', () => { - console.log('force error button'); - client['websocket']?.dispatchEvent(new Event('error')); +forceErrorButton.addEventListener("click", () => { + console.log("force error button"); + client["websocket"]?.dispatchEvent(new Event("error")); }); -forceCloseButton.addEventListener('click', () => { - console.log('force close button'); - client['websocket']?.dispatchEvent(new Event('close')); +forceCloseButton.addEventListener("click", () => { + console.log("force close button"); + client["websocket"]?.dispatchEvent(new Event("close")); }); const addTrack = async (stream: MediaStream): Promise => { - console.log('Add track'); + console.log("Add track"); const trackMetadata: TrackMetadata = { - type: 'camera', + type: "camera", active: true, }; const track = stream.getVideoTracks()[0]; @@ -395,53 +396,53 @@ const addTrack = async (stream: MediaStream): Promise => { const removeTrack = (track: Track) => { if (!track) return; - console.log('Remove track'); + console.log("Remove track"); track.id && client.removeTrack(track.id); track.id = null; }; -addTrackButton.addEventListener('click', async () => { +addTrackButton.addEventListener("click", async () => { remoteTracks.canvas = await addTrack(stream); localVideo.classList.add(...borderActiveClasses); }); -removeTrackButton.addEventListener('click', () => { +removeTrackButton.addEventListener("click", () => { removeTrack(remoteTracks.canvas); localVideo.classList.remove(...borderActiveClasses); }); -enumerateDevicesButton.addEventListener('click', () => { +enumerateDevicesButton.addEventListener("click", () => { enumerateDevices(true, false).then((result) => { console.log(result); - if (result.video.type !== 'OK') return; + if (result.video.type !== "OK") return; - const videoPlayers = document.querySelector('#video-players')!; - videoPlayers.innerHTML = ''; + const videoPlayers = document.querySelector("#video-players")!; + videoPlayers.innerHTML = ""; // Video devices views result.video.devices.forEach((device) => { const clone = // @ts-ignore templateVideoPlayer.content.firstElementChild.cloneNode(true); - const videoPlayer = clone.querySelector('.video-player'); + const videoPlayer = clone.querySelector(".video-player"); - clone.querySelector('.device-label').innerHTML = device.label; - clone.querySelector('.device-id').innerHTML = device.deviceId; + clone.querySelector(".device-label").innerHTML = device.label; + clone.querySelector(".device-id").innerHTML = device.deviceId; clone - .querySelector('.start-template-btn') - .addEventListener('click', () => { - console.log('Start'); - getUserMedia(device.deviceId, 'video').then((stream) => { - console.log('Connecting stream'); + .querySelector(".start-template-btn") + .addEventListener("click", () => { + console.log("Start"); + getUserMedia(device.deviceId, "video").then((stream) => { + console.log("Connecting stream"); videoPlayer.srcObject = stream; videoPlayer.play(); }); }); clone - .querySelector('.stop-template-btn') - .addEventListener('click', () => { - console.log('Stop'); + .querySelector(".stop-template-btn") + .addEventListener("click", () => { + console.log("Stop"); const stream = videoPlayer.srcObject; stream.getTracks().forEach((track: MediaStreamTrack) => { track.stop(); @@ -450,8 +451,8 @@ enumerateDevicesButton.addEventListener('click', () => { }); clone - .querySelector('.add-track-template-btn') - .addEventListener('click', async () => { + .querySelector(".add-track-template-btn") + .addEventListener("click", async () => { if (!videoPlayer.srcObject) return; remoteTracks.cameras[device.deviceId] = await addTrack( @@ -461,8 +462,8 @@ enumerateDevicesButton.addEventListener('click', () => { }); clone - .querySelector('.remove-track-template-btn') - .addEventListener('click', () => { + .querySelector(".remove-track-template-btn") + .addEventListener("click", () => { removeTrack(remoteTracks.cameras[device.deviceId]); videoPlayer.classList.remove(...borderActiveClasses); }); @@ -480,24 +481,24 @@ const templateClone = ( screenSharingContainer.appendChild(templateClone); const screenSharingVideo = templateClone.querySelector( - '.video-player', + ".video-player", )! as HTMLVideoElement; templateClone - .querySelector('.start-template-btn')! - .addEventListener('click', async () => { + .querySelector(".start-template-btn")! + .addEventListener("click", async () => { const stream = await navigator.mediaDevices.getDisplayMedia( SCREEN_SHARING_MEDIA_CONSTRAINTS, ); - console.log('Screen sharing stream'); + console.log("Screen sharing stream"); screenSharingVideo.srcObject = stream; await screenSharingVideo.play(); }); templateClone - .querySelector('.stop-template-btn')! - .addEventListener('click', () => { - console.log('Stop screen sharing'); + .querySelector(".stop-template-btn")! + .addEventListener("click", () => { + console.log("Stop screen sharing"); const stream = screenSharingVideo.srcObject as MediaStream; stream?.getTracks().forEach((track: MediaStreamTrack) => { track.stop(); @@ -506,8 +507,8 @@ templateClone }); templateClone - .querySelector('.add-track-template-btn')! - .addEventListener('click', async () => { + .querySelector(".add-track-template-btn")! + .addEventListener("click", async () => { if (!screenSharingVideo.srcObject) return; remoteTracks.screen = await addTrack( @@ -517,25 +518,25 @@ templateClone }); templateClone - .querySelector('.remove-track-template-btn')! - .addEventListener('click', () => { + .querySelector(".remove-track-template-btn")! + .addEventListener("click", () => { removeTrack(remoteTracks.screen); screenSharingVideo.classList.remove(...borderActiveClasses); }); (function hideRemotePeersIfEmpty() { const remotePeersContainer = document.getElementById( - 'remote-peers-container', + "remote-peers-container", )!; - const targetNode = document.getElementById('remote-peers')!; + const targetNode = document.getElementById("remote-peers")!; const config = { childList: true }; const callback = () => { if (targetNode.childElementCount === 0) { - remotePeersContainer.style.display = 'none'; + remotePeersContainer.style.display = "none"; } else { - remotePeersContainer.style.display = ''; + remotePeersContainer.style.display = ""; } }; @@ -547,7 +548,7 @@ templateClone // Toasts const templateAlert = document.getElementById( - 'toast-alert-template', + "toast-alert-template", )! as HTMLTemplateElement; function toastAlert(message: string) { @@ -555,7 +556,7 @@ function toastAlert(message: string) { } const templateInfo = document.getElementById( - 'toast-info-template', + "toast-info-template", )! as HTMLTemplateElement; function toastInfo(message: string) { @@ -563,7 +564,7 @@ function toastInfo(message: string) { } const templateSuccess = document.getElementById( - 'toast-success-template', + "toast-success-template", )! as HTMLTemplateElement; function toastSuccess(message: string) { @@ -572,29 +573,29 @@ function toastSuccess(message: string) { function toast(message: string, template: HTMLTemplateElement) { const hiddenClasses = [ - 'opacity-0', - '-translate-y-4', - 'scale-x-95', - 'h-0', - 'py-0', - 'mt-0', + "opacity-0", + "-translate-y-4", + "scale-x-95", + "h-0", + "py-0", + "mt-0", ]; const visibleClasses = [ - 'opacity-100', - 'translate-y-0', - 'scale-100', - 'h-[60px]', - 'mt-2', + "opacity-100", + "translate-y-0", + "scale-100", + "h-[60px]", + "mt-2", ]; - const toastContainer = document.getElementById('toast-container')!; + const toastContainer = document.getElementById("toast-container")!; const clone = template.content.firstElementChild!.cloneNode( true, )! as HTMLElement; let animationDuration: number = 0; clone.classList.forEach((c) => { - if (c.startsWith('duration-')) { - const [_, d] = c.split('-'); + if (c.startsWith("duration-")) { + const [_, d] = c.split("-"); const parsed = parseInt(d); if (isNaN(parsed)) return; @@ -608,7 +609,7 @@ function toast(message: string, template: HTMLTemplateElement) { clone.classList.add(...visibleClasses); }, 1); - clone.querySelector('.toast-message')!.innerHTML = message; + clone.querySelector(".toast-message")!.innerHTML = message; toastContainer.appendChild(clone); const hideAlert = () => { @@ -620,7 +621,7 @@ function toast(message: string, template: HTMLTemplateElement) { }, animationDuration); }; - clone.addEventListener('click', () => { + clone.addEventListener("click", () => { hideAlert(); }); diff --git a/examples/ts-client/simple-app/tailwind.config.cjs b/examples/ts-client/simple-app/tailwind.config.cjs index 0b328ed4..829c1bdb 100644 --- a/examples/ts-client/simple-app/tailwind.config.cjs +++ b/examples/ts-client/simple-app/tailwind.config.cjs @@ -1,10 +1,10 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ['./index.html', './src/**/*.{js,ts}'], + content: ["./index.html", "./src/**/*.{js,ts}"], theme: { extend: {}, }, - plugins: [require('daisyui')], + plugins: [require("daisyui")], daisyui: { logs: false, }, diff --git a/examples/ts-client/simple-app/vite.config.ts b/examples/ts-client/simple-app/vite.config.ts index 95dc4c3d..8f875455 100644 --- a/examples/ts-client/simple-app/vite.config.ts +++ b/examples/ts-client/simple-app/vite.config.ts @@ -1,5 +1,5 @@ -import { defineConfig } from 'vite'; -import checker from 'vite-plugin-checker'; +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; // import mkcert from 'vite-plugin-mkcert' // https://vitejs.dev/config/ @@ -15,7 +15,7 @@ export default defineConfig({ checker({ typescript: true, eslint: { - lintCommand: 'eslint --ext .ts', + lintCommand: "eslint --ext .ts", }, }), // mkcert(), diff --git a/package.json b/package.json index 44c3da13..4ee2c089 100644 --- a/package.json +++ b/package.json @@ -17,5 +17,15 @@ "format:check": "yarn workspaces foreach -A -p run format:check", "lint": "yarn workspaces foreach -A -p run lint", "lint:check": "yarn workspaces foreach -A -p run lint:check" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^7.14.1", + "@typescript-eslint/parser": "^7.8.0", + "eslint": "^8.55.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.6", + "prettier": "^3.3.0", + "prettier-plugin-tailwindcss": "^0.6.5" } } diff --git a/packages/react-client/.eslintrc b/packages/react-client/.eslintrc index 5add10d3..9f9c7553 100644 --- a/packages/react-client/.eslintrc +++ b/packages/react-client/.eslintrc @@ -1,28 +1,4 @@ { - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "react-hooks", "react-refresh"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "prettier", - ], - "rules": { - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/consistent-type-imports": "error", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "caughtErrorsIgnorePattern": "^_", - }, - ], - "no-console": ["error", { "allow": ["warn", "error"] }], - "react-hooks/exhaustive-deps": "error", - "react-hooks/rules-of-hooks": "error", - "react-refresh/only-export-components": ["warn", { "allowConstantExport": true }], - }, + "extends": ["../../.eslintrc.js"], + "ignorePatterns": ["lib"], } diff --git a/packages/react-client/package.json b/packages/react-client/package.json index 0d7339ef..6497816b 100644 --- a/packages/react-client/package.json +++ b/packages/react-client/package.json @@ -36,9 +36,9 @@ "build": "tsc", "e2e": "NODE_OPTIONS=--dns-result-order=ipv4first playwright test", "docs": "typedoc src src/experimental", - "format:fix": "prettier --write . --ignore-path ./.eslintignore", + "format": "prettier --write . --ignore-path ./.eslintignore", "format:check": "prettier --check . --ignore-path ./.eslintignore", - "lint:fix": "eslint . --ext .ts,.tsx --fix", + "lint": "eslint . --ext .ts,.tsx --fix", "lint:check": "eslint . --ext .ts,.tsx", "prepare": "tsc" }, @@ -48,14 +48,6 @@ "@types/lodash.isequal": "^4.5.8", "@types/node": "^20.11.27", "@types/react": "^18.2.55", - "@typescript-eslint/eslint-plugin": "^7.14.1", - "@typescript-eslint/parser": "^7.8.0", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.6", - "prettier": "^3.3.0", - "prettier-plugin-tailwindcss": "^0.6.5", "react": "^18.2.0", "typed-emitter": "^2.1.0", "typedoc": "^0.26.3", diff --git a/packages/ts-client/.eslintrc b/packages/ts-client/.eslintrc index 86c64dfd..9f9c7553 100644 --- a/packages/ts-client/.eslintrc +++ b/packages/ts-client/.eslintrc @@ -1,24 +1,4 @@ { - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "prettier" - ], - "rules": { - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-explicit-any": "warn", - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "caughtErrorsIgnorePattern": "^_" - } - ], - "no-console": ["error", { "allow": ["warn", "error"] }] - } + "extends": ["../../.eslintrc.js"], + "ignorePatterns": ["lib"], } diff --git a/packages/ts-client/.husky/pre-commit b/packages/ts-client/.husky/pre-commit index 8aff43c0..5dcc1882 100644 --- a/packages/ts-client/.husky/pre-commit +++ b/packages/ts-client/.husky/pre-commit @@ -1,2 +1,2 @@ npx lint-staged -npm run build:check +yarn build \ No newline at end of file diff --git a/packages/ts-client/package.json b/packages/ts-client/package.json index 4122faa0..c869e14a 100644 --- a/packages/ts-client/package.json +++ b/packages/ts-client/package.json @@ -44,17 +44,10 @@ "@types/events": "^3.0.3", "@types/node": "^20.10.3", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^7.14.1", - "@typescript-eslint/parser": "^7.8.0", "@vitest/coverage-v8": "^1.6.0", - "eslint": "^8.55.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-react-hooks": "^4.6.0", "fake-mediastreamtrack": "^1.2.0", "husky": "^9.0.11", "lint-staged": "^15.2.5", - "prettier": "^3.3.0", - "prettier-plugin-tailwindcss": "^0.6.5", "react": "^18.2.0", "ts-proto": "^1.176.0", "typed-emitter": "^2.1.0", diff --git a/packages/ts-client/src/FishjamClient.ts b/packages/ts-client/src/FishjamClient.ts index 74be7632..380fdd0a 100644 --- a/packages/ts-client/src/FishjamClient.ts +++ b/packages/ts-client/src/FishjamClient.ts @@ -1,6 +1,5 @@ -import { +import type { BandwidthLimit, - WebRTCEndpoint, Endpoint, SerializedMediaEvent, SimulcastConfig, @@ -10,12 +9,14 @@ import { MetadataParser, WebRTCEndpointEvents, } from './webrtc'; -import TypedEmitter from 'typed-emitter'; +import { WebRTCEndpoint } from './webrtc'; +import type TypedEmitter from 'typed-emitter'; import { EventEmitter } from 'events'; import { PeerMessage } from './protos'; -import { ReconnectConfig, ReconnectManager } from './reconnection'; -import { AuthErrorReason, isAuthError } from './auth'; -import { Deferred } from './webrtc/deferred'; +import type { ReconnectConfig } from './reconnection'; +import { ReconnectManager } from './reconnection'; +import type { AuthErrorReason } from './auth'; +import { isAuthError } from './auth'; export type Peer = Endpoint< PeerMetadata, diff --git a/packages/ts-client/src/reconnection.ts b/packages/ts-client/src/reconnection.ts index ec8f3fe7..64423263 100644 --- a/packages/ts-client/src/reconnection.ts +++ b/packages/ts-client/src/reconnection.ts @@ -1,5 +1,5 @@ -import { Endpoint } from './webrtc'; -import { FishjamClient, MessageEvents } from './FishjamClient'; +import type { Endpoint } from './webrtc'; +import type { FishjamClient, MessageEvents } from './FishjamClient'; import { isAuthError } from './auth'; export type ReconnectionStatus = 'reconnecting' | 'idle' | 'error'; diff --git a/packages/ts-client/src/webrtc/.eslintrc b/packages/ts-client/src/webrtc/.eslintrc new file mode 100644 index 00000000..944d8e3f --- /dev/null +++ b/packages/ts-client/src/webrtc/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "@typescript-eslint/no-explicit-any": "off", + }, +} diff --git a/packages/ts-client/src/webrtc/bandwidth.ts b/packages/ts-client/src/webrtc/bandwidth.ts index 43793904..f2b93a3b 100644 --- a/packages/ts-client/src/webrtc/bandwidth.ts +++ b/packages/ts-client/src/webrtc/bandwidth.ts @@ -1,4 +1,4 @@ -import { +import type { SimulcastBandwidthLimit, TrackBandwidthLimit, TrackEncoding, diff --git a/packages/ts-client/src/webrtc/bitrate.ts b/packages/ts-client/src/webrtc/bitrate.ts index 30e59b98..7186d89d 100644 --- a/packages/ts-client/src/webrtc/bitrate.ts +++ b/packages/ts-client/src/webrtc/bitrate.ts @@ -1,10 +1,6 @@ -import { - type BandwidthLimit, - RemoteTrackId, - TrackContext, - TrackEncoding, -} from './types'; -import { TrackContextImpl } from './internal'; +import type { RemoteTrackId, TrackContext, TrackEncoding } from './types'; +import { type BandwidthLimit } from './types'; +import type { TrackContextImpl } from './internal'; import { findSender } from './RTCPeerConnectionUtils'; import { generateCustomEvent } from './mediaEvent'; diff --git a/packages/ts-client/src/webrtc/commands.ts b/packages/ts-client/src/webrtc/commands.ts index 8f1d357a..8c4bb850 100644 --- a/packages/ts-client/src/webrtc/commands.ts +++ b/packages/ts-client/src/webrtc/commands.ts @@ -1,5 +1,5 @@ -import { SimulcastConfig, TrackBandwidthLimit } from './types'; -import { Deferred } from './deferred'; +import type { SimulcastConfig, TrackBandwidthLimit } from './types'; +import type { Deferred } from './deferred'; export type AddTrackCommand = { commandType: 'ADD-TRACK'; diff --git a/packages/ts-client/src/webrtc/const.ts b/packages/ts-client/src/webrtc/const.ts index 372c778f..b9483080 100644 --- a/packages/ts-client/src/webrtc/const.ts +++ b/packages/ts-client/src/webrtc/const.ts @@ -1,6 +1,3 @@ -import type { BandwidthLimit, TrackEncoding } from './types'; -// const TEMPORAL_LAYERS_COUNT = 2; - export const simulcastTransceiverConfig: RTCRtpTransceiverInit = { direction: 'sendonly', // keep this array from low resolution to high resolution diff --git a/packages/ts-client/src/webrtc/internal.ts b/packages/ts-client/src/webrtc/internal.ts index cf00586f..ff53c779 100644 --- a/packages/ts-client/src/webrtc/internal.ts +++ b/packages/ts-client/src/webrtc/internal.ts @@ -1,6 +1,6 @@ import EventEmitter from 'events'; -import TypedEmitter from 'typed-emitter'; -import { +import type TypedEmitter from 'typed-emitter'; +import type { EncodingReason, Endpoint, MetadataParser, diff --git a/packages/ts-client/src/webrtc/types.ts b/packages/ts-client/src/webrtc/types.ts index 0c7af5ef..2dfdf6bc 100644 --- a/packages/ts-client/src/webrtc/types.ts +++ b/packages/ts-client/src/webrtc/types.ts @@ -1,5 +1,5 @@ -import TypedEmitter from 'typed-emitter'; -import { SerializedMediaEvent } from './mediaEvent'; +import type TypedEmitter from 'typed-emitter'; +import type { SerializedMediaEvent } from './mediaEvent'; export type MetadataParser = ( rawMetadata: unknown, diff --git a/packages/ts-client/src/webrtc/voiceActivityDetection.ts b/packages/ts-client/src/webrtc/voiceActivityDetection.ts index cdc07f4d..e656dc8f 100644 --- a/packages/ts-client/src/webrtc/voiceActivityDetection.ts +++ b/packages/ts-client/src/webrtc/voiceActivityDetection.ts @@ -1,6 +1,6 @@ -import { MediaEvent } from './mediaEvent'; -import { TrackContextImpl } from './internal'; -import { VadStatus } from './types'; +import type { MediaEvent } from './mediaEvent'; +import type { TrackContextImpl } from './internal'; +import type { VadStatus } from './types'; const vadStatuses = ['speech', 'silence'] as const; diff --git a/packages/ts-client/src/webrtc/webRTCEndpoint.ts b/packages/ts-client/src/webrtc/webRTCEndpoint.ts index cd1ca7a2..75875dbe 100644 --- a/packages/ts-client/src/webrtc/webRTCEndpoint.ts +++ b/packages/ts-client/src/webrtc/webRTCEndpoint.ts @@ -1,23 +1,22 @@ +import type { MediaEvent, SerializedMediaEvent } from './mediaEvent'; import { deserializeMediaEvent, generateCustomEvent, generateMediaEvent, - MediaEvent, - SerializedMediaEvent, serializeMediaEvent, } from './mediaEvent'; import { v4 as uuidv4 } from 'uuid'; import EventEmitter from 'events'; -import TypedEmitter from 'typed-emitter'; +import type TypedEmitter from 'typed-emitter'; import { simulcastTransceiverConfig } from './const'; -import { +import type { AddTrackCommand, Command, RemoveTrackCommand, ReplaceTackCommand, } from './commands'; import { Deferred } from './deferred'; -import { +import type { BandwidthLimit, Config, LocalTrackId, @@ -29,7 +28,8 @@ import { TrackEncoding, WebRTCEndpointEvents, } from './types'; -import { EndpointWithTrackContext, TrackContextImpl } from './internal'; +import type { EndpointWithTrackContext } from './internal'; +import { TrackContextImpl } from './internal'; import { handleVoiceActivationDetectionNotification } from './voiceActivityDetection'; import { applyBandwidthLimitation } from './bandwidth'; import { diff --git a/packages/ts-client/tests/.eslintrc b/packages/ts-client/tests/.eslintrc new file mode 100644 index 00000000..944d8e3f --- /dev/null +++ b/packages/ts-client/tests/.eslintrc @@ -0,0 +1,5 @@ +{ + "rules": { + "@typescript-eslint/no-explicit-any": "off", + }, +} diff --git a/packages/ts-client/tests/events/connectedEvent.test.ts b/packages/ts-client/tests/events/connectedEvent.test.ts index 4b4fff2f..f5161b5b 100644 --- a/packages/ts-client/tests/events/connectedEvent.test.ts +++ b/packages/ts-client/tests/events/connectedEvent.test.ts @@ -4,7 +4,8 @@ import { createSimulcastTrack, trackId, } from '../fixtures'; -import { Endpoint, WebRTCEndpoint } from '../../src'; +import type { Endpoint } from '../../src'; +import { WebRTCEndpoint } from '../../src'; import { expect, vi, it } from 'vitest'; it('Connecting to empty room produce event', () => diff --git a/packages/ts-client/tests/events/trackAddedEvent.test.ts b/packages/ts-client/tests/events/trackAddedEvent.test.ts index 650bf019..b237e929 100644 --- a/packages/ts-client/tests/events/trackAddedEvent.test.ts +++ b/packages/ts-client/tests/events/trackAddedEvent.test.ts @@ -6,7 +6,7 @@ import { createCustomOfferDataEventWithOneVideoTrack, trackId, } from '../fixtures'; -import { CustomOfferDataEvent, TracksAddedMediaEvent } from '../schema'; +import type { CustomOfferDataEvent, TracksAddedMediaEvent } from '../schema'; import { mockRTCPeerConnection } from '../mocks'; import { deserializeMediaEvent } from '../../src/webrtc/mediaEvent'; import { expect, it } from 'vitest'; diff --git a/packages/ts-client/tests/fixtures.ts b/packages/ts-client/tests/fixtures.ts index cc03e8b9..a847b5c1 100644 --- a/packages/ts-client/tests/fixtures.ts +++ b/packages/ts-client/tests/fixtures.ts @@ -1,34 +1,36 @@ -import { +import type { ConnectedMediaEvent, - ConnectedMediaEventSchema, CustomEncodingUpdatedEvent, - CustomEncodingSwitchedEventSchema, CustomOfferDataEvent, - CustomOfferDataEventSchema, CustomSdpAnswerDataEvent, - CustomSdpAnswerDataEventSchema, Endpoint, - EndpointSchema, EndpointUpdatedWebrtcEvent, - EndpointUpdatedWebrtcEventSchema, Track, TracksAddedMediaEvent, - TracksAddedMediaEventSchema, - CustomBandwidthEstimationEventSchema, CustomBandwidthEstimationEvent, CustomVadNotificationEvent, - CustomVadNotificationEventSchema, TrackUpdatedEvent, - TrackUpdatedEventSchema, EndpointAddedWebrtcEvent, - EndpointAddedWebrtcEventSchema, - EndpointRemovedEventSchema, EndpointRemovedEvent, TracksRemovedEvent, +} from './schema'; +import { + ConnectedMediaEventSchema, + CustomEncodingSwitchedEventSchema, + CustomOfferDataEventSchema, + CustomSdpAnswerDataEventSchema, + EndpointSchema, + EndpointUpdatedWebrtcEventSchema, + TracksAddedMediaEventSchema, + CustomBandwidthEstimationEventSchema, + CustomVadNotificationEventSchema, + TrackUpdatedEventSchema, + EndpointAddedWebrtcEventSchema, + EndpointRemovedEventSchema, TracksRemovedEventSchema, } from './schema'; import { FakeMediaStreamTrack } from 'fake-mediastreamtrack'; -import { TrackEncoding, VadStatus } from '../src'; +import type { TrackEncoding, VadStatus } from '../src'; import { vi } from 'vitest'; export const endpointId = 'exampleEndpointId'; diff --git a/packages/ts-client/tests/utils.ts b/packages/ts-client/tests/utils.ts index 1c73e715..c86f2d10 100644 --- a/packages/ts-client/tests/utils.ts +++ b/packages/ts-client/tests/utils.ts @@ -5,7 +5,7 @@ import { createConnectedEventWithOneEndpointWithOneTrack, stream, } from './fixtures'; -import { WebRTCEndpoint } from '../src'; +import type { WebRTCEndpoint } from '../src'; import { mockRTCPeerConnection } from './mocks'; export const setupRoom = ( diff --git a/yarn.lock b/yarn.lock index b8812f60..2c5c8d7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -507,16 +507,8 @@ __metadata: "@types/lodash.isequal": "npm:^4.5.8" "@types/node": "npm:^20.11.27" "@types/react": "npm:^18.2.55" - "@typescript-eslint/eslint-plugin": "npm:^7.14.1" - "@typescript-eslint/parser": "npm:^7.8.0" - eslint: "npm:^8.57.0" - eslint-config-prettier: "npm:^9.1.0" - eslint-plugin-react-hooks: "npm:^4.6.0" - eslint-plugin-react-refresh: "npm:^0.4.6" events: "npm:3.3.0" lodash.isequal: "npm:4.5.0" - prettier: "npm:^3.3.0" - prettier-plugin-tailwindcss: "npm:^0.6.5" react: "npm:^18.2.0" typed-emitter: "npm:^2.1.0" typedoc: "npm:^0.26.3" @@ -533,18 +525,11 @@ __metadata: "@types/events": "npm:^3.0.3" "@types/node": "npm:^20.10.3" "@types/uuid": "npm:^9.0.8" - "@typescript-eslint/eslint-plugin": "npm:^7.14.1" - "@typescript-eslint/parser": "npm:^7.8.0" "@vitest/coverage-v8": "npm:^1.6.0" - eslint: "npm:^8.55.0" - eslint-config-prettier: "npm:^9.1.0" - eslint-plugin-react-hooks: "npm:^4.6.0" events: "npm:^3.3.0" fake-mediastreamtrack: "npm:^1.2.0" husky: "npm:^9.0.11" lint-staged: "npm:^15.2.5" - prettier: "npm:^3.3.0" - prettier-plugin-tailwindcss: "npm:^0.6.5" protobufjs: "npm:^7.3.0" react: "npm:^18.2.0" ts-proto: "npm:^1.176.0" @@ -2294,7 +2279,7 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.55.0, eslint@npm:^8.57.0": +"eslint@npm:^8.55.0": version: 8.57.0 resolution: "eslint@npm:8.57.0" dependencies: @@ -2530,6 +2515,15 @@ __metadata: "fishjam-web-sdk@workspace:.": version: 0.0.0-use.local resolution: "fishjam-web-sdk@workspace:." + dependencies: + "@typescript-eslint/eslint-plugin": "npm:^7.14.1" + "@typescript-eslint/parser": "npm:^7.8.0" + eslint: "npm:^8.55.0" + eslint-config-prettier: "npm:^9.1.0" + eslint-plugin-react-hooks: "npm:^4.6.0" + eslint-plugin-react-refresh: "npm:^0.4.6" + prettier: "npm:^3.3.0" + prettier-plugin-tailwindcss: "npm:^0.6.5" languageName: unknown linkType: soft