Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
node_modules
.DS_STORE
.wrangler

/.cache
/build
/dist
/public/build
/.mf
.env
.dev.vars
.sentryclirc
public/mockServiceWorker.js

tailwind.config.js
remix.config.js
20 changes: 19 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: ['@remix-run/eslint-config', '@remix-run/eslint-config/node'],
reportUnusedDisableDirectives: true,
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2020,
EXPERIMENTAL_useProjectService: true,
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
'plugin:deprecation/recommended',
],
ignorePatterns: ['/public/noise/*'],
rules: {
'no-mixed-spaces-and-tabs': ['error', 'smart-tabs'],
'@typescript-eslint/no-extra-semi': ['off'],
'@typescript-eslint/no-unused-vars': [
'warn',
Expand All @@ -14,4 +31,5 @@ module.exports = {
},
],
},
root: true,
}
4 changes: 3 additions & 1 deletion app/components/AudioGlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export const AudioGlow: FC<AudioGlowProps> = ({
'opacity-[--opacity] transition-opacity',
className
)}
style={{ '--opacity': Math.min(1, audioLevel * 4) } as any}
style={
{ '--opacity': Math.min(1, audioLevel * 4) } as React.CSSProperties
}
aria-hidden
>
{children}
Expand Down
4 changes: 2 additions & 2 deletions app/components/AudioIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const AudioIndicator: FC<AudioIndicatorProps> = ({ audioTrack }) => {
style={
{
'--scale': Math.max(minSize, audioLevel + scaleModifier),
} as any
} as React.CSSProperties
}
></div>
<div
Expand All @@ -27,7 +27,7 @@ export const AudioIndicator: FC<AudioIndicatorProps> = ({ audioTrack }) => {
style={
{
'--scale': Math.max(minSize, audioLevel + scaleModifier),
} as any
} as React.CSSProperties
}
></div>
</div>
Expand Down
1 change: 1 addition & 0 deletions app/components/AudioInputSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const AudioInputSelector: FC<{ id?: string }> = ({ id }) => {

return (
<div className="max-w-[40ch]">
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */}
<Select id={id} value={audioDeviceId} onValueChange={setAudioDeviceId}>
{audioInputDevices.map((d) => (
<Option key={d.deviceId} value={d.deviceId}>
Expand Down
11 changes: 9 additions & 2 deletions app/components/AudioStream.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ export const AudioStream: FC<AudioStreamProps> = ({
// need to set srcObject again in Chrome and call play() again for Safari
// https://www.youtube.com/live/Tkx3OGrwVk8?si=K--P_AzNnAGrjraV&t=2533
// calling play() this way to make Chrome happy otherwise it throws an error
audio.addEventListener('canplay', () => audio.play(), { once: true })
audio.addEventListener(
'canplay',
() => {
audio.play().catch(console.error)
},
{ once: true }
)
audio.srcObject = mediaStream
}

return (
<>
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
<audio ref={ref} autoPlay />
{tracksToPull.map((track) => (
<AudioTrack
Expand Down Expand Up @@ -98,7 +105,7 @@ function AudioTrack({
mediaStream.removeTrack(audioTrack)
onTrackRemovedRef.current(track, audioTrack)
}
}, [audioTrack])
}, [audioTrack, mediaStream, track])

return null
}
3 changes: 1 addition & 2 deletions app/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const displayTypeMap = {
],
}

export type ButtonProps = Omit<JSX.IntrinsicElements['button'], 'ref'> & {
export type ButtonProps = Omit<React.JSX.IntrinsicElements['button'], 'ref'> & {
displayType?: keyof typeof displayTypeMap
}

Expand Down Expand Up @@ -59,7 +59,6 @@ export const ButtonLink = forwardRef<
displayType?: keyof typeof displayTypeMap
}
>(({ className, displayType = 'primary', ...rest }, ref) => (
// eslint-disable-next-line jsx-a11y/anchor-has-content
<Link
className={cn(
'inline-block',
Expand Down
12 changes: 9 additions & 3 deletions app/components/CopyButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ export const CopyButton: FC<CopyButtonProps> = () => {
<Button
displayType="secondary"
onClick={() => {
navigator.clipboard.writeText(roomUrl)
setCopied(true)
reset()
navigator.clipboard.writeText(roomUrl).then(
() => {
setCopied(true)
reset()
},
(err) => {
console.error('Failed to copy to clipboard', err)
}
)
}}
>
<Icon
Expand Down
4 changes: 2 additions & 2 deletions app/components/EnsurePermissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type PermissionState = 'denied' | 'granted' | 'prompt' | 'unable-to-determine'
async function getExistingPermissionState(): Promise<PermissionState> {
try {
const query = await navigator.permissions.query({
name: 'microphone' as any,
name: 'microphone' as PermissionName,
})
return query.state
} catch (error) {
Expand All @@ -27,7 +27,7 @@ export function EnsurePermissions(props: EnsurePermissionsProps) {
useEffect(() => {
getExistingPermissionState().then((result) => {
if (mountedRef.current) setPermissionState(result)
})
}, console.error)
return () => {
mountedRef.current = false
}
Expand Down
2 changes: 1 addition & 1 deletion app/components/HoverFade.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const HoverFade: FC<HoverFadeProps> = ({
const [visible, setVisible] = useState(false)

useEffect(() => {
let mounted = true
const mounted = true
if (visible) {
const t = setTimeout(() => {
if (mounted) setVisible(false)
Expand Down
2 changes: 1 addition & 1 deletion app/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ interface IconProps {
}

export const Icon: FC<
IconProps & Omit<JSX.IntrinsicElements['svg'], 'ref'>
IconProps & Omit<React.JSX.IntrinsicElements['svg'], 'ref'>
> = ({ type, className, ...rest }) => {
const Component = iconMap[type]
return <Component className={cn('h-[1em]', className)} {...rest} />
Expand Down
2 changes: 1 addition & 1 deletion app/components/Icon/custom/MicrophoneSlashIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { FC } from 'react'

export const MicrophoneSlashIcon: FC<JSX.IntrinsicElements['svg']> = (
export const MicrophoneSlashIcon: FC<React.JSX.IntrinsicElements['svg']> = (
props
) => {
return (
Expand Down
2 changes: 1 addition & 1 deletion app/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { cn } from '~/utils/style'

export const Input = forwardRef<
HTMLInputElement,
JSX.IntrinsicElements['input']
React.JSX.IntrinsicElements['input']
>(({ className, ...rest }, ref) => (
<input
className={cn(
Expand Down
2 changes: 1 addition & 1 deletion app/components/Participant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { VideoSrcObject } from './VideoSrcObject'

export const Participant = forwardRef<
HTMLDivElement,
JSX.IntrinsicElements['div'] & {
React.JSX.IntrinsicElements['div'] & {
flipId: string
isScreenShare?: boolean
user: User
Expand Down
2 changes: 1 addition & 1 deletion app/components/ReportBugDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const ReportBugDialog: FC<ReportBugDialogProps> = ({ onOpenChange }) => {
)
}

const ReportBugForm: FC<{}> = () => {
const ReportBugForm: FC = () => {
const { Form, data, state } = useFetcher()
const { room, roomHistory } = useRoomContext()
const { roomName } = useParams()
Expand Down
2 changes: 1 addition & 1 deletion app/components/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { cn } from '~/utils/style'

export const TextArea = forwardRef<
HTMLTextAreaElement,
JSX.IntrinsicElements['textarea']
React.JSX.IntrinsicElements['textarea']
>(({ className, ...rest }, ref) => (
<textarea
ref={ref}
Expand Down
8 changes: 7 additions & 1 deletion app/components/VideoInputSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ export const VideoInputSelector: FC<{ id?: string }> = ({ id }) => {

return (
<div className="max-w-[40ch]">
<Select value={shownDeviceId} onValueChange={setVideoDeviceId} id={id}>
<Select
value={shownDeviceId}
onValueChange={(id) => {
setVideoDeviceId(id).catch(console.error)
}}
id={id}
>
{videoInputDevices.map((d) => (
<Option key={d.deviceId} value={d.deviceId}>
{d.label}
Expand Down
3 changes: 2 additions & 1 deletion app/components/VideoSrcObject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { forwardRef, useEffect, useRef } from 'react'
import { cn } from '~/utils/style'

export type VideoSrcObjectProps = Omit<
JSX.IntrinsicElements['video'],
React.JSX.IntrinsicElements['video'],
'ref'
> & {
videoTrack?: MediaStreamTrack
Expand All @@ -29,6 +29,7 @@ export const VideoSrcObject = forwardRef<HTMLVideoElement, VideoSrcObjectProps>(
}, [videoTrack])

return (
// eslint-disable-next-line jsx-a11y/media-has-caption
<video
className={cn('bg-zinc-700', className)}
ref={(v) => {
Expand Down
21 changes: 11 additions & 10 deletions app/durableObjects/ChatRoom.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ export class ChatRoom extends Server<Env> {
)
)

if (!this.ctx.storage.getAlarm()) {
if (!(await this.ctx.storage.getAlarm())) {
// start the alarm to broadcast state every 30 seconds
this.ctx.storage.setAlarm(30000)
this.ctx.storage.setAlarm(Date.now() + 30000).catch(() => {
console.warn('Failed to set alarm')
})
}

// cleaning out storage used by older versions of this code
Expand Down Expand Up @@ -86,17 +88,14 @@ export class ChatRoom extends Server<Env> {
)
}

async onMessage(
connection: Connection<User>,
message: WSMessage
): Promise<void> {
onMessage(connection: Connection<User>, message: WSMessage): void {
try {
if (typeof message !== 'string') {
console.warn('Received non-string message')
return
}

let data: ClientMessage = JSON.parse(message)
const data = JSON.parse(message) as ClientMessage

switch (data.type) {
case 'userLeft':
Expand All @@ -106,7 +105,7 @@ export class ChatRoom extends Server<Env> {
connection.setState(data.user)
this.broadcastState()
break
case 'directMessage':
case 'directMessage': {
const { to, message } = data

for (const otherConnection of this.getConnections<User>()) {
Expand All @@ -123,7 +122,7 @@ export class ChatRoom extends Server<Env> {
`User with id "${to}" not found, cannot send DM from "${connection.state!.name}"`
)
break

}
case 'muteUser':
{
let mutedUser = false
Expand Down Expand Up @@ -187,6 +186,8 @@ export class ChatRoom extends Server<Env> {
// technically we don't need to broadcast state on an alarm,
// but let's keep it for a while and see if it's useful
this.broadcastState()
this.ctx.storage.setAlarm(30000)
this.ctx.storage.setAlarm(Date.now() + 30000).catch(() => {
console.warn('Failed to set alarm')
})
}
}
2 changes: 1 addition & 1 deletion app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function handleRequest(
remixContext: EntryContext
) {
try {
let markup = renderToString(
const markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
).replace(
'__CLIENT_ENV__',
Expand Down
1 change: 1 addition & 0 deletions app/hooks/useBroadcastStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default function useBroadcastStatus({
},
}

// eslint-disable-next-line no-inner-declarations
function sendUserUpdate() {
websocket.send(
JSON.stringify({
Expand Down
2 changes: 1 addition & 1 deletion app/hooks/useConditionForAtLeast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export function useConditionForAtLeast(condition: boolean, time: number) {
const [value, setValue] = useState(condition)

useEffect(() => {
let timeout = window.setTimeout(() => {
const timeout = window.setTimeout(() => {
setValue(condition)
}, time)
return () => {
Expand Down
5 changes: 2 additions & 3 deletions app/hooks/useDeadPulledTrackMonitor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function useDeadPulledTrackMonitor(
// reset this to -1 for the check above
timeoutRef.current = -1
}
}, [deadTrack, enabled, feedbackEnabled, peer, track])
}, [deadTrack, enabled, feedbackEnabled, peer, peerConnection, track])

useEffect(() => {
if (!sessionId || !deadTrack || !feedbackEnabled) return
Expand All @@ -56,7 +56,7 @@ export function useDeadPulledTrackMonitor(
fetch('/api/deadTrack', {
method: 'POST',
body: JSON.stringify(info),
})
}).catch(console.error)
}
}, [
deadTrack,
Expand All @@ -65,7 +65,6 @@ export function useDeadPulledTrackMonitor(
name,
sessionId,
room.identity?.name,
sessionId,
traceLink,
trackInfo,
])
Expand Down
2 changes: 1 addition & 1 deletion app/hooks/useIsSpeaking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function useIsSpeaking(mediaStreamTrack?: MediaStreamTrack) {
useEffect(() => {
isSpeakingRef.current = isSpeaking
const interval = window.setInterval(() => {
// state is already in sync — do nothing
// state is already in syncdo nothing
if (isSpeaking === isSpeakingRef.current) {
return
}
Expand Down
2 changes: 1 addition & 1 deletion app/hooks/useRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default function useRoom({
party: 'rooms',
room: roomName,
onMessage: (e) => {
const message = JSON.parse(e.data) as ServerMessage
const message = JSON.parse(e.data as string) as ServerMessage
switch (message.type) {
case 'roomState':
// prevent updating state if nothing has changed
Expand Down
Loading