make it look nicer
This commit is contained in:
parent
77f8019507
commit
9eb19bf85b
15 changed files with 857 additions and 146 deletions
1
.tokeignore
Normal file
1
.tokeignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package-lock.json
|
|
@ -7,3 +7,9 @@ npm ci
|
||||||
npm run build
|
npm run build
|
||||||
cargo build --release
|
cargo build --release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```
|
||||||
|
grub [--port 6106]
|
||||||
|
```
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
import "bootstrap/dist/css/bootstrap.min.css";
|
||||||
|
import "./global.css";
|
||||||
|
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import Room from "./Room";
|
import Room from "./Room";
|
||||||
|
import { Container } from "react-bootstrap";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const x = new URL(window.location.href);
|
const x = new URL(window.location.href);
|
||||||
|
@ -9,5 +13,9 @@ export default function App() {
|
||||||
location.href = `/${v4()}`;
|
location.href = `/${v4()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Room roomId={roomId} />;
|
return (
|
||||||
|
<Container>
|
||||||
|
<Room roomId={roomId} />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
70
client/Chat.tsx
Normal file
70
client/Chat.tsx
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import { useContext, useState } from "react";
|
||||||
|
import useWebSocket from "react-use-websocket";
|
||||||
|
import { wsUrl } from "./constants";
|
||||||
|
import CBOR from "cbor";
|
||||||
|
import * as uuid from "uuid";
|
||||||
|
import { RoomContext } from "./lib/roomContext";
|
||||||
|
|
||||||
|
export default function Chat() {
|
||||||
|
const { roomId, clientId } = useContext(RoomContext);
|
||||||
|
const [chats, setChats] = useState([]);
|
||||||
|
const [message, setMessage] = useState("");
|
||||||
|
|
||||||
|
const {
|
||||||
|
sendMessage,
|
||||||
|
lastJsonMessage,
|
||||||
|
readyState: newReadyState,
|
||||||
|
} = useWebSocket(wsUrl, {
|
||||||
|
share: true,
|
||||||
|
onOpen: ({}) => {
|
||||||
|
console.log("Shiet, connected.");
|
||||||
|
},
|
||||||
|
onMessage: async (event) => {
|
||||||
|
const data = CBOR.decode(await event.data.arrayBuffer());
|
||||||
|
console.log("received", data);
|
||||||
|
|
||||||
|
if (data.type === "ChatMessage") {
|
||||||
|
setChats([...chats, data]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function sendCborMessage(data) {
|
||||||
|
let cbor = CBOR.encode(data);
|
||||||
|
sendMessage(cbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
sendCborMessage({
|
||||||
|
type: "ChatMessage",
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
message_id: uuid.v4(),
|
||||||
|
room_id: roomId,
|
||||||
|
author: clientId,
|
||||||
|
content: message,
|
||||||
|
});
|
||||||
|
setMessage("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
Messages:
|
||||||
|
<ul>
|
||||||
|
{chats.map((x) => (
|
||||||
|
<li key={x.message_id}>
|
||||||
|
[{x.timestamp}] {uuid.stringify(x.author)}: {x.content}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<form onSubmit={onSubmit}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={message}
|
||||||
|
onChange={(e) => setMessage(e.target.value)}
|
||||||
|
placeholder="Type a message..."
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
86
client/Grub.tsx
Normal file
86
client/Grub.tsx
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import * as Automerge from "@automerge/automerge";
|
||||||
|
import { useContext, useState } from "react";
|
||||||
|
import useWebSocket from "react-use-websocket";
|
||||||
|
import { wsUrl } from "./constants";
|
||||||
|
import CBOR from "cbor";
|
||||||
|
import { RoomContext } from "./lib/roomContext";
|
||||||
|
|
||||||
|
export default function Grub() {
|
||||||
|
const { roomId, clientId } = useContext(RoomContext);
|
||||||
|
const [doc, setDoc] = useState(Automerge.init());
|
||||||
|
const [syncState, setSyncState] = useState(Automerge.initSyncState());
|
||||||
|
const [addItemName, setAddItemName] = useState("");
|
||||||
|
|
||||||
|
function updateDoc(newDoc) {
|
||||||
|
setDoc(newDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { sendMessage } = useWebSocket(wsUrl, {
|
||||||
|
share: true,
|
||||||
|
onOpen: ({}) => {
|
||||||
|
console.log("Shiet, connected.");
|
||||||
|
},
|
||||||
|
onMessage: async (event) => {
|
||||||
|
const data = CBOR.decode(await event.data.arrayBuffer());
|
||||||
|
|
||||||
|
if (data.type === "Automerge") {
|
||||||
|
const [nextDoc, nextSyncState, patch] = Automerge.receiveSyncMessage(
|
||||||
|
doc,
|
||||||
|
syncState,
|
||||||
|
data.message[1]
|
||||||
|
);
|
||||||
|
setDoc(nextDoc);
|
||||||
|
setSyncState(nextSyncState);
|
||||||
|
console.log("patch", patch);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function sendCborMessage(data) {
|
||||||
|
let cbor = CBOR.encode(data);
|
||||||
|
sendMessage(cbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addItem(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const newDoc = Automerge.change(doc, (doc) => {
|
||||||
|
if (!doc.items) doc.items = [];
|
||||||
|
doc.items.push({
|
||||||
|
id: uuid.v4(),
|
||||||
|
content: addItemName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
updateDoc(newDoc);
|
||||||
|
const [syncMessage, binary] = Automerge.generateSyncMessage(doc, syncState);
|
||||||
|
if (syncMessage)
|
||||||
|
sendCborMessage({
|
||||||
|
type: "Automerge",
|
||||||
|
client_id: clientId,
|
||||||
|
room_id: roomId,
|
||||||
|
message: binary,
|
||||||
|
});
|
||||||
|
setAddItemName("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = doc.items || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
Grubs:
|
||||||
|
<ul>
|
||||||
|
{items.map((x) => (
|
||||||
|
<li key={x.id}>{x.content}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<form onSubmit={addItem}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={addItemName}
|
||||||
|
onChange={(e) => setAddItemName(e.target.value)}
|
||||||
|
placeholder="Type a message..."
|
||||||
|
/>
|
||||||
|
<button type="submit">add item</button>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
126
client/Room.tsx
126
client/Room.tsx
|
@ -3,9 +3,13 @@ import { useEffect, useState } from "react";
|
||||||
import useWebSocket, { ReadyState } from "react-use-websocket";
|
import useWebSocket, { ReadyState } from "react-use-websocket";
|
||||||
import * as Automerge from "@automerge/automerge";
|
import * as Automerge from "@automerge/automerge";
|
||||||
import * as uuid from "uuid";
|
import * as uuid from "uuid";
|
||||||
import {} from "libsodium";
|
|
||||||
import Upload from "./Upload";
|
|
||||||
import { wsUrl } from "./constants";
|
import { wsUrl } from "./constants";
|
||||||
|
import { Tab, Tabs } from "react-bootstrap";
|
||||||
|
import Upload from "./Upload";
|
||||||
|
import Chat from "./Chat";
|
||||||
|
import Grub from "./Grub";
|
||||||
|
import { RoomContext } from "./lib/roomContext";
|
||||||
|
import { Wifi } from "react-bootstrap-icons";
|
||||||
|
|
||||||
const connectionStatusMap = {
|
const connectionStatusMap = {
|
||||||
[ReadyState.CONNECTING]: "Connecting",
|
[ReadyState.CONNECTING]: "Connecting",
|
||||||
|
@ -19,17 +23,6 @@ export default function Room({ roomId }) {
|
||||||
const [readyState, setReadyState] = useState(ReadyState.CLOSED);
|
const [readyState, setReadyState] = useState(ReadyState.CLOSED);
|
||||||
const [connectedClients, setConnectedClients] = useState([]);
|
const [connectedClients, setConnectedClients] = useState([]);
|
||||||
const [clientId, setClientId] = useState<string | null>(null);
|
const [clientId, setClientId] = useState<string | null>(null);
|
||||||
const [chats, setChats] = useState([]);
|
|
||||||
|
|
||||||
const [doc, setDoc] = useState(Automerge.init());
|
|
||||||
const [syncState, setSyncState] = useState(Automerge.initSyncState());
|
|
||||||
|
|
||||||
const [message, setMessage] = useState("");
|
|
||||||
const [addItemName, setAddItemName] = useState("");
|
|
||||||
|
|
||||||
function updateDoc(newDoc) {
|
|
||||||
setDoc(newDoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
sendMessage,
|
sendMessage,
|
||||||
|
@ -52,10 +45,6 @@ export default function Room({ roomId }) {
|
||||||
setConnectedClients(data.clients.map((x) => uuid.stringify(x)));
|
setConnectedClients(data.clients.map((x) => uuid.stringify(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === "ChatMessage") {
|
|
||||||
setChats([...chats, data]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.type === "Automerge") {
|
if (data.type === "Automerge") {
|
||||||
const [nextDoc, nextSyncState, patch] = Automerge.receiveSyncMessage(
|
const [nextDoc, nextSyncState, patch] = Automerge.receiveSyncMessage(
|
||||||
doc,
|
doc,
|
||||||
|
@ -81,7 +70,6 @@ export default function Room({ roomId }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("hellosu", readyState, newReadyState);
|
|
||||||
if (
|
if (
|
||||||
readyState === ReadyState.CONNECTING &&
|
readyState === ReadyState.CONNECTING &&
|
||||||
newReadyState === ReadyState.OPEN
|
newReadyState === ReadyState.OPEN
|
||||||
|
@ -93,88 +81,48 @@ export default function Room({ roomId }) {
|
||||||
setReadyState(newReadyState);
|
setReadyState(newReadyState);
|
||||||
}, [newReadyState]);
|
}, [newReadyState]);
|
||||||
|
|
||||||
function onSubmit(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
sendWtfMessage({
|
|
||||||
type: "ChatMessage",
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
message_id: uuid.v4(),
|
|
||||||
room_id: roomId,
|
|
||||||
author: clientId,
|
|
||||||
content: message,
|
|
||||||
});
|
|
||||||
setMessage("");
|
|
||||||
}
|
|
||||||
|
|
||||||
function addItem(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const newDoc = Automerge.change(doc, (doc) => {
|
|
||||||
if (!doc.items) doc.items = [];
|
|
||||||
doc.items.push({
|
|
||||||
id: uuid.v4(),
|
|
||||||
content: addItemName,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
updateDoc(newDoc);
|
|
||||||
const [syncMessage, binary] = Automerge.generateSyncMessage(doc, syncState);
|
|
||||||
if (syncMessage)
|
|
||||||
sendWtfMessage({
|
|
||||||
type: "Automerge",
|
|
||||||
client_id: clientId,
|
|
||||||
room_id: roomId,
|
|
||||||
message: binary,
|
|
||||||
});
|
|
||||||
setAddItemName("");
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = doc.items || [];
|
|
||||||
const connectionStatus = connectionStatusMap[readyState];
|
const connectionStatus = connectionStatusMap[readyState];
|
||||||
|
|
||||||
if (newReadyState !== ReadyState.OPEN) return <>Connecting...</>;
|
if (newReadyState !== ReadyState.OPEN) return <>Connecting...</>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<RoomContext.Provider value={{ roomId, clientId }}>
|
||||||
<Upload roomId={roomId} />
|
|
||||||
<hr />
|
|
||||||
<p>Room Id: {roomId}</p>
|
<p>Room Id: {roomId}</p>
|
||||||
<p>Connection status: {connectionStatus}</p>
|
<p>
|
||||||
|
Connection status: <ConnectionStatus readyState={readyState} />
|
||||||
|
</p>
|
||||||
Connected:
|
Connected:
|
||||||
<ul>
|
<ul>
|
||||||
{connectedClients.map((x) => (
|
{connectedClients.map((x) => (
|
||||||
<li key={x}>{x}</li>
|
<li key={x}>{x}</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
Messages:
|
<Tabs
|
||||||
<ul>
|
defaultActiveKey="file-transfer"
|
||||||
{chats.map((x) => (
|
id="uncontrolled-tab-example"
|
||||||
<li key={x.message_id}>
|
className="mb-3"
|
||||||
[{x.timestamp}] {uuid.stringify(x.author)}: {x.content}
|
>
|
||||||
</li>
|
<Tab eventKey="file-transfer" title="File Transfer">
|
||||||
))}
|
<Upload />
|
||||||
</ul>
|
</Tab>
|
||||||
<form onSubmit={onSubmit}>
|
<Tab eventKey="grocery-tracking" title="Grocery Tracking">
|
||||||
<input
|
<Grub />
|
||||||
type="text"
|
</Tab>
|
||||||
value={message}
|
<Tab eventKey="chat" title="Chat">
|
||||||
onChange={(e) => setMessage(e.target.value)}
|
<Chat />
|
||||||
placeholder="Type a message..."
|
</Tab>
|
||||||
/>
|
</Tabs>
|
||||||
</form>
|
</RoomContext.Provider>
|
||||||
Grubs:
|
|
||||||
<ul>
|
|
||||||
{items.map((x) => (
|
|
||||||
<li key={x.id}>{x.content}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<form onSubmit={addItem}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={addItemName}
|
|
||||||
onChange={(e) => setAddItemName(e.target.value)}
|
|
||||||
placeholder="Type a message..."
|
|
||||||
/>
|
|
||||||
<button type="submit">add item</button>
|
|
||||||
</form>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ConnectionStatus({ readyState }) {
|
||||||
|
switch (readyState) {
|
||||||
|
case ReadyState.CONNECTING:
|
||||||
|
return <Wifi color="yellow" />;
|
||||||
|
case ReadyState.OPEN:
|
||||||
|
return <Wifi color="green" />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,48 @@
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useContext, useEffect, useState } from "react";
|
||||||
import * as sodium from "libsodium-wrappers";
|
import * as sodium from "libsodium-wrappers-sumo";
|
||||||
import useWebSocket from "react-use-websocket";
|
import useWebSocket from "react-use-websocket";
|
||||||
import CBOR from "cbor";
|
import CBOR from "cbor";
|
||||||
import { wsUrl } from "./constants";
|
import { wsUrl } from "./constants";
|
||||||
|
import { RoomContext } from "./lib/roomContext";
|
||||||
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
import {
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Button,
|
||||||
|
Form,
|
||||||
|
Badge,
|
||||||
|
OverlayTrigger,
|
||||||
|
Tooltip,
|
||||||
|
} from "react-bootstrap";
|
||||||
|
|
||||||
export default function Upload({ roomId }) {
|
export default function Upload() {
|
||||||
|
const { roomId } = useContext(RoomContext);
|
||||||
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
||||||
const [encryptionKey, setEncryptionKey] = useState(null);
|
const [encryptionKey, setEncryptionKey] = useState(null);
|
||||||
|
const [passphrase, setPassphrase] = useState("");
|
||||||
const [uploadProgress, setUploadProgress] = useState(null);
|
const [uploadProgress, setUploadProgress] = useState(null);
|
||||||
|
|
||||||
|
const setHashedPassphrase = useDebouncedCallback(
|
||||||
|
(passphrase) => {
|
||||||
|
if (passphrase) {
|
||||||
|
const salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);
|
||||||
|
console.log("salt", salt);
|
||||||
|
setEncryptionKey(
|
||||||
|
sodium.crypto_pwhash(
|
||||||
|
sodium.crypto_box_SEEDBYTES,
|
||||||
|
passphrase,
|
||||||
|
salt,
|
||||||
|
sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
|
||||||
|
sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
|
||||||
|
sodium.crypto_pwhash_ALG_ARGON2ID13
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// delay in ms
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
|
||||||
const [decryptionKey, setDecryptionKey] = useState("");
|
const [decryptionKey, setDecryptionKey] = useState("");
|
||||||
const [selectedSaveFile, setSelectedSaveFile] = useState(null);
|
const [selectedSaveFile, setSelectedSaveFile] = useState(null);
|
||||||
const [decryptState, setDecryptState] = useState(null);
|
const [decryptState, setDecryptState] = useState(null);
|
||||||
|
@ -22,11 +56,7 @@ export default function Upload({ roomId }) {
|
||||||
const readyToDownload =
|
const readyToDownload =
|
||||||
!!decryptionKeyInternal && !!selectedSaveFile && !!writeStream;
|
!!decryptionKeyInternal && !!selectedSaveFile && !!writeStream;
|
||||||
|
|
||||||
const {
|
const { sendMessage } = useWebSocket(wsUrl, {
|
||||||
sendMessage,
|
|
||||||
lastJsonMessage,
|
|
||||||
readyState: newReadyState,
|
|
||||||
} = useWebSocket(wsUrl, {
|
|
||||||
share: true,
|
share: true,
|
||||||
onMessage: async (event) => {
|
onMessage: async (event) => {
|
||||||
const message = CBOR.decode(await event.data.arrayBuffer());
|
const message = CBOR.decode(await event.data.arrayBuffer());
|
||||||
|
@ -69,10 +99,14 @@ export default function Upload({ roomId }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
await sodium.ready;
|
await sodium.ready;
|
||||||
const key = sodium.crypto_secretstream_xchacha20poly1305_keygen();
|
if (passphrase) {
|
||||||
setEncryptionKey(key);
|
setHashedPassphrase(passphrase);
|
||||||
|
} else {
|
||||||
|
const key = sodium.crypto_secretstream_xchacha20poly1305_keygen();
|
||||||
|
setEncryptionKey(key);
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
}, []);
|
}, [passphrase]);
|
||||||
|
|
||||||
const uploadFile = useCallback(async () => {
|
const uploadFile = useCallback(async () => {
|
||||||
if (!encryptionKey) return;
|
if (!encryptionKey) return;
|
||||||
|
@ -128,43 +162,102 @@ export default function Upload({ roomId }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<h3>Send file</h3>
|
<h3>How does this work?</h3>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<b>Uploader:</b> Copy the key and send it to whoever you're sending
|
||||||
|
files to
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Receiver:</b> Paste the key into the "Paste key here" box
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Receiver:</b> Press the "select save file" button to choose where
|
||||||
|
to save the file to
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Receiver:</b> Tell the uploader to press "upload"
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<b>Uploader:</b> Press "upload"
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<p>Only one person can upload at a time.</p>
|
||||||
|
|
||||||
<p>Upload Key: {encryptionKey && bytes2Hex(encryptionKey)}</p>
|
<Row>
|
||||||
|
<Col md={6}>
|
||||||
|
<h3>Send file</h3>
|
||||||
|
|
||||||
<input type="file" onChange={(e) => setSelectedFile(e.target.files[0])} />
|
{/* <p>
|
||||||
<button onClick={uploadFile}>upload</button>
|
Upload passphrase:
|
||||||
|
<Form.Control
|
||||||
<hr />
|
value={passphrase}
|
||||||
|
onChange={(e) => {
|
||||||
<h3>Receive file</h3>
|
setEncryptionKey(null);
|
||||||
|
setPassphrase(e.target.value);
|
||||||
<p>
|
}}
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={decryptionKey}
|
|
||||||
onChange={(e) => setDecryptionKey(e.target.value)}
|
|
||||||
placeholder="Download Key..."
|
|
||||||
/>
|
/>
|
||||||
</li>
|
</p> */}
|
||||||
<li>
|
|
||||||
<button onClick={selectSaveFile} disabled={!!selectedSaveFile}>
|
<p>
|
||||||
{selectedSaveFile
|
Upload Key:{" "}
|
||||||
? `Saving to "${selectedSaveFile.name}"`
|
<Form.Control
|
||||||
: "select save file"}
|
type="text"
|
||||||
</button>
|
disabled
|
||||||
</li>
|
value={encryptionKey ? bytes2Hex(encryptionKey) : "generating..."}
|
||||||
</ol>
|
/>
|
||||||
(
|
</p>
|
||||||
{readyToDownload
|
|
||||||
? "you are ready to download"
|
<input
|
||||||
: "you are not ready to download, make sure you enter the key and select a place to save"}
|
type="file"
|
||||||
)
|
onChange={(e) => setSelectedFile(e.target.files[0])}
|
||||||
</p>
|
/>
|
||||||
</div>
|
<Button onClick={uploadFile} disabled={!encryptionKey}>
|
||||||
|
upload
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col md={6}>
|
||||||
|
<h3>
|
||||||
|
Receive file
|
||||||
|
{readyToDownload ? (
|
||||||
|
<Badge bg="success">ready</Badge>
|
||||||
|
) : (
|
||||||
|
<OverlayTrigger
|
||||||
|
placement="top"
|
||||||
|
overlay={
|
||||||
|
<Tooltip>
|
||||||
|
you are not ready to download, make sure you enter the key
|
||||||
|
and select a place to save
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Badge bg="warning">not ready</Badge>
|
||||||
|
</OverlayTrigger>
|
||||||
|
)}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<Form.Control
|
||||||
|
type="text"
|
||||||
|
value={decryptionKey}
|
||||||
|
onChange={(e) => setDecryptionKey(e.target.value)}
|
||||||
|
placeholder="Paste key here..."
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Button onClick={selectSaveFile} disabled={!!selectedSaveFile}>
|
||||||
|
{selectedSaveFile
|
||||||
|
? `Saving to "${selectedSaveFile.name}"`
|
||||||
|
: "select save file"}
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
client/global.css
Normal file
4
client/global.css
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.container {
|
||||||
|
max-width: 980px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
8
client/lib/roomContext.ts
Normal file
8
client/lib/roomContext.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { createContext } from "react";
|
||||||
|
|
||||||
|
interface RoomContextProps {
|
||||||
|
roomId: string;
|
||||||
|
clientId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RoomContext = createContext<RoomContextProps>(undefined);
|
496
package-lock.json
generated
496
package-lock.json
generated
|
@ -1,21 +1,29 @@
|
||||||
{
|
{
|
||||||
"name": "grub",
|
"name": "grub",
|
||||||
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
"name": "grub",
|
||||||
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@automerge/automerge": "^2.0.3",
|
"@automerge/automerge": "^2.0.3",
|
||||||
|
"bootstrap": "^5.3.1",
|
||||||
"cbor": "npm:@jprochazk/cbor@^0.5.0",
|
"cbor": "npm:@jprochazk/cbor@^0.5.0",
|
||||||
"libsodium": "^0.7.11",
|
"libsodium": "^0.7.11",
|
||||||
"libsodium-wrappers": "^0.7.11",
|
"libsodium-wrappers": "^0.7.11",
|
||||||
|
"libsodium-wrappers-sumo": "^0.7.11",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"match-sorter": "^6.3.1",
|
"match-sorter": "^6.3.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-bootstrap": "^2.8.0",
|
||||||
|
"react-bootstrap-icons": "^1.10.3",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^6.15.0",
|
"react-router-dom": "^6.15.0",
|
||||||
"react-use-websocket": "^4.3.1",
|
"react-use-websocket": "^4.3.1",
|
||||||
"sort-by": "^1.2.0",
|
"sort-by": "^1.2.0",
|
||||||
|
"use-debounce": "^9.0.4",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -24,6 +32,7 @@
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"@types/uuid": "^9.0.2",
|
"@types/uuid": "^9.0.2",
|
||||||
"@vitejs/plugin-react": "^4.0.4",
|
"@vitejs/plugin-react": "^4.0.4",
|
||||||
|
"sass": "^1.65.1",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
"vite-plugin-top-level-await": "^1.3.1",
|
"vite-plugin-top-level-await": "^1.3.1",
|
||||||
|
@ -795,6 +804,29 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@popperjs/core": {
|
||||||
|
"version": "2.11.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/popperjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-aria/ssr": {
|
||||||
|
"version": "3.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.1.tgz",
|
||||||
|
"integrity": "sha512-ovVPSD1WlRpZHt7GI9DqJrWG3OIYS+NXQ9y5HIewMJpSe+jPQmMQfyRmgX4EnvmxSlp0u04Wg/7oItcoSIb/RA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@swc/helpers": "^0.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@remix-run/router": {
|
"node_modules/@remix-run/router": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz",
|
||||||
|
@ -803,6 +835,45 @@
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@restart/hooks": {
|
||||||
|
"version": "0.4.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz",
|
||||||
|
"integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==",
|
||||||
|
"dependencies": {
|
||||||
|
"dequal": "^2.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@restart/ui": {
|
||||||
|
"version": "1.6.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz",
|
||||||
|
"integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.21.0",
|
||||||
|
"@popperjs/core": "^2.11.6",
|
||||||
|
"@react-aria/ssr": "^3.5.0",
|
||||||
|
"@restart/hooks": "^0.4.9",
|
||||||
|
"@types/warning": "^3.0.0",
|
||||||
|
"dequal": "^2.0.3",
|
||||||
|
"dom-helpers": "^5.2.0",
|
||||||
|
"uncontrollable": "^8.0.1",
|
||||||
|
"warning": "^4.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.14.0",
|
||||||
|
"react-dom": ">=16.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@restart/ui/node_modules/uncontrollable": {
|
||||||
|
"version": "8.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
|
||||||
|
"integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/plugin-virtual": {
|
"node_modules/@rollup/plugin-virtual": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.1.tgz",
|
||||||
|
@ -1014,6 +1085,14 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@swc/helpers": {
|
||||||
|
"version": "0.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz",
|
||||||
|
"integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/libsodium-wrappers": {
|
"node_modules/@types/libsodium-wrappers": {
|
||||||
"version": "0.7.10",
|
"version": "0.7.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz",
|
||||||
|
@ -1023,14 +1102,12 @@
|
||||||
"node_modules/@types/prop-types": {
|
"node_modules/@types/prop-types": {
|
||||||
"version": "15.7.5",
|
"version": "15.7.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||||
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
|
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "18.2.20",
|
"version": "18.2.20",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.20.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.20.tgz",
|
||||||
"integrity": "sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==",
|
"integrity": "sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"@types/scheduler": "*",
|
"@types/scheduler": "*",
|
||||||
|
@ -1046,11 +1123,18 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-transition-group": {
|
||||||
|
"version": "4.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
|
||||||
|
"integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/scheduler": {
|
"node_modules/@types/scheduler": {
|
||||||
"version": "0.16.3",
|
"version": "0.16.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||||
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
|
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/uuid": {
|
"node_modules/@types/uuid": {
|
||||||
"version": "9.0.2",
|
"version": "9.0.2",
|
||||||
|
@ -1058,6 +1142,11 @@
|
||||||
"integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==",
|
"integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/warning": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA=="
|
||||||
|
},
|
||||||
"node_modules/@vitejs/plugin-react": {
|
"node_modules/@vitejs/plugin-react": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz",
|
||||||
|
@ -1088,6 +1177,58 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/anymatch": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"picomatch": "^2.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/binary-extensions": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bootstrap": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/twbs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/bootstrap"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"peerDependencies": {
|
||||||
|
"@popperjs/core": "^2.11.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/braces": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"fill-range": "^7.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.21.10",
|
"version": "4.21.10",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
|
||||||
|
@ -1160,6 +1301,38 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chokidar": {
|
||||||
|
"version": "3.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
|
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"anymatch": "~3.1.2",
|
||||||
|
"braces": "~3.0.2",
|
||||||
|
"glob-parent": "~5.1.2",
|
||||||
|
"is-binary-path": "~2.1.0",
|
||||||
|
"is-glob": "~4.0.1",
|
||||||
|
"normalize-path": "~3.0.0",
|
||||||
|
"readdirp": "~3.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.10.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
@ -1184,8 +1357,7 @@
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
|
@ -1204,6 +1376,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dequal": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dom-helpers": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.8.7",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.490",
|
"version": "1.4.490",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz",
|
||||||
|
@ -1265,6 +1454,18 @@
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fill-range": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
|
@ -1288,6 +1489,18 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/glob-parent": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-glob": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "11.12.0",
|
"version": "11.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
|
||||||
|
@ -1311,6 +1524,62 @@
|
||||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/immutable": {
|
||||||
|
"version": "4.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.2.tgz",
|
||||||
|
"integrity": "sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/invariant": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-binary-path": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"binary-extensions": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-extglob": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-glob": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-extglob": "^2.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
@ -1345,6 +1614,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.11.tgz",
|
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.11.tgz",
|
||||||
"integrity": "sha512-WPfJ7sS53I2s4iM58QxY3Inb83/6mjlYgcmZs7DJsvDlnmVUwNinBCi5vBT43P6bHRy01O4zsMU2CoVR6xJ40A=="
|
"integrity": "sha512-WPfJ7sS53I2s4iM58QxY3Inb83/6mjlYgcmZs7DJsvDlnmVUwNinBCi5vBT43P6bHRy01O4zsMU2CoVR6xJ40A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/libsodium-sumo": {
|
||||||
|
"version": "0.7.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.11.tgz",
|
||||||
|
"integrity": "sha512-bY+7ph7xpk51Ez2GbE10lXAQ5sJma6NghcIDaSPbM/G9elfrjLa0COHl/7P6Wb/JizQzl5UQontOOP1z0VwbLA=="
|
||||||
|
},
|
||||||
"node_modules/libsodium-wrappers": {
|
"node_modules/libsodium-wrappers": {
|
||||||
"version": "0.7.11",
|
"version": "0.7.11",
|
||||||
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz",
|
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz",
|
||||||
|
@ -1353,6 +1627,14 @@
|
||||||
"libsodium": "^0.7.11"
|
"libsodium": "^0.7.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/libsodium-wrappers-sumo": {
|
||||||
|
"version": "0.7.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.11.tgz",
|
||||||
|
"integrity": "sha512-DGypHOmJbB1nZn89KIfGOAkDgfv5N6SBGC3Qvmy/On0P0WD1JQvNRS/e3UL3aFF+xC0m+MYz5M+MnRnK2HMrKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"libsodium-sumo": "^0.7.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lie": {
|
"node_modules/lie": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
||||||
|
@ -1428,6 +1710,23 @@
|
||||||
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/normalize-path": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-path": {
|
"node_modules/object-path": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/object-path/-/object-path-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/object-path/-/object-path-0.6.0.tgz",
|
||||||
|
@ -1442,6 +1741,18 @@
|
||||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.27",
|
"version": "8.4.27",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
||||||
|
@ -1470,6 +1781,38 @@
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prop-types": {
|
||||||
|
"version": "15.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"react-is": "^16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prop-types-extra": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
|
||||||
|
"dependencies": {
|
||||||
|
"react-is": "^16.3.2",
|
||||||
|
"warning": "^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=0.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prop-types-extra/node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
|
},
|
||||||
|
"node_modules/prop-types/node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
|
@ -1481,6 +1824,46 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-bootstrap": {
|
||||||
|
"version": "2.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz",
|
||||||
|
"integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.21.0",
|
||||||
|
"@restart/hooks": "^0.4.9",
|
||||||
|
"@restart/ui": "^1.6.3",
|
||||||
|
"@types/react-transition-group": "^4.4.5",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
|
"dom-helpers": "^5.2.1",
|
||||||
|
"invariant": "^2.2.4",
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"prop-types-extra": "^1.1.0",
|
||||||
|
"react-transition-group": "^4.4.5",
|
||||||
|
"uncontrollable": "^7.2.1",
|
||||||
|
"warning": "^4.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": ">=16.14.8",
|
||||||
|
"react": ">=16.14.0",
|
||||||
|
"react-dom": ">=16.14.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-bootstrap-icons": {
|
||||||
|
"version": "1.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-bootstrap-icons/-/react-bootstrap-icons-1.10.3.tgz",
|
||||||
|
"integrity": "sha512-j4hSby6gT9/enhl3ybB1tfr1slZNAYXDVntcRrmVjxB3//2WwqrzpESVqKhyayYVaWpEtnwf9wgUQ03cuziwrw==",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
|
@ -1493,6 +1876,11 @@
|
||||||
"react": "^18.2.0"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-lifecycles-compat": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
||||||
|
@ -1532,6 +1920,21 @@
|
||||||
"react-dom": ">=16.8"
|
"react-dom": ">=16.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-transition-group": {
|
||||||
|
"version": "4.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||||
|
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.5.5",
|
||||||
|
"dom-helpers": "^5.0.1",
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"prop-types": "^15.6.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.6.0",
|
||||||
|
"react-dom": ">=16.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-use-websocket": {
|
"node_modules/react-use-websocket": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.3.1.tgz",
|
||||||
|
@ -1541,6 +1944,18 @@
|
||||||
"react-dom": ">= 18.0.0"
|
"react-dom": ">= 18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readdirp": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
||||||
|
@ -1567,6 +1982,23 @@
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sass": {
|
||||||
|
"version": "1.65.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.65.1.tgz",
|
||||||
|
"integrity": "sha512-9DINwtHmA41SEd36eVPQ9BJKpn7eKDQmUHmpI0y5Zv2Rcorrh0zS+cFrt050hdNbmmCNKTW3hV5mWfuegNRsEA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
|
"immutable": "^4.0.0",
|
||||||
|
"source-map-js": ">=0.6.2 <2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sass": "sass.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/scheduler": {
|
"node_modules/scheduler": {
|
||||||
"version": "0.23.0",
|
"version": "0.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||||
|
@ -1622,6 +2054,23 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
|
||||||
|
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
|
||||||
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.1.6",
|
"version": "5.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
|
||||||
|
@ -1635,6 +2084,20 @@
|
||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uncontrollable": {
|
||||||
|
"version": "7.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
|
||||||
|
"integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.6.3",
|
||||||
|
"@types/react": ">=16.9.11",
|
||||||
|
"invariant": "^2.2.4",
|
||||||
|
"react-lifecycles-compat": "^3.0.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=15.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
|
||||||
|
@ -1665,6 +2128,17 @@
|
||||||
"browserslist": ">= 4.21.0"
|
"browserslist": ">= 4.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-debounce": {
|
||||||
|
"version": "9.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-9.0.4.tgz",
|
||||||
|
"integrity": "sha512-6X8H/mikbrt0XE8e+JXRtZ8yYVvKkdYRfmIhWZYsP8rcNs9hk3APV8Ua2mFkKRLcJKVdnX2/Vwrmg2GWKUQEaQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||||
|
@ -1751,6 +2225,14 @@
|
||||||
"vite": "^2 || ^3 || ^4"
|
"vite": "^2 || ^3 || ^4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/warning": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"@types/uuid": "^9.0.2",
|
"@types/uuid": "^9.0.2",
|
||||||
"@vitejs/plugin-react": "^4.0.4",
|
"@vitejs/plugin-react": "^4.0.4",
|
||||||
|
"sass": "^1.65.1",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
"vite-plugin-top-level-await": "^1.3.1",
|
"vite-plugin-top-level-await": "^1.3.1",
|
||||||
|
@ -18,16 +19,21 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@automerge/automerge": "^2.0.3",
|
"@automerge/automerge": "^2.0.3",
|
||||||
|
"bootstrap": "^5.3.1",
|
||||||
"cbor": "npm:@jprochazk/cbor@^0.5.0",
|
"cbor": "npm:@jprochazk/cbor@^0.5.0",
|
||||||
"libsodium": "^0.7.11",
|
"libsodium": "^0.7.11",
|
||||||
"libsodium-wrappers": "^0.7.11",
|
"libsodium-wrappers": "^0.7.11",
|
||||||
|
"libsodium-wrappers-sumo": "^0.7.11",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"match-sorter": "^6.3.1",
|
"match-sorter": "^6.3.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-bootstrap": "^2.8.0",
|
||||||
|
"react-bootstrap-icons": "^1.10.3",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router-dom": "^6.15.0",
|
"react-router-dom": "^6.15.0",
|
||||||
"react-use-websocket": "^4.3.1",
|
"react-use-websocket": "^4.3.1",
|
||||||
"sort-by": "^1.2.0",
|
"sort-by": "^1.2.0",
|
||||||
|
"use-debounce": "^9.0.4",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[clap(long, default_value = "3000")]
|
#[clap(long, default_value = "6106")]
|
||||||
port: u16,
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt::{Formatter};
|
use std::fmt::Formatter;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use axum::extract::ws;
|
use axum::extract::ws;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["ESNext", "DOM"],
|
"lib": ["ESNext", "DOM"],
|
||||||
"target": "ESNext",
|
|
||||||
"jsx": "react-jsx"
|
"jsx": "react-jsx"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
"/ws": {
|
"/ws": {
|
||||||
target: "ws://localhost:3000/ws",
|
target: "ws://localhost:6106/ws",
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/ws/, ""),
|
rewrite: (path) => path.replace(/^\/ws/, ""),
|
||||||
ws: true,
|
ws: true,
|
||||||
|
|
Loading…
Reference in a new issue