Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
react-node-insim
Advanced tools
A React renderer for InSim buttons, based on Node InSim.
🚧 This project is still under development. Any API may change as needed.
React Node InSim is a React renderer for Live for Speed InSim buttons. It also provides layout components for easier button positioning, hooks for handling incoming InSim packets and tracking server connections & players.
It is based on Node InSim, a Node.js library, written in TypeScript, for InSim communication.
It allows you to create things like this:
import type { InSim } from 'node-insim';
import { InSimFlags, IS_BTC, IS_MST, PacketType } from 'node-insim/packets';
import { StrictMode } from 'react';
import {
Button,
ConnectionsProvider,
createRoot,
PlayersProvider,
useConnections,
useOnConnect,
useOnPacket,
usePlayers,
VStack,
} from 'react-node-insim';
function App() {
// Get the list of current players and connections
const players = usePlayers();
const connections = useConnections();
// Do something after the InSim app has been connected to LFS
useOnConnect((packet, inSim) => {
console.log(`Connected to LFS ${packet.Product} ${packet.Version}`);
inSim.send(new IS_MST({ Msg: `React Node InSim connected` }));
});
// Handle incoming packets
useOnPacket(PacketType.ISP_NCN, (packet) => {
console.log(`New connection: ${packet.UName}`);
});
// Clickable buttons
const handlePlayerClick = (plid: number) => (_: IS_BTC, inSim: InSim) => {
inSim.send(new IS_MST({ Msg: `/echo PLID ${plid}` }));
};
const handleConnectionClick = (ucid: number) => (_: IS_BTC, inSim: InSim) => {
inSim.send(new IS_MST({ Msg: `/echo UCID ${ucid}` }));
};
return (
<>
<Button top={10} left={40} width={30} height={5} UCID={255} color="title">
Players
</Button>
<VStack
background="dark"
top={15}
left={40}
width={30}
height={5}
UCID={255}
>
{players.map((player) => (
<Button key={player.PLID} onClick={handlePlayerClick(player.PLID)}>
{player.PName}
</Button>
))}
</VStack>
<Button top={10} left={70} width={30} height={5} UCID={255} color="title">
Connections
</Button>
<VStack
background="dark"
top={15}
left={70}
width={30}
height={5}
UCID={255}
>
{connections.map((connection) => (
<Button
key={connection.UCID}
onClick={handleConnectionClick(connection.UCID)}
>
{connection.UName}
</Button>
))}
</VStack>
</>
);
}
const root = createRoot({
name: 'React InSim',
host: '127.0.0.1',
port: 29999,
flags: InSimFlags.ISF_LOCAL,
});
root.render(
<StrictMode>
<PlayersProvider>
<ConnectionsProvider>
<App />
</ConnectionsProvider>
</PlayersProvider>
</StrictMode>,
);
npm install react@18 node-insim react-node-insim
yarn add react@18 node-insim react-node-insim
pnpm add react@18 node-insim react-node-insim
Displaying an InSim button on a local computer
import { InSimFlags } from 'node-insim/packets';
import { Button, createRoot } from 'react-node-insim';
const root = createRoot({
name: 'React InSim',
host: '127.0.0.1',
port: 29999,
flags: InSimFlags.ISF_LOCAL,
});
root.render(
<Button top={100} left={80} width={30} height={10}>
Hello InSim!
</Button>,
);
You can use React hooks as usual to display stateful data via InSim.
import { InSimFlags } from 'node-insim/packets';
import { useEffect, useState } from 'react';
import { Button, createRoot } from 'react-node-insim';
function App() {
const [time, setTime] = useState(new Date());
useEffect(() => {
const interval = setInterval(() => {
setTime(new Date());
}, 1000);
return () => {
clearInterval(interval);
};
});
return (
<Button top={100} left={80} width={40} height={10}>
Current time: {time.toLocaleTimeString()}
</Button>
);
}
const root = createRoot({
name: 'React InSim',
host: '127.0.0.1',
port: 29999,
flags: InSimFlags.ISF_LOCAL,
});
root.render(<App />);
The Button component is used to display a button in LFS.
import { Button } from 'react-node-insim';
<Button top={100} left={80} width={30} height={10}>
Button
</Button>
Buttons use XY coordinates to position themselves on the screen. The top
and left
props control the button's X and Y position on the screen. The allowed range of values is 0 to 200.
<>
<Button width={12} height={6} top={100} left={40}>
Button
</Button>
<Button width={12} height={6} top={100} left={53}>
Button
</Button>
<Button width={12} height={6} top={106} left={40}>
Button
</Button>
<Button width={12} height={6} top={106} left={53}>
Button
</Button>
</>
Use the width
and height
props to change the dimensions of the button. The allowed range of values is 0 to 200.
<>
<Button variant="light" top={100} left={40} width={6} height={4}>
Button
</Button>
<Button variant="light" top={99} left={47} width={10} height={6}>
Button
</Button>
<Button variant="light" top={97} left={58} width={14} height={10}>
Button
</Button>
</>
Use the variant
prop to change the button's visual style. You can use light
or dark
. If you don't specify a variant, the button will have transparent background and a light gray text color.
<>
<Button top={100} left={40} width={12} height={6} variant="light">
Button
</Button>
<Button top={100} left={53} width={12} height={6} variant="dark">
Button
</Button>
</>
Use the color
prop to customize the button's text color. If you don't specify a color, the button text will be default
.
<>
<Button top={73} left={40} width={12} height={6} color="default">
default
</Button>
<Button top={73} left={53} width={12} height={6} color="title">
title
</Button>
<Button top={73} left={66} width={12} height={6} color="unselected">
unselected
</Button>
<Button top={73} left={79} width={12} height={6} color="selected">
selected
</Button>
<Button top={80} left={40} width={12} height={6} color="ok">
ok
</Button>
<Button top={80} left={53} width={12} height={6} color="cancel">
cancel
</Button>
<Button top={80} left={66} width={12} height={6} color="textstring">
textstring
</Button>
<Button top={80} left={79} width={12} height={6} color="unavailable">
unavailable
</Button>
</>
You can choose from a set of semantic colors or use one of the colors from the LFS color palette.
Semantic colors
Note: The semantic color values can be customized in LFS Options -> Display -> Interface.
LFS color palette
Use the background
prop to customize the button's background color. If you don't specify a color, the background will be transparent.
<>
<Button top={67} left={40} width={12} height={6} background="light">
light
</Button>
<Button top={67} left={53} width={12} height={6} background="dark">
dark
</Button>
<Button top={67} left={66} width={12} height={6} background="transparent">
transparent
</Button>
</>
HStack
displays buttons in a column without having to specify each button's position manually. You can also override button colors and sizes.
import { HStack } from 'react-node-insim';
<HStack top={10} left={20} width={7} height={4} variant="dark">
<Button>Stacked button</Button>
<Button color="title">Custom color</Button>
<Button height={6}>Custom height</Button>
</HStack>
VStack
displays buttons in a row without having to specify each button's position manually. You can also override button colors and sizes.
import { VStack } from 'react-node-insim';
<VStack top={10} left={20} width={7} height={4} variant="dark">
<Button>Stacked button</Button>
<Button color="title">Custom color</Button>
<Button height={6}>Custom height</Button>
</VStack>
Flex layout displays buttons in a row or column with flexbox options.
import { Flex } from 'react-node-insim';
<Flex
top={10}
left={20}
width={36}
height={16}
alignItems="center"
justifyContent="space-evenly"
background="dark"
backgroundColor="light"
>
<Button width={8} height={4}>
Left
</Button>
<Button width={10} height={6}>
Center
</Button>
<Button width={8} height={4}>
Right
</Button>
</Flex>
Grid layout displays buttons in a grid.
import { Grid, GridButton } from 'react-node-insim';
<Grid
top={30}
left={40}
width={30}
height={30}
background="dark"
backgroundColor="light"
gridTemplateColumns="1fr 2fr 1fr"
gridTemplateRows="1fr 3fr 2fr"
gridColumnGap={1}
gridRowGap={1}
>
<GridButton>1</GridButton>
<GridButton
gridColumnStart={2}
gridRowStart={1}
gridRowEnd={3}
color="title"
background="light"
>
2
</GridButton>
<GridButton
gridColumnStart={3}
gridColumnEnd={3}
gridRowStart={1}
gridRowEnd={3}
>
3
</GridButton>
<GridButton alignSelf="end" height={10}>
4
</GridButton>
<GridButton gridColumnStart={1} gridColumnEnd={4}>
5
</GridButton>
</Grid>
A button that can be toggled on and off by clicking it.
import { ToggleButton } from 'react-node-insim';
function App() {
const [isOn, setIsOn] = useState(false);
return (
<ToggleButton
top={100}
left={80}
width={12}
height={6}
isOn={isOn}
onToggle={setIsOn}
>
Toggle
</ToggleButton>
);
}
Use the variant
prop to change the button's background style. You can use light
or dark
. If you don't specify a variant, light
will be used.
<>
<ToggleButton variant="light" top={100} left={40} width={12} height={6}>
Toggle
</ToggleButton>
<ToggleButton variant="dark" top={100} left={53} width={12} height={6}>
Toggle
</ToggleButton>
</>
Use the isDisabled
prop to prevent toggling the button on/off.
<>
<ToggleButton
isDisabled={false}
variant="light"
top={100}
left={40}
width={12}
height={6}
>
Enabled
</ToggleButton>
<ToggleButton
isDisabled
variant="light"
top={100}
left={53}
width={12}
height={6}
>
Disabled
</ToggleButton>
<ToggleButton
isDisabled={false}
variant="dark"
top={106}
left={40}
width={12}
height={6}
>
Enabled
</ToggleButton>
<ToggleButton
isDisabled
variant="dark"
top={106}
left={53}
width={12}
height={6}
>
Disabled
</ToggleButton>
</>
A group of buttons that can be toggled on and off by clicking them.
import { ToggleButtonGroup } from 'react-node-insim';
const options = [
{ label: 'low', value: 1 },
{ label: 'medium', value: 2 },
{ label: 'high', value: 3 },
];
function App() {
const [selectedOption, setSelectedOption] = useState(options[0]);
return (
<ToggleButtonGroup
top={30}
left={50}
width={36}
height={6}
options={options}
selectedOption={selectedOption}
onChange={setSelectedOption}
/>
);
}
A text box whose content can span multiple rows. If the content is too long, the text box will show a scrollbar.
import { TextBox } from 'react-node-insim';
<TextBox
top={40}
left={50}
cols={20}
rows={4}
width={20}
rowHeight={4}
variant="light"
>
Hello world this is a text box lorem ipsum dolor sit amet consectetur
adipisicing elitrea lorem ipsum dolor sit amet consectetur adipisicing elit
</TextBox>
useOnConnect
Execute code after the InSim app has been connected.
The first parameter is an IS_VER
packet callback executed when IS_VER
is received upon successful InSim connection to LFS.
import { useOnConnect } from 'react-node-insim';
function App() {
useOnConnect((packet, inSim) => {
console.log(`Connected to LFS ${packet.Product} ${packet.Version}`);
inSim.send(new IS_MST({ Msg: `React Node InSim connected` }));
});
return null;
}
useOnDisconnect
Execute code after the InSim app has been disconnected.
The first parameter is the "disconnect" event callback from Node InSim.
import { useOnDisconnect } from 'react-node-insim';
function App() {
useOnDisconnect(() => {
console.log('Disconnected from LFS');
});
return null;
}
useOnPacket
Execute code when an InSim packet is received
import { useOnPacket } from 'react-node-insim';
function App() {
useOnPacket(PacketType.ISP_NCN, (packet) => {
console.log(`New connection: ${packet.UName}`);
});
return null;
}
useConnections
Get a live list of all connected guests.
import { useConnections } from 'react-node-insim';
function App() {
const connections = useConnections();
return (
<VStack background="dark" top={10} left={10} width={20} height={4}>
{connections.map((connection) => (
<Button key={connection.UCID}>{connection.UName}</Button>
))}
</VStack>
);
}
usePlayers
Get a live list of all players on track.
import { usePlayers } from 'react-node-insim';
function App() {
const players = usePlayers();
return (
<VStack background="dark" top={10} left={10} width={20} height={4}>
{players.map((player) => (
<Button key={player.PLID}>{player.PName}</Button>
))}
</VStack>
);
}
useMessage
Send a message to a connection or a player.
import { useMessage } from 'react-node-insim';
function App() {
const { sendMessageToConnection, sendMessageToPlayer } = useMessage();
return (
<>
<Button
top={5}
left={10}
width={15}
height={5}
onClick={(packet) => {
sendMessageToConnection(
packet.UCID,
'Hello from React Node InSim',
MessageSound.SND_SYSMESSAGE,
);
}}
>
Send message to a connection
</Button>
<Button
top={10}
left={10}
width={15}
height={5}
onClick={(packet) => {
sendMessageToPlayer(
12, // PLID
'Hello from React Node InSim',
MessageSound.SND_SYSMESSAGE,
);
}}
>
Send message to a player
</Button>
</>
);
}
useRaceControlMessage
Send a race control message (RCM) to a connection or a player.
import { useRaceControlMessage } from 'react-node-insim';
function App() {
const { sendRaceControlMessageToConnection, sendRaceControlMessageToPlayer } =
useRaceControlMessage();
return (
<>
<Button
top={5}
left={10}
width={15}
height={5}
onClick={(packet) => {
sendRaceControlMessageToConnection(
packet.UCID,
'Hello from React Node InSim',
2000,
);
}}
>
Send message to a connection
</Button>
<Button
top={10}
left={10}
width={15}
height={5}
onClick={(packet) => {
sendRaceControlMessageToPlayer(
12, // PLID
'Hello from React Node InSim',
2000,
);
}}
>
Send message to a player
</Button>
</>
);
}
useInSim
Access to Node InSim API of the current InSim client instance.
import { useInSim } from 'react-node-insim';
function App() {
const inSim = useInSim();
useEffect(() => {
inSim.send(new IS_MST({ Msg: 'App mounted' }));
}, []);
return null;
}
yarn
yarn start
yarn lint
yarn format
FAQs
React Node InSim
The npm package react-node-insim receives a total of 3 weekly downloads. As such, react-node-insim popularity was classified as not popular.
We found that react-node-insim demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.