Merge pull request #151 from streamwall/bump-dependencies

Bump-dependencies
This commit is contained in:
Ben Menesini
2024-10-05 14:51:39 -07:00
committed by GitHub
5 changed files with 4681 additions and 2450 deletions

View File

@@ -7,10 +7,12 @@ module.exports = {
'\\.(css|less)$': 'identity-obj-proxy', '\\.(css|less)$': 'identity-obj-proxy',
"^preact(/(.*)|$)": "preact$1" "^preact(/(.*)|$)": "preact$1"
}, },
testEnvironment: 'node',
transform: { transform: {
'^.+\\.jsx?$': 'babel-jest', '^.+\\.jsx?$': 'babel-jest',
}, },
transformIgnorePatterns: [
'node_modules/(?!(jsondiffpatch)/)',
],
testPathIgnorePatterns: ['/node_modules/'], testPathIgnorePatterns: ['/node_modules/'],
coveragePathIgnorePatterns: ['/node_modules/'], coveragePathIgnorePatterns: ['/node_modules/'],
collectCoverage: true, collectCoverage: true,

6645
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,62 +16,63 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",
"@repeaterjs/repeater": "^3.0.4", "@repeaterjs/repeater": "^3.0.6",
"@sentry/electron": "^4.4.0", "@sentry/electron": "^5.3.0",
"base-x": "^4.0.0", "base-x": "^5.0.0",
"chokidar": "^3.5.3", "chokidar": "^3.6.0",
"color": "^4.2.3", "color": "^4.2.3",
"dank-twitch-irc": "^3.3.0", "dank-twitch-irc": "^4.3.0",
"ejs": "^3.1.9", "ejs": "^3.1.10",
"electron": "^24.1.2", "electron": "^31.3.1",
"hls.js": "^1.4.0", "hls.js": "^1.5.14",
"jsondiffpatch": "^0.4.1", "jsondiffpatch": "^0.6.0",
"koa": "^2.14.2", "koa": "^2.15.3",
"koa-basic-auth": "^4.0.0", "koa-basic-auth": "^4.0.0",
"koa-easy-ws": "^2.1.0", "koa-easy-ws": "^2.1.0",
"koa-route": "^3.2.0", "koa-route": "^4.0.1",
"koa-static": "^5.0.0", "koa-static": "^5.0.0",
"koa-views": "^8.0.0", "koa-views": "^8.1.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"luxon": "^3.3.0", "luxon": "^3.5.0",
"node-fetch": "^3.3.1", "node-fetch": "^3.3.2",
"node-simple-cert": "0.0.1", "node-simple-cert": "0.0.1",
"preact": "^10.13.2", "preact": "^10.23.1",
"react-hotkeys-hook": "^4.4.0", "react-hotkeys-hook": "^4.5.0",
"reconnecting-websocket": "^4.4.0", "reconnecting-websocket": "^4.4.0",
"styled-components": "^5.3.9", "styled-components": "^6.1.12",
"svg-loaders-react": "^2.2.1", "svg-loaders-react": "^2.2.1",
"webpack-dev-server": "^4.13.2", "webpack-dev-server": "^5.0.4",
"ws": "^8.13.0", "ws": "^8.18.0",
"xstate": "^4.37.1", "xstate": "^4.37.1",
"yargs": "^17.7.1", "yargs": "^17.7.2",
"yjs": "^13.5.52" "yjs": "^13.6.18"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.21.4", "@babel/core": "^7.25.2",
"@babel/plugin-proposal-decorators": "^7.24.1", "@babel/plugin-proposal-decorators": "^7.24.7",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
"@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@babel/plugin-transform-react-jsx": "^7.21.0", "@babel/plugin-transform-react-jsx": "^7.25.2",
"@babel/preset-env": "^7.24.5", "@babel/preset-env": "^7.25.3",
"@svgr/webpack": "^7.0.0", "@svgr/webpack": "^8.1.0",
"babel-jest": "^29.7.0", "babel-jest": "^29.7.0",
"babel-loader": "^9.1.2", "babel-loader": "^9.1.3",
"babel-plugin-styled-components": "^2.1.1", "babel-plugin-styled-components": "^2.1.4",
"bufferutil": "^4.0.8", "bufferutil": "^4.0.8",
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^12.0.2",
"css-loader": "^6.7.3", "css-loader": "^7.1.2",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^29.5.0", "jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0", "jest-environment-jsdom": "^29.7.0",
"jest-junit": "^16.0.0", "jest-junit": "^16.0.0",
"prettier": "2.8.7", "npm-check-updates": "^17.0.6",
"style-loader": "^3.3.2", "prettier": "3.3.3",
"supertest": "^6.3.3", "style-loader": "^4.0.0",
"utf-8-validate": "^5.0.10", "supertest": "^7.0.0",
"webpack": "^5.79.0", "utf-8-validate": "^6.0.4",
"webpack-cli": "^5.0.1" "webpack": "^5.93.0",
"webpack-cli": "^5.1.4"
}, },
"browserslist": [ "browserslist": [
"electron 9.0" "electron 9.0"

View File

@@ -6,7 +6,8 @@ import { validRoles } from '../roles'
const scrypt = promisify(scryptCb) const scrypt = promisify(scryptCb)
const base62 = require('base-x')( import baseX from 'base-x'
const base62 = baseX(
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
) )

View File

@@ -13,6 +13,8 @@ import {
useRef, useRef,
} from 'preact/hooks' } from 'preact/hooks'
import { State } from 'xstate' import { State } from 'xstate'
import isPropValid from '@emotion/is-prop-valid';
import { StyleSheetManager } from 'styled-components';
import styled, { createGlobalStyle } from 'styled-components' import styled, { createGlobalStyle } from 'styled-components'
import { useHotkeys } from 'react-hotkeys-hook' import { useHotkeys } from 'react-hotkeys-hook'
import Color from 'color' import Color from 'color'
@@ -580,214 +582,216 @@ function App({ wsEndpoint, role }) {
} }
return ( return (
<Stack flex="1"> <StyleSheetManager shouldForwardProp={(prop) => isPropValid(prop) && !prop.startsWith('$')}>
<Stack> <Stack flex="1">
<StyledHeader> <Stack>
<h1>Streamwall ({location.host})</h1> <StyledHeader>
<div> <h1>Streamwall ({location.host})</h1>
connection status: {isConnected ? 'connected' : 'connecting...'} <div>
</div> connection status: {isConnected ? 'connected' : 'connecting...'}
<div>role: {role}</div> </div>
</StyledHeader> <div>role: {role}</div>
{delayState && ( </StyledHeader>
<StreamDelayBox {delayState && (
role={role} <StreamDelayBox
delayState={delayState} role={role}
setStreamCensored={setStreamCensored} delayState={delayState}
setStreamRunning={setStreamRunning} setStreamCensored={setStreamCensored}
/> setStreamRunning={setStreamRunning}
)} />
<StyledDataContainer isConnected={isConnected}> )}
{gridCount && ( <StyledDataContainer isConnected={isConnected}>
<StyledGridContainer {gridCount && (
onMouseMove={updateHoveringIdx} <StyledGridContainer
windowWidth={windowWidth} onMouseMove={updateHoveringIdx}
windowHeight={windowHeight} windowWidth={windowWidth}
> windowHeight={windowHeight}
<StyledGridInputs> >
{range(0, gridCount).map((y) => <StyledGridInputs>
range(0, gridCount).map((x) => { {range(0, gridCount).map((y) =>
const idx = gridCount * y + x range(0, gridCount).map((x) => {
const { state } = stateIdxMap.get(idx) || {} const idx = gridCount * y + x
const { streamId } = sharedState.views?.[idx] ?? {} const { state } = stateIdxMap.get(idx) || {}
const isDragHighlighted = const { streamId } = sharedState.views?.[idx] ?? {}
dragStart !== undefined && const isDragHighlighted =
idxInBox(gridCount, dragStart, hoveringIdx, idx) dragStart !== undefined &&
idxInBox(gridCount, dragStart, hoveringIdx, idx)
return (
<GridInput
style={{
width: `${100 / gridCount}%`,
height: `${100 / gridCount}%`,
left: `${(100 * x) / gridCount}%`,
top: `${(100 * y) / gridCount}%`,
}}
idx={idx}
spaceValue={streamId}
onChangeSpace={handleSetView}
isHighlighted={isDragHighlighted}
role={role}
onMouseDown={handleDragStart}
onFocus={handleFocusInput}
onBlur={handleBlurInput}
/>
)
}),
)}
</StyledGridInputs>
<StyledGridPreview>
{views.map(({ state, isListening }) => {
const { pos } = state.context
const { streamId } = sharedState.views[pos.spaces[0]] ?? {}
const data = streams.find((d) => d._id === streamId)
return ( return (
<GridInput <StyledGridPreviewBox
color={idColor(streamId)}
style={{ style={{
width: `${100 / gridCount}%`, left: `${(100 * pos.x) / windowWidth}%`,
height: `${100 / gridCount}%`, top: `${(100 * pos.y) / windowHeight}%`,
left: `${(100 * x) / gridCount}%`, width: `${(100 * pos.width) / windowWidth}%`,
top: `${(100 * y) / gridCount}%`, height: `${(100 * pos.height) / windowHeight}%`,
}} }}
idx={idx} pos={pos}
spaceValue={streamId} windowWidth={windowWidth}
onChangeSpace={handleSetView} windowHeight={windowHeight}
isHighlighted={isDragHighlighted} isListening={isListening}
isError={state && state.matches('displaying.error')}
>
<StyledGridInfo>
<StyledGridLabel>{streamId}</StyledGridLabel>
<div>{data?.source}</div>
</StyledGridInfo>
</StyledGridPreviewBox>
)
})}
</StyledGridPreview>
{views.map(
({ state, isListening, isBackgroundListening, isBlurred }) => {
const { pos } = state.context
const { streamId } = sharedState.views[pos.spaces[0]] ?? {}
return (
<GridControls
idx={pos.spaces[0]}
streamId={streamId}
style={{
left: `${(100 * pos.x) / windowWidth}%`,
top: `${(100 * pos.y) / windowHeight}%`,
width: `${(100 * pos.width) / windowWidth}%`,
height: `${(100 * pos.height) / windowHeight}%`,
}}
isDisplaying={state && state.matches('displaying')}
isListening={isListening}
isBackgroundListening={isBackgroundListening}
isBlurred={isBlurred}
isSwapping={pos.spaces.includes(swapStartIdx)}
showDebug={showDebug}
role={role} role={role}
onSetListening={handleSetListening}
onSetBackgroundListening={handleSetBackgroundListening}
onSetBlurred={handleSetBlurred}
onReloadView={handleReloadView}
onSwapView={handleSwapView}
onRotateView={handleRotateStream}
onBrowse={handleBrowse}
onDevTools={handleDevTools}
onMouseDown={handleDragStart} onMouseDown={handleDragStart}
onFocus={handleFocusInput}
onBlur={handleBlurInput}
/> />
) )
}), },
)} )}
</StyledGridInputs> </StyledGridContainer>
<StyledGridPreview> )}
{views.map(({ state, isListening }) => { {(roleCan(role, 'dev-tools') || roleCan(role, 'browse')) && (
const { pos } = state.context <label>
const { streamId } = sharedState.views[pos.spaces[0]] ?? {} <input
const data = streams.find((d) => d._id === streamId) type="checkbox"
return ( value={showDebug}
<StyledGridPreviewBox onChange={handleChangeShowDebug}
color={idColor(streamId)} />
style={{ Show stream debug tools
left: `${(100 * pos.x) / windowWidth}%`, </label>
top: `${(100 * pos.y) / windowHeight}%`, )}
width: `${(100 * pos.width) / windowWidth}%`, <Facts />
height: `${(100 * pos.height) / windowHeight}%`, </StyledDataContainer>
}} </Stack>
pos={pos} <Stack flex="1" scroll={true} minHeight={200}>
windowWidth={windowWidth} <StyledDataContainer isConnected={isConnected}>
windowHeight={windowHeight} {isConnected ? (
isListening={isListening} <div>
isError={state && state.matches('displaying.error')} <h3>Live</h3>
> <StreamList rows={liveStreams} />
<StyledGridInfo> <h3>Offline / Unknown</h3>
<StyledGridLabel>{streamId}</StyledGridLabel> <StreamList rows={otherStreams} />
<div>{data?.source}</div> </div>
</StyledGridInfo> ) : (
</StyledGridPreviewBox> <div>loading...</div>
) )}
})} {roleCan(role, 'update-custom-stream') &&
</StyledGridPreview> roleCan(role, 'delete-custom-stream') && (
{views.map( <>
({ state, isListening, isBackgroundListening, isBlurred }) => { <h2>Custom Streams</h2>
const { pos } = state.context <div>
const { streamId } = sharedState.views[pos.spaces[0]] ?? {} {/*
return ( Include an empty object at the end to create an extra input for a new custom stream.
<GridControls We need it to be part of the array (rather than JSX below) for DOM diffing to match the key and retain focus.
idx={pos.spaces[0]} */}
streamId={streamId} {customStreams.map(({ link, label, kind }, idx) => (
style={{ <CustomStreamInput
left: `${(100 * pos.x) / windowWidth}%`, key={idx}
top: `${(100 * pos.y) / windowHeight}%`, link={link}
width: `${(100 * pos.width) / windowWidth}%`, label={label}
height: `${(100 * pos.height) / windowHeight}%`, kind={kind}
}} onChange={handleChangeCustomStream}
isDisplaying={state && state.matches('displaying')} onDelete={handleDeleteCustomStream}
isListening={isListening} />
isBackgroundListening={isBackgroundListening} ))}
isBlurred={isBlurred} <CreateCustomStreamInput
isSwapping={pos.spaces.includes(swapStartIdx)} onCreate={handleChangeCustomStream}
showDebug={showDebug}
role={role}
onSetListening={handleSetListening}
onSetBackgroundListening={handleSetBackgroundListening}
onSetBlurred={handleSetBlurred}
onReloadView={handleReloadView}
onSwapView={handleSwapView}
onRotateView={handleRotateStream}
onBrowse={handleBrowse}
onDevTools={handleDevTools}
onMouseDown={handleDragStart}
/> />
) </div>
}, </>
)} )}
</StyledGridContainer> {roleCan(role, 'edit-tokens') && authState && (
)}
{(roleCan(role, 'dev-tools') || roleCan(role, 'browse')) && (
<label>
<input
type="checkbox"
value={showDebug}
onChange={handleChangeShowDebug}
/>
Show stream debug tools
</label>
)}
<Facts />
</StyledDataContainer>
</Stack>
<Stack flex="1" scroll={true} minHeight={200}>
<StyledDataContainer isConnected={isConnected}>
{isConnected ? (
<div>
<h3>Live</h3>
<StreamList rows={liveStreams} />
<h3>Offline / Unknown</h3>
<StreamList rows={otherStreams} />
</div>
) : (
<div>loading...</div>
)}
{roleCan(role, 'update-custom-stream') &&
roleCan(role, 'delete-custom-stream') && (
<> <>
<h2>Custom Streams</h2> <h2>Access</h2>
<div> <div>
{/* <CreateInviteInput onCreateInvite={handleCreateInvite} />
Include an empty object at the end to create an extra input for a new custom stream. <h3>Invites</h3>
We need it to be part of the array (rather than JSX below) for DOM diffing to match the key and retain focus. {newInvite && (
*/} <StyledNewInviteBox>
{customStreams.map(({ link, label, kind }, idx) => ( Invite link created:{' '}
<CustomStreamInput <a
key={idx} href={`/invite/${newInvite.secret}`}
link={link} onClick={preventLinkClick}
label={label} >
kind={kind} "{newInvite.name}"
onChange={handleChangeCustomStream} </a>
onDelete={handleDeleteCustomStream} </StyledNewInviteBox>
)}
{authState.invites.map(({ id, name, role }) => (
<AuthTokenLine
id={id}
name={name}
role={role}
onDelete={handleDeleteToken}
/>
))}
<h3>Sessions</h3>
{authState.sessions.map(({ id, name, role }) => (
<AuthTokenLine
id={id}
name={name}
role={role}
onDelete={handleDeleteToken}
/> />
))} ))}
<CreateCustomStreamInput
onCreate={handleChangeCustomStream}
/>
</div> </div>
</> </>
)} )}
{roleCan(role, 'edit-tokens') && authState && ( </StyledDataContainer>
<> </Stack>
<h2>Access</h2>
<div>
<CreateInviteInput onCreateInvite={handleCreateInvite} />
<h3>Invites</h3>
{newInvite && (
<StyledNewInviteBox>
Invite link created:{' '}
<a
href={`/invite/${newInvite.secret}`}
onClick={preventLinkClick}
>
"{newInvite.name}"
</a>
</StyledNewInviteBox>
)}
{authState.invites.map(({ id, name, role }) => (
<AuthTokenLine
id={id}
name={name}
role={role}
onDelete={handleDeleteToken}
/>
))}
<h3>Sessions</h3>
{authState.sessions.map(({ id, name, role }) => (
<AuthTokenLine
id={id}
name={name}
role={role}
onDelete={handleDeleteToken}
/>
))}
</div>
</>
)}
</StyledDataContainer>
</Stack> </Stack>
</Stack> </StyleSheetManager>
) )
} }
@@ -888,9 +892,9 @@ function StreamLine({
return ( return (
<StyledStreamLine> <StyledStreamLine>
<StyledId <StyledId
disabled={disabled} $disabled={disabled}
onMouseDown={disabled ? null : handleMouseDownId} onMouseDown={disabled ? null : handleMouseDownId}
color={idColor(id)} $color={idColor(id)}
> >
{id} {id}
</StyledId> </StyledId>
@@ -1120,7 +1124,7 @@ function GridControls({
{roleCan(role, 'set-listening-view') && ( {roleCan(role, 'set-listening-view') && (
<StyledButton <StyledButton
isActive={isListening || isBackgroundListening} isActive={isListening || isBackgroundListening}
activeColor={isListening ? 'red' : Color('red').desaturate(0.5)} activeColor={isListening ? 'red' : Color('red').desaturate(0.5).hsl().string()}
onClick={handleListeningClick} onClick={handleListeningClick}
tabIndex={1} tabIndex={1}
> >
@@ -1234,8 +1238,8 @@ const StyledButton = styled.button`
${({ isActive, activeColor = 'red' }) => ${({ isActive, activeColor = 'red' }) =>
isActive && isActive &&
` `
border-color: ${activeColor}; border-color: ${Color(activeColor).hsl().string()};
background: ${Color(activeColor).desaturate(0.5).lighten(0.5)}; background: ${Color(activeColor).desaturate(0.5).lighten(0.5).hsl().string()};
`}; `};
&:focus { &:focus {
@@ -1271,8 +1275,8 @@ const StyledGridPreviewBox = styled.div.attrs((props) => ({
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: absolute; position: absolute;
background: ${({ color }) => color.lightness(50) || '#333'}; background: ${({ color }) => Color(color).lightness(50).hsl().string() || '#333'};
border: 0 solid ${({ isError }) => (isError ? 'red' : 'black')}; border: 0 solid ${({ isError }) => (isError ? Color('red').hsl().string() : Color('black').hsl().string() )};
border-left-width: ${({ pos, borderWidth }) => border-left-width: ${({ pos, borderWidth }) =>
pos.x === 0 ? 0 : borderWidth}px; pos.x === 0 ? 0 : borderWidth}px;
border-right-width: ${({ pos, borderWidth, windowWidth }) => border-right-width: ${({ pos, borderWidth, windowWidth }) =>
@@ -1331,7 +1335,7 @@ const StyledGridInput = styled(LazyChangeInput)`
border: none; border: none;
padding: 0; padding: 0;
background: ${({ color, isHighlighted }) => background: ${({ color, isHighlighted }) =>
isHighlighted ? color.lightness(90) : color.lightness(75)}; isHighlighted ? Color(color).lightness(90).hsl().string() : Color(color).lightness(75).hsl().string() };
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
@@ -1368,13 +1372,13 @@ const StyledGridContainer = styled.div.attrs((props) => ({
const StyledId = styled.div` const StyledId = styled.div`
flex-shrink: 0; flex-shrink: 0;
margin-right: 5px; margin-right: 5px;
background: ${({ color }) => color.lightness(50) || '#333'}; background: ${({ $color }) => Color($color).lightness(50).hsl().string() || '#333'};
color: white; color: white;
padding: 3px; padding: 3px;
border-radius: 5px; border-radius: 5px;
width: 3em; width: 3em;
text-align: center; text-align: center;
cursor: ${({ disabled }) => (disabled ? 'normal' : 'pointer')}; cursor: ${({ $disabled }) => ($disabled ? 'normal' : 'pointer')};
` `
const StyledStreamLine = styled.div` const StyledStreamLine = styled.div`