savibg this weird hacked together state
This commit is contained in:
parent
4c73ee78ce
commit
719b501386
14 changed files with 916 additions and 13 deletions
55
app/routes/api.ably.tsx
Normal file
55
app/routes/api.ably.tsx
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import { getAuth } from "@clerk/remix/ssr.server";
|
||||||
|
import { LoaderFunctionArgs, json } from "@remix-run/node";
|
||||||
|
import { AblyTokenResponse } from "~/services/types";
|
||||||
|
|
||||||
|
// Get Room List
|
||||||
|
export async function loader({ context, params, request }: LoaderFunctionArgs) {
|
||||||
|
const { userId } = await getAuth({ context, params, request });
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return json("Not Signed In!", {
|
||||||
|
status: 403,
|
||||||
|
statusText: "UNAUTHORIZED!",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!process.env.ABLY_API_KEY) {
|
||||||
|
return new Response(
|
||||||
|
`Missing ABLY_API_KEY environment variable.
|
||||||
|
If you're running locally, please ensure you have a ./.env file with a value for ABLY_API_KEY=your-key.
|
||||||
|
If you're running in Netlify, make sure you've configured env variable ABLY_API_KEY.
|
||||||
|
Please see README.md for more details on configuring your Ably API Key.`,
|
||||||
|
{
|
||||||
|
status: 500,
|
||||||
|
statusText: `Missing ABLY_API_KEY environment variable.
|
||||||
|
If you're running locally, please ensure you have a ./.env file with a value for ABLY_API_KEY=your-key.
|
||||||
|
If you're running in Netlify, make sure you've configured env variable ABLY_API_KEY.
|
||||||
|
Please see README.md for more details on configuring your Ably API Key.`,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyName = process.env.ABLY_API_KEY!.split(":")[0];
|
||||||
|
|
||||||
|
const tokenResponse = await fetch(
|
||||||
|
`https://rest.ably.io/keys/${keyName}/requestToken`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Basic ${btoa(process.env.ABLY_API_KEY!)}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
keyName,
|
||||||
|
clientId: userId,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const tokenResponseData = (await tokenResponse.json()) as AblyTokenResponse;
|
||||||
|
|
||||||
|
return json(tokenResponseData, {
|
||||||
|
status: 200,
|
||||||
|
statusText: "SUCCESS",
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { getAuth } from "@clerk/remix/ssr.server";
|
import { getAuth } from "@clerk/remix/ssr.server";
|
||||||
import { ActionFunctionArgs, json } from "@remix-run/node";
|
import { ActionFunctionArgs, json } from "@remix-run/node";
|
||||||
import { createId } from "@paralleldrive/cuid2";
|
import { createId } from "@paralleldrive/cuid2";
|
||||||
import { db } from "~/services/db";
|
import { db } from "~/services/db.server";
|
||||||
import { emitter } from "~/services/emitter.server";
|
import { emitter } from "~/services/emitter.server";
|
||||||
import { rooms } from "~/services/schema";
|
import { rooms } from "~/services/schema";
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { getAuth } from "@clerk/remix/ssr.server";
|
import { getAuth } from "@clerk/remix/ssr.server";
|
||||||
import { ActionFunctionArgs, json } from "@remix-run/node";
|
import { ActionFunctionArgs, json } from "@remix-run/node";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "~/services/db";
|
import { db } from "~/services/db.server";
|
||||||
import { emitter } from "~/services/emitter.server";
|
import { emitter } from "~/services/emitter.server";
|
||||||
import { rooms } from "~/services/schema";
|
import { rooms } from "~/services/schema";
|
||||||
|
|
||||||
|
|
45
app/routes/api.room.get.$roomId.tsx
Normal file
45
app/routes/api.room.get.$roomId.tsx
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { getAuth } from "@clerk/remix/ssr.server";
|
||||||
|
import { LoaderFunctionArgs, json } from "@remix-run/node";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { eventStream } from "remix-utils/sse/server";
|
||||||
|
import { db } from "~/services/db.server";
|
||||||
|
import { emitter } from "~/services/emitter.server";
|
||||||
|
import { rooms } from "~/services/schema";
|
||||||
|
|
||||||
|
// Get Room List
|
||||||
|
export async function loader({ context, params, request }: LoaderFunctionArgs) {
|
||||||
|
const { userId } = await getAuth({ context, params, request });
|
||||||
|
|
||||||
|
const roomId = params.roomId;
|
||||||
|
|
||||||
|
if (!roomId) {
|
||||||
|
return json("RoomId Missing!", {
|
||||||
|
status: 400,
|
||||||
|
statusText: "BAD REQUEST!",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventStream(request.signal, function setup(send) {
|
||||||
|
async function handler() {
|
||||||
|
const roomList = await db.query.rooms.findMany({
|
||||||
|
where: eq(rooms.userId, userId || ""),
|
||||||
|
});
|
||||||
|
send({ event: roomId, data: JSON.stringify(roomList) });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial fetch
|
||||||
|
db.query.rooms
|
||||||
|
.findMany({
|
||||||
|
where: eq(rooms.userId, userId || ""),
|
||||||
|
})
|
||||||
|
.then((roomList) => {
|
||||||
|
send({ event: roomId, data: JSON.stringify(roomList) });
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on("roomlist", handler);
|
||||||
|
|
||||||
|
return function clear() {
|
||||||
|
emitter.off("roomlist", handler);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
import { getAuth } from "@clerk/remix/ssr.server";
|
import { getAuth } from "@clerk/remix/ssr.server";
|
||||||
import { LoaderFunctionArgs } from "@remix-run/node";
|
import { LoaderFunctionArgs, json } from "@remix-run/node";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { eventStream } from "remix-utils/sse/server";
|
import { eventStream } from "remix-utils/sse/server";
|
||||||
import { db } from "~/services/db";
|
import { db } from "~/services/db.server";
|
||||||
import { emitter } from "~/services/emitter.server";
|
import { emitter } from "~/services/emitter.server";
|
||||||
import { rooms } from "~/services/schema";
|
import { rooms } from "~/services/schema";
|
||||||
|
|
||||||
|
@ -10,12 +10,20 @@ import { rooms } from "~/services/schema";
|
||||||
export async function loader({ context, params, request }: LoaderFunctionArgs) {
|
export async function loader({ context, params, request }: LoaderFunctionArgs) {
|
||||||
const { userId } = await getAuth({ context, params, request });
|
const { userId } = await getAuth({ context, params, request });
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return json("Not Signed In!", {
|
||||||
|
status: 403,
|
||||||
|
statusText: "UNAUTHORIZED!",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return eventStream(request.signal, function setup(send) {
|
return eventStream(request.signal, function setup(send) {
|
||||||
async function handler() {
|
async function handler() {
|
||||||
const roomList = await db.query.rooms.findMany({
|
const roomList = await db.query.rooms.findMany({
|
||||||
where: eq(rooms.userId, userId || ""),
|
where: eq(rooms.userId, userId || ""),
|
||||||
});
|
});
|
||||||
send({ event: "roomlist", data: JSON.stringify(roomList) });
|
|
||||||
|
send({ event: userId!, data: JSON.stringify(roomList) });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial fetch
|
// Initial fetch
|
||||||
|
@ -24,7 +32,7 @@ export async function loader({ context, params, request }: LoaderFunctionArgs) {
|
||||||
where: eq(rooms.userId, userId || ""),
|
where: eq(rooms.userId, userId || ""),
|
||||||
})
|
})
|
||||||
.then((roomList) => {
|
.then((roomList) => {
|
||||||
send({ event: "roomlist", data: JSON.stringify(roomList) });
|
send({ event: userId!, data: JSON.stringify(roomList) });
|
||||||
});
|
});
|
||||||
|
|
||||||
emitter.on("roomlist", handler);
|
emitter.on("roomlist", handler);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { useUser } from "@clerk/remix";
|
|
||||||
import { getAuth } from "@clerk/remix/ssr.server";
|
import { getAuth } from "@clerk/remix/ssr.server";
|
||||||
import { LoaderFunction, redirect } from "@remix-run/node";
|
import { LoaderFunction, redirect } from "@remix-run/node";
|
||||||
import { Link } from "@remix-run/react";
|
import { Link } from "@remix-run/react";
|
||||||
|
@ -6,6 +5,7 @@ import { LogInIcon, TrashIcon } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import LoadingIndicator from "~/components/LoadingIndicator";
|
import LoadingIndicator from "~/components/LoadingIndicator";
|
||||||
import { useEventSource } from "remix-utils/sse/react";
|
import { useEventSource } from "remix-utils/sse/react";
|
||||||
|
import { useAuth } from "@clerk/remix";
|
||||||
|
|
||||||
export const loader: LoaderFunction = async (args) => {
|
export const loader: LoaderFunction = async (args) => {
|
||||||
const { userId } = await getAuth(args);
|
const { userId } = await getAuth(args);
|
||||||
|
@ -34,8 +34,9 @@ type RoomsResponse =
|
||||||
| null
|
| null
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
export default function Index() {
|
export default function Dashboard() {
|
||||||
let roomsFromDb = useEventSource("/api/room/get/all", { event: "roomlist" });
|
const { userId } = useAuth();
|
||||||
|
let roomsFromDb = useEventSource("/api/room/get/all", { event: userId! });
|
||||||
|
|
||||||
let roomsFromDbParsed = JSON.parse(roomsFromDb!) as RoomsResponse;
|
let roomsFromDbParsed = JSON.parse(roomsFromDb!) as RoomsResponse;
|
||||||
|
|
||||||
|
|
479
app/routes/room.$roomId.tsx
Normal file
479
app/routes/room.$roomId.tsx
Normal file
|
@ -0,0 +1,479 @@
|
||||||
|
import { getAuth } from "@clerk/remix/ssr.server";
|
||||||
|
import { LoaderFunction, redirect } from "@remix-run/node";
|
||||||
|
import { Link, useParams } from "@remix-run/react";
|
||||||
|
import { AblyProvider, useChannel, usePresence } from "ably/react";
|
||||||
|
import {} from "ably/react";
|
||||||
|
import * as Ably from "ably";
|
||||||
|
import {
|
||||||
|
CheckCircleIcon,
|
||||||
|
CopyIcon,
|
||||||
|
CrownIcon,
|
||||||
|
DownloadIcon,
|
||||||
|
EyeIcon,
|
||||||
|
EyeOffIcon,
|
||||||
|
HourglassIcon,
|
||||||
|
RefreshCwIcon,
|
||||||
|
SaveIcon,
|
||||||
|
ShieldIcon,
|
||||||
|
StarIcon,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import LoadingIndicator from "~/components/LoadingIndicator";
|
||||||
|
import { useEventSource } from "remix-utils/sse/react";
|
||||||
|
import {
|
||||||
|
EventTypes,
|
||||||
|
PresenceItem,
|
||||||
|
RoomResponse,
|
||||||
|
VoteResponse,
|
||||||
|
} from "~/services/types";
|
||||||
|
import { isAdmin, isVIP, jsonToCsv } from "~/services/helpers";
|
||||||
|
import { useUser } from "@clerk/remix";
|
||||||
|
|
||||||
|
export const loader: LoaderFunction = async (args) => {
|
||||||
|
const { userId } = await getAuth(args);
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return redirect("/sign-in");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Room() {
|
||||||
|
const { user } = useUser();
|
||||||
|
const params = useParams();
|
||||||
|
const roomId = params.roomId;
|
||||||
|
|
||||||
|
let roomFromDb = useEventSource("/api/room/get", { event: params.roomId });
|
||||||
|
let votesFromDb = useEventSource("/api/votes/get/all", {
|
||||||
|
event: params.roomId,
|
||||||
|
});
|
||||||
|
|
||||||
|
let roomFromDbParsed = JSON.parse(roomFromDb!) as RoomResponse;
|
||||||
|
let votesFromDbParsed = JSON.parse(votesFromDb!) as VoteResponse;
|
||||||
|
|
||||||
|
const [storyNameText, setStoryNameText] = useState<string>("");
|
||||||
|
const [roomScale, setRoomScale] = useState<string>("");
|
||||||
|
const [copied, setCopied] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
// =================================
|
||||||
|
async function getRoomHandler() {
|
||||||
|
const response = await fetch(`/api/internal/room/${roomId}`, {
|
||||||
|
cache: "no-cache",
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
|
||||||
|
return (await response.json()) as RoomResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getVotesHandler() {
|
||||||
|
const dbVotesResponse = await fetch(`/api/internal/room/${roomId}/votes`, {
|
||||||
|
cache: "no-cache",
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
const dbVotes = (await dbVotesResponse.json()) as VoteResponse;
|
||||||
|
return dbVotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setVoteHandler(value: string) {
|
||||||
|
if (roomFromDb) {
|
||||||
|
await fetch(`/api/internal/room/${roomId}/vote`, {
|
||||||
|
cache: "no-cache",
|
||||||
|
method: "PUT",
|
||||||
|
body: JSON.stringify({
|
||||||
|
value,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setRoomHandler(data: {
|
||||||
|
visible: boolean;
|
||||||
|
reset: boolean | undefined;
|
||||||
|
log: boolean | undefined;
|
||||||
|
}) {
|
||||||
|
if (roomFromDb) {
|
||||||
|
await fetch(`/api/internal/room/${roomId}`, {
|
||||||
|
cache: "no-cache",
|
||||||
|
method: "PUT",
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: storyNameText,
|
||||||
|
visible: data.visible,
|
||||||
|
scale: roomScale,
|
||||||
|
reset: data.reset ? data.reset : false,
|
||||||
|
log: data.log ? data.log : false,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
// =================================
|
||||||
|
const getVoteForCurrentUser = () => {
|
||||||
|
if (roomFromDb) {
|
||||||
|
return (
|
||||||
|
votesFromDbParsed &&
|
||||||
|
votesFromDbParsed.find((vote) => vote.userId === user?.id)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadLogs = () => {
|
||||||
|
if (roomFromDb && votesFromDb) {
|
||||||
|
const jsonObject = roomFromDbParsed?.logs
|
||||||
|
.map((item) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
created_at: item.created_at,
|
||||||
|
userId: item.userId,
|
||||||
|
roomId: item.roomId,
|
||||||
|
roomName: item.roomName,
|
||||||
|
storyName: item.storyName,
|
||||||
|
scale: item.scale,
|
||||||
|
votes: item.votes,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.concat({
|
||||||
|
id: "LATEST",
|
||||||
|
created_at: new Date(),
|
||||||
|
userId: roomFromDbParsed.userId,
|
||||||
|
roomId: roomFromDbParsed.id,
|
||||||
|
roomName: roomFromDbParsed.roomName,
|
||||||
|
storyName: storyNameText,
|
||||||
|
scale: roomScale,
|
||||||
|
votes: votesFromDbParsed?.map((vote) => {
|
||||||
|
return {
|
||||||
|
value: vote.value,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
jsonToCsv(jsonObject!, `sp_${roomId}.csv`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyRoomURLHandler = () => {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(window.location.href)
|
||||||
|
.then(() => {
|
||||||
|
console.log(`Copied Room Link to Clipboard!`);
|
||||||
|
setCopied(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setCopied(false);
|
||||||
|
}, 2000);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log(`Error Copying Room Link to Clipboard!`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const voteString = (
|
||||||
|
visible: boolean,
|
||||||
|
votes: typeof votesFromDbParsed,
|
||||||
|
presenceItem: PresenceItem
|
||||||
|
) => {
|
||||||
|
const matchedVote = votes?.find(
|
||||||
|
(vote) => vote.userId === presenceItem.client_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
if (!!matchedVote) {
|
||||||
|
return <div>{matchedVote.value}</div>;
|
||||||
|
} else {
|
||||||
|
return <HourglassIcon className="text-xl text-error" />;
|
||||||
|
}
|
||||||
|
} else if (!!matchedVote) {
|
||||||
|
return <CheckCircleIcon className="text-xl text-success" />;
|
||||||
|
} else {
|
||||||
|
return <HourglassIcon className="text-xl animate-spin text-warning" />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
// =================================
|
||||||
|
useChannel(
|
||||||
|
{
|
||||||
|
channelName: `${process.env.APP_ENV}-${roomId}`,
|
||||||
|
},
|
||||||
|
({ name }: { name: string }) => {
|
||||||
|
if (name === EventTypes.ROOM_UPDATE) {
|
||||||
|
void getRoomHandler();
|
||||||
|
void getVotesHandler();
|
||||||
|
} else if (name === EventTypes.VOTE_UPDATE) {
|
||||||
|
void getVotesHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const { presenceData } = usePresence<PresenceItem>(
|
||||||
|
`${process.env.APP_ENV}-${roomId}`,
|
||||||
|
{
|
||||||
|
name: (user?.fullName ?? user?.username) || "",
|
||||||
|
image: user?.imageUrl || "",
|
||||||
|
client_id: user?.id || "unknown",
|
||||||
|
isAdmin: isAdmin(user?.publicMetadata),
|
||||||
|
isVIP: isVIP(user?.publicMetadata),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (roomFromDb) {
|
||||||
|
setStoryNameText(roomFromDbParsed?.storyName || "");
|
||||||
|
setRoomScale(roomFromDbParsed?.scale || "ERROR");
|
||||||
|
}
|
||||||
|
}, [roomFromDb]);
|
||||||
|
|
||||||
|
// UI
|
||||||
|
// =================================
|
||||||
|
// Room is loading
|
||||||
|
if (!roomFromDbParsed) {
|
||||||
|
return <LoadingIndicator />;
|
||||||
|
// Room has been loaded
|
||||||
|
} else {
|
||||||
|
return roomFromDb ? (
|
||||||
|
<div className="flex flex-col gap-4 text-center justify-center items-center">
|
||||||
|
<div className="text-2xl">{roomFromDbParsed.roomName}</div>
|
||||||
|
<div className="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-md">
|
||||||
|
<div>ID:</div>
|
||||||
|
<div>{roomFromDbParsed.id}</div>
|
||||||
|
|
||||||
|
<button>
|
||||||
|
{copied ? (
|
||||||
|
<CheckCircleIcon className="mx-1 text-success animate-bounce" />
|
||||||
|
) : (
|
||||||
|
<CopyIcon
|
||||||
|
className="mx-1 hover:text-primary"
|
||||||
|
onClick={copyRoomURLHandler}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{roomFromDb && (
|
||||||
|
<div className="card card-compact bg-base-100 shadow-xl">
|
||||||
|
<div className="card-body">
|
||||||
|
<h2 className="card-title mx-auto">
|
||||||
|
Story: {roomFromDbParsed.storyName}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul className="p-0 flex flex-row flex-wrap justify-center items-center text-ceter gap-4">
|
||||||
|
{presenceData &&
|
||||||
|
presenceData
|
||||||
|
.filter(
|
||||||
|
(value, index, self) =>
|
||||||
|
index ===
|
||||||
|
self.findIndex(
|
||||||
|
(presenceItem) =>
|
||||||
|
presenceItem.clientId === value.clientId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map((presenceItem) => {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={presenceItem.clientId}
|
||||||
|
className="flex flex-row items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<div className="w-10 rounded-full avatar">
|
||||||
|
<img
|
||||||
|
src={presenceItem.data.image}
|
||||||
|
alt={`${presenceItem.data.name}'s Profile Picture`}
|
||||||
|
height={32}
|
||||||
|
width={32}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-md">
|
||||||
|
{presenceItem.data.name}{" "}
|
||||||
|
{presenceItem.data.isAdmin && (
|
||||||
|
<span
|
||||||
|
className="tooltip tooltip-primary"
|
||||||
|
data-tip="Admin"
|
||||||
|
>
|
||||||
|
<ShieldIcon className="inline-block text-primary" />
|
||||||
|
</span>
|
||||||
|
)}{" "}
|
||||||
|
{presenceItem.data.isVIP && (
|
||||||
|
<span
|
||||||
|
className="tooltip tooltip-secondary"
|
||||||
|
data-tip="VIP"
|
||||||
|
>
|
||||||
|
<StarIcon className="inline-block text-secondary" />
|
||||||
|
</span>
|
||||||
|
)}{" "}
|
||||||
|
{presenceItem.clientId ===
|
||||||
|
roomFromDbParsed?.userId && (
|
||||||
|
<span
|
||||||
|
className="tooltip tooltip-warning"
|
||||||
|
data-tip="Room Owner"
|
||||||
|
>
|
||||||
|
<CrownIcon className="inline-block text-yellow-500" />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{" : "}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{roomFromDb &&
|
||||||
|
votesFromDb &&
|
||||||
|
voteString(
|
||||||
|
roomFromDbParsed?.visible!,
|
||||||
|
votesFromDbParsed,
|
||||||
|
presenceItem.data
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div className="join md:btn-group-horizontal mx-auto">
|
||||||
|
{roomFromDbParsed.scale?.split(",").map((scaleItem, index) => {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
className={`join-item ${
|
||||||
|
getVoteForCurrentUser()?.value === scaleItem
|
||||||
|
? "btn btn-active btn-primary"
|
||||||
|
: "btn"
|
||||||
|
}`}
|
||||||
|
onClick={() => void setVoteHandler(scaleItem)}
|
||||||
|
>
|
||||||
|
{scaleItem}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!!roomFromDbParsed &&
|
||||||
|
(roomFromDbParsed.userId === user?.id ||
|
||||||
|
isAdmin(user?.publicMetadata)) && (
|
||||||
|
<>
|
||||||
|
<div className="card card-compact bg-base-100 shadow-xl">
|
||||||
|
<div className="card-body flex flex-col flex-wrap">
|
||||||
|
<h2 className="card-title">Room Settings</h2>
|
||||||
|
|
||||||
|
<label className="label">
|
||||||
|
{"Vote Scale (Comma Separated):"}{" "}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Scale (Comma Separated)"
|
||||||
|
className="input input-bordered"
|
||||||
|
value={roomScale}
|
||||||
|
onChange={(event) => {
|
||||||
|
setRoomScale(event.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label className="label">{"Story Name:"} </label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Story Name"
|
||||||
|
className="input input-bordered"
|
||||||
|
value={storyNameText}
|
||||||
|
onChange={(event) => {
|
||||||
|
setStoryNameText(event.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex flex-row flex-wrap text-center items-center justify-center gap-2">
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
void setRoomHandler({
|
||||||
|
visible: !roomFromDbParsed?.visible,
|
||||||
|
reset: false,
|
||||||
|
log: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="btn btn-primary inline-flex"
|
||||||
|
>
|
||||||
|
{roomFromDbParsed.visible ? (
|
||||||
|
<>
|
||||||
|
<EyeOffIcon className="text-xl mr-1" />
|
||||||
|
Hide
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<EyeIcon className="text-xl mr-1" />
|
||||||
|
Show
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
void setRoomHandler({
|
||||||
|
visible: false,
|
||||||
|
reset: true,
|
||||||
|
log:
|
||||||
|
roomFromDbParsed?.storyName === storyNameText ||
|
||||||
|
votesFromDb?.length === 0
|
||||||
|
? false
|
||||||
|
: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="btn btn-primary inline-flex"
|
||||||
|
disabled={
|
||||||
|
[...new Set(roomScale.split(","))].filter(
|
||||||
|
(item) => item !== ""
|
||||||
|
).length <= 1
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{roomFromDbParsed?.storyName === storyNameText ||
|
||||||
|
votesFromDb?.length === 0 ? (
|
||||||
|
<>
|
||||||
|
<RefreshCwIcon className="text-xl mr-1" /> Reset
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<SaveIcon className="text-xl mr-1" /> Save
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{votesFromDb &&
|
||||||
|
(roomFromDbParsed?.logs.length > 0 ||
|
||||||
|
votesFromDb.length > 0) && (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={() => downloadLogs()}
|
||||||
|
className="btn btn-primary inline-flex hover:animate-pulse"
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
<DownloadIcon className="text-xl" />
|
||||||
|
</>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="text-center">
|
||||||
|
<h1 className="text-5xl font-bold m-2">4️⃣0️⃣4️⃣</h1>
|
||||||
|
<h1 className="text-5xl font-bold m-2">
|
||||||
|
Oops! This room does not appear to exist, or may have been deleted! 😢
|
||||||
|
</h1>
|
||||||
|
<Link
|
||||||
|
about="Back to home."
|
||||||
|
to="/"
|
||||||
|
className="btn btn-secondary normal-case text-xl m-2"
|
||||||
|
>
|
||||||
|
Back to Home
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
47
app/services/helpers.ts
Normal file
47
app/services/helpers.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { json2csv } from "csv42";
|
||||||
|
|
||||||
|
export const jsonToCsv = (jsonObject: Array<object>, fileName: string) => {
|
||||||
|
const csv = json2csv(jsonObject);
|
||||||
|
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
||||||
|
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.setAttribute("href", url);
|
||||||
|
link.setAttribute("download", fileName);
|
||||||
|
link.style.visibility = "hidden";
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isAdmin(meta: UserPublicMetadata | undefined) {
|
||||||
|
return (meta?.isAdmin as boolean | undefined) || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVIP(meta: UserPublicMetadata | undefined) {
|
||||||
|
return (meta?.isVIP as boolean | undefined) || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const writeToLogs = (
|
||||||
|
level: "warn" | "info" | "error" | "success",
|
||||||
|
message: string
|
||||||
|
) => {
|
||||||
|
switch (level) {
|
||||||
|
case "info":
|
||||||
|
console.log(`[ℹ️ INFO]: ${message}`);
|
||||||
|
break;
|
||||||
|
case "warn":
|
||||||
|
console.log(`[⚠️ WARN]: ${message}`);
|
||||||
|
break;
|
||||||
|
case "error":
|
||||||
|
console.log(`[❌ ERROR]: ${message}`);
|
||||||
|
break;
|
||||||
|
case "success":
|
||||||
|
console.log(`[✅ SUCCESS]: ${message}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.log(`[ℹ️ INFO]: ${message}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
76
app/services/types.ts
Normal file
76
app/services/types.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
type BetterEnum<T> = T[keyof T];
|
||||||
|
|
||||||
|
export const EventTypes = {
|
||||||
|
ROOM_LIST_UPDATE: "room.list.update",
|
||||||
|
ROOM_UPDATE: "room.update",
|
||||||
|
VOTE_UPDATE: "vote.update",
|
||||||
|
} as const;
|
||||||
|
export type EventType = BetterEnum<typeof EventTypes>;
|
||||||
|
|
||||||
|
export interface PresenceItem {
|
||||||
|
name: string;
|
||||||
|
image: string;
|
||||||
|
client_id: string;
|
||||||
|
isAdmin: boolean;
|
||||||
|
isVIP: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RoomsResponse =
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
roomName: string;
|
||||||
|
}[]
|
||||||
|
| {
|
||||||
|
roomName: string | null;
|
||||||
|
id: string;
|
||||||
|
created_at: Date | null;
|
||||||
|
userId: string;
|
||||||
|
storyName: string | null;
|
||||||
|
visible: boolean;
|
||||||
|
scale: string;
|
||||||
|
}[]
|
||||||
|
| null
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
export type RoomResponse =
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
created_at: Date | null;
|
||||||
|
userId: string;
|
||||||
|
roomName: string | null;
|
||||||
|
storyName: string | null;
|
||||||
|
visible: boolean;
|
||||||
|
scale: string | null;
|
||||||
|
logs: {
|
||||||
|
id: string;
|
||||||
|
created_at: Date | null;
|
||||||
|
userId: string;
|
||||||
|
roomId: string;
|
||||||
|
roomName: string | null;
|
||||||
|
storyName: string | null;
|
||||||
|
scale: string | null;
|
||||||
|
votes: unknown;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
| null;
|
||||||
|
|
||||||
|
export type VoteResponse =
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
value: string;
|
||||||
|
created_at: Date | null;
|
||||||
|
userId: string;
|
||||||
|
roomId: string;
|
||||||
|
}[]
|
||||||
|
| null
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
export type AblyTokenResponse = {
|
||||||
|
token: string;
|
||||||
|
issued: number;
|
||||||
|
expires: number;
|
||||||
|
capability: string;
|
||||||
|
clientId: string;
|
||||||
|
};
|
|
@ -18,6 +18,8 @@
|
||||||
"@remix-run/node": "^2.3.0",
|
"@remix-run/node": "^2.3.0",
|
||||||
"@remix-run/react": "^2.3.0",
|
"@remix-run/react": "^2.3.0",
|
||||||
"@remix-run/serve": "^2.3.0",
|
"@remix-run/serve": "^2.3.0",
|
||||||
|
"ably": "1.2.47",
|
||||||
|
"csv42": "^5.0.0",
|
||||||
"drizzle-orm": "^0.29.0",
|
"drizzle-orm": "^0.29.0",
|
||||||
"isbot": "^3.7.1",
|
"isbot": "^3.7.1",
|
||||||
"lucide-react": "^0.292.0",
|
"lucide-react": "^0.292.0",
|
||||||
|
|
193
pnpm-lock.yaml
generated
193
pnpm-lock.yaml
generated
|
@ -26,6 +26,12 @@ dependencies:
|
||||||
'@remix-run/serve':
|
'@remix-run/serve':
|
||||||
specifier: ^2.3.0
|
specifier: ^2.3.0
|
||||||
version: 2.3.0(typescript@5.3.2)
|
version: 2.3.0(typescript@5.3.2)
|
||||||
|
ably:
|
||||||
|
specifier: 1.2.47
|
||||||
|
version: 1.2.47(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
csv42:
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.0
|
||||||
drizzle-orm:
|
drizzle-orm:
|
||||||
specifier: ^0.29.0
|
specifier: ^0.29.0
|
||||||
version: 0.29.0(@libsql/client@0.4.0-pre.2)(better-sqlite3@9.1.1)
|
version: 0.29.0(@libsql/client@0.4.0-pre.2)(better-sqlite3@9.1.1)
|
||||||
|
@ -87,6 +93,12 @@ packages:
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@ably/msgpack-js@0.4.0:
|
||||||
|
resolution: {integrity: sha512-IPt/BoiQwCWubqoNik1aw/6M/DleMdrxJOUpSja6xmMRbT2p1TA8oqKWgfZabqzrq8emRNeSl/+4XABPNnW5pQ==}
|
||||||
|
dependencies:
|
||||||
|
bops: 1.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@alloc/quick-lru@5.2.0:
|
/@alloc/quick-lru@5.2.0:
|
||||||
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -1875,6 +1887,18 @@ packages:
|
||||||
resolution: {integrity: sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==}
|
resolution: {integrity: sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@sindresorhus/is@4.6.0:
|
||||||
|
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@szmarczak/http-timer@4.0.6:
|
||||||
|
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
defer-to-connect: 2.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@testing-library/dom@8.20.1:
|
/@testing-library/dom@8.20.1:
|
||||||
resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==}
|
resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -1899,6 +1923,15 @@ packages:
|
||||||
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
|
resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/cacheable-request@6.0.3:
|
||||||
|
resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/http-cache-semantics': 4.0.4
|
||||||
|
'@types/keyv': 3.1.4
|
||||||
|
'@types/node': 20.9.3
|
||||||
|
'@types/responselike': 1.0.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/cookie@0.5.4:
|
/@types/cookie@0.5.4:
|
||||||
resolution: {integrity: sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==}
|
resolution: {integrity: sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==}
|
||||||
|
|
||||||
|
@ -1924,6 +1957,10 @@ packages:
|
||||||
'@types/unist': 2.0.10
|
'@types/unist': 2.0.10
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/http-cache-semantics@4.0.4:
|
||||||
|
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/json-schema@7.0.15:
|
/@types/json-schema@7.0.15:
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -1932,6 +1969,12 @@ packages:
|
||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/keyv@3.1.4:
|
||||||
|
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.9.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/mdast@3.0.15:
|
/@types/mdast@3.0.15:
|
||||||
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
|
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1986,6 +2029,12 @@ packages:
|
||||||
csstype: 3.1.2
|
csstype: 3.1.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/responselike@1.0.3:
|
||||||
|
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.9.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/scheduler@0.16.7:
|
/@types/scheduler@0.16.7:
|
||||||
resolution: {integrity: sha512-8g25Nl3AuB1KulTlSUsUhUo/oBgBU6XIXQ+XURpeioEbEJvkO7qI4vDfREv3vJYHHzqXjcAHvoJy4pTtSQNZtA==}
|
resolution: {integrity: sha512-8g25Nl3AuB1KulTlSUsUhUo/oBgBU6XIXQ+XURpeioEbEJvkO7qI4vDfREv3vJYHHzqXjcAHvoJy4pTtSQNZtA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -2201,6 +2250,28 @@ packages:
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
/ably@1.2.47(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-YaBr4qwRNBfb9Zb6Oolbng7oK0oDadZG0cWCOv+Wh4XOWi91JKWbcy82bzN1RKkFTT/rCFG7nZrXT5pkMroMLg==}
|
||||||
|
engines: {node: '>=5.10.x'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8.0'
|
||||||
|
react-dom: '>=16.8.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react:
|
||||||
|
optional: true
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@ably/msgpack-js': 0.4.0
|
||||||
|
got: 11.8.6
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
ws: 8.14.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
dev: false
|
||||||
|
|
||||||
/abort-controller@3.0.0:
|
/abort-controller@3.0.0:
|
||||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||||
engines: {node: '>=6.5'}
|
engines: {node: '>=6.5'}
|
||||||
|
@ -2452,6 +2523,11 @@ packages:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/base64-js@1.0.2:
|
||||||
|
resolution: {integrity: sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/base64-js@1.5.1:
|
/base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
|
@ -2507,6 +2583,13 @@ packages:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
/bops@1.0.1:
|
||||||
|
resolution: {integrity: sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag==}
|
||||||
|
dependencies:
|
||||||
|
base64-js: 1.0.2
|
||||||
|
to-utf8: 0.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/brace-expansion@1.1.11:
|
/brace-expansion@1.1.11:
|
||||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2589,6 +2672,24 @@ packages:
|
||||||
unique-filename: 3.0.0
|
unique-filename: 3.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/cacheable-lookup@5.0.4:
|
||||||
|
resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
|
||||||
|
engines: {node: '>=10.6.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/cacheable-request@7.0.4:
|
||||||
|
resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dependencies:
|
||||||
|
clone-response: 1.0.3
|
||||||
|
get-stream: 5.2.0
|
||||||
|
http-cache-semantics: 4.1.1
|
||||||
|
keyv: 4.5.4
|
||||||
|
lowercase-keys: 2.0.0
|
||||||
|
normalize-url: 6.1.0
|
||||||
|
responselike: 2.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/call-bind@1.0.5:
|
/call-bind@1.0.5:
|
||||||
resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
|
resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2716,6 +2817,12 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/clone-response@1.0.3:
|
||||||
|
resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
|
||||||
|
dependencies:
|
||||||
|
mimic-response: 1.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/clone@1.0.4:
|
/clone@1.0.4:
|
||||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
@ -2851,6 +2958,10 @@ packages:
|
||||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/csv42@5.0.0:
|
||||||
|
resolution: {integrity: sha512-CUniGKBgHkEkpcPJYC41r8b5PJO1J80W2QmrSeuVDWkiH+bt3wcz16odu62DT/9V6AbfwnCojf1QcPOH2ibfhQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/culori@3.3.0:
|
/culori@3.3.0:
|
||||||
resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==}
|
resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
@ -2989,6 +3100,11 @@ packages:
|
||||||
clone: 1.0.4
|
clone: 1.0.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/defer-to-connect@2.0.1:
|
||||||
|
resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/define-data-property@1.1.1:
|
/define-data-property@1.1.1:
|
||||||
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
|
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -4265,6 +4381,13 @@ packages:
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/get-stream@5.2.0:
|
||||||
|
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dependencies:
|
||||||
|
pump: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/get-stream@6.0.1:
|
/get-stream@6.0.1:
|
||||||
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -4384,6 +4507,23 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic: 1.2.2
|
get-intrinsic: 1.2.2
|
||||||
|
|
||||||
|
/got@11.8.6:
|
||||||
|
resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
|
||||||
|
engines: {node: '>=10.19.0'}
|
||||||
|
dependencies:
|
||||||
|
'@sindresorhus/is': 4.6.0
|
||||||
|
'@szmarczak/http-timer': 4.0.6
|
||||||
|
'@types/cacheable-request': 6.0.3
|
||||||
|
'@types/responselike': 1.0.3
|
||||||
|
cacheable-lookup: 5.0.4
|
||||||
|
cacheable-request: 7.0.4
|
||||||
|
decompress-response: 6.0.0
|
||||||
|
http2-wrapper: 1.0.3
|
||||||
|
lowercase-keys: 2.0.0
|
||||||
|
p-cancelable: 2.1.1
|
||||||
|
responselike: 2.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/graceful-fs@4.2.11:
|
/graceful-fs@4.2.11:
|
||||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -4487,6 +4627,10 @@ packages:
|
||||||
lru-cache: 7.18.3
|
lru-cache: 7.18.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/http-cache-semantics@4.1.1:
|
||||||
|
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/http-errors@2.0.0:
|
/http-errors@2.0.0:
|
||||||
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
@ -4497,6 +4641,14 @@ packages:
|
||||||
statuses: 2.0.1
|
statuses: 2.0.1
|
||||||
toidentifier: 1.0.1
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
|
/http2-wrapper@1.0.3:
|
||||||
|
resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
|
||||||
|
engines: {node: '>=10.19.0'}
|
||||||
|
dependencies:
|
||||||
|
quick-lru: 5.1.1
|
||||||
|
resolve-alpn: 1.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/human-signals@2.1.0:
|
/human-signals@2.1.0:
|
||||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||||
engines: {node: '>=10.17.0'}
|
engines: {node: '>=10.17.0'}
|
||||||
|
@ -4885,7 +5037,6 @@ packages:
|
||||||
|
|
||||||
/json-buffer@3.0.1:
|
/json-buffer@3.0.1:
|
||||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/json-diff@0.9.0:
|
/json-diff@0.9.0:
|
||||||
resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==}
|
resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==}
|
||||||
|
@ -4948,7 +5099,6 @@ packages:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.1
|
json-buffer: 3.0.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/kleur@4.1.5:
|
/kleur@4.1.5:
|
||||||
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
||||||
|
@ -5066,6 +5216,11 @@ packages:
|
||||||
tslib: 2.4.1
|
tslib: 2.4.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/lowercase-keys@2.0.0:
|
||||||
|
resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/lru-cache@10.0.3:
|
/lru-cache@10.0.3:
|
||||||
resolution: {integrity: sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==}
|
resolution: {integrity: sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==}
|
||||||
engines: {node: 14 || >=16.14}
|
engines: {node: 14 || >=16.14}
|
||||||
|
@ -5596,6 +5751,11 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mimic-response@1.0.1:
|
||||||
|
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/mimic-response@3.1.0:
|
/mimic-response@3.1.0:
|
||||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -5855,6 +6015,11 @@ packages:
|
||||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
/normalize-url@6.1.0:
|
||||||
|
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/npm-install-checks@6.3.0:
|
/npm-install-checks@6.3.0:
|
||||||
resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==}
|
resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==}
|
||||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||||
|
@ -6032,6 +6197,11 @@ packages:
|
||||||
resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==}
|
resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/p-cancelable@2.1.1:
|
||||||
|
resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/p-limit@3.1.0:
|
/p-limit@3.1.0:
|
||||||
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -6458,6 +6628,11 @@ packages:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/quick-lru@5.1.1:
|
||||||
|
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/range-parser@1.2.1:
|
/range-parser@1.2.1:
|
||||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
@ -6692,6 +6867,10 @@ packages:
|
||||||
engines: {node: '>=0.10.5'}
|
engines: {node: '>=0.10.5'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/resolve-alpn@1.2.1:
|
||||||
|
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/resolve-from@4.0.0:
|
/resolve-from@4.0.0:
|
||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -6724,6 +6903,12 @@ packages:
|
||||||
supports-preserve-symlinks-flag: 1.0.0
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/responselike@2.0.1:
|
||||||
|
resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
|
||||||
|
dependencies:
|
||||||
|
lowercase-keys: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/restore-cursor@3.1.0:
|
/restore-cursor@3.1.0:
|
||||||
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
|
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -7317,6 +7502,10 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
|
|
||||||
|
/to-utf8@0.0.1:
|
||||||
|
resolution: {integrity: sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/toidentifier@1.0.1:
|
/toidentifier@1.0.1:
|
||||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/** @type {import('@remix-run/dev').AppConfig} */
|
/** @type {import('@remix-run/dev').AppConfig} */
|
||||||
export default {
|
export default {
|
||||||
ignoredRouteFiles: ["**/.*"],
|
ignoredRouteFiles: ["**/.*"],
|
||||||
|
serverDependenciesToBundle: [/^ably\/react/],
|
||||||
// appDirectory: "app",
|
// appDirectory: "app",
|
||||||
// assetsBuildDirectory: "public/build",
|
// assetsBuildDirectory: "public/build",
|
||||||
// publicPath: "/build/",
|
// publicPath: "/build/",
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"target": "ES2022",
|
"target": "ESNext",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
|
Loading…
Add table
Reference in a new issue