mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-02-09 02:10:18 +01:00
fixed problems for depployment
This commit is contained in:
@@ -1,22 +1,18 @@
|
||||
services:
|
||||
front:
|
||||
build: ./traque-front
|
||||
restart: always
|
||||
|
||||
reverse_proxy:
|
||||
build: ./proxy
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NEXT_PUBLIC_SOCKET_HOST = 'quentinrsl.com'
|
||||
- NEXT_PUBLIC_SOCKET_PORT = 3001
|
||||
- "3000:443"
|
||||
volumes:
|
||||
- ./traque-back/ssl:/etc/nginx/ssl:ro
|
||||
restart: always
|
||||
|
||||
back:
|
||||
build: ./traque-back
|
||||
ports:
|
||||
- "3001:3001"
|
||||
environment:
|
||||
- HOST = 'quentinrsl.com'
|
||||
- PORT = 3001
|
||||
- SSL_KEY = "/etc/letsencrypt/live/quentinrsl.com/privkey.pem"
|
||||
- SSL_CERT = "/etc/letsencrypt/live/quentinrsl.com/cert.pem"
|
||||
- ADMIN_PASSWORD = 'admin'
|
||||
- MAX_PENALTIES = 3
|
||||
- ALLOWED_TIME_OUT_OF_ZONE_IN_MINUTES = 10
|
||||
- ALLOWED_TIME_BETWEEN_POSITION_UPDATE_IN_MINUTES = 10
|
||||
restart: always
|
||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "traque",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
8
proxy/Dockerfile
Normal file
8
proxy/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
# nginx/Dockerfile
|
||||
|
||||
FROM nginx:1.23.3-alpine
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
42
proxy/nginx.conf
Normal file
42
proxy/nginx.conf
Normal file
@@ -0,0 +1,42 @@
|
||||
# nginx/nginx.conf
|
||||
|
||||
events {
|
||||
}
|
||||
|
||||
http {
|
||||
upstream front {
|
||||
server front:3000;
|
||||
}
|
||||
server {
|
||||
# Redirect HTTP requests to HTTPS.
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /srv/public;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
|
||||
server_name localhost;
|
||||
root /srv/public;
|
||||
server_tokens off;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ @front;
|
||||
}
|
||||
|
||||
location @front {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header X-Forwarded-Ssl on;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_pass http://front;
|
||||
proxy_cookie_path / "/; HTTPOnly; Secure";
|
||||
}
|
||||
}
|
||||
}
|
||||
10
readme.md
10
readme.md
@@ -4,7 +4,7 @@
|
||||
Edit the .env file in traque-front and add specify the following values:
|
||||
```
|
||||
NEXT_PUBLIC_SOCKET_HOST = 'example.com'
|
||||
NEXT_PUBLIC_SOCKET_PORT = 3000
|
||||
NEXT_PUBLIC_SOCKET_PORT = 3001
|
||||
```
|
||||
Where NEXT_PUBLIC_SOCKET_HOST is the host of the socket server and NEXT_PUBLIC_SOCKET_PORT is the port of the socket server.
|
||||
### Back end configuration
|
||||
@@ -25,6 +25,8 @@ MAX_PENALTIES is the maximum number of penalties a user can have before loosing
|
||||
ALLOWED_TIME_OUT_OF_ZONE_IN_MINUTES is the time a user can be out of the zone before being penalized.
|
||||
ALLOWED_TIME_BETWEEN_POSITION_UPDATE_IN_MINUTES is the maximum amount of time a user can wait before updating their position, after this period they will recieve a pennalty.
|
||||
|
||||
Note : make sure PORT and NEXT_PUBLIC_SOCKET_PORT are the same
|
||||
|
||||
### Running the project
|
||||
#### Front end
|
||||
To run the front end, navigate to the traque-front directory and run the following commands:
|
||||
@@ -43,5 +45,9 @@ Then navigate to the host and port specified in the .env file to access the appl
|
||||
https://example.com:3000
|
||||
```
|
||||
|
||||
## Depployment
|
||||
## Deployment
|
||||
|
||||
### SSL certificates
|
||||
Put your certificate and private key in the traque-back/ssl folder. They need to be named `cert.pem` and `privkey.pem`.
|
||||
You can then depploy the docker application with `docker compose up`
|
||||
|
||||
|
||||
4
traque-back/.gitignore
vendored
4
traque-back/.gitignore
vendored
@@ -1,8 +1,6 @@
|
||||
uploads/*
|
||||
#https dev certificates
|
||||
csr.pem
|
||||
key.pem
|
||||
server.crt
|
||||
*.pem
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
@@ -122,6 +122,7 @@ export function initAdminSocketHandler() {
|
||||
}
|
||||
if (game.reorderTeams(newOrder)) {
|
||||
secureAdminBroadcast("teams", game.teams);
|
||||
game.teams.forEach(t => sendUpdatedTeamInformations(t.id))
|
||||
} else {
|
||||
socket.emit("error", "Error reordering teams");
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export default class Game {
|
||||
}
|
||||
//The game has started
|
||||
if (newState == GameState.PLAYING) {
|
||||
penaltyController.start();
|
||||
if (!this.zone.ready()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ function onUpdateZone(zone) {
|
||||
|
||||
export const game = new Game(onUpdateZone, onUpdateNewZone);
|
||||
export const penaltyController = new PenaltyController();
|
||||
penaltyController.init()
|
||||
|
||||
|
||||
initAdminSocketHandler();
|
||||
|
||||
@@ -14,7 +14,7 @@ export class PenaltyController {
|
||||
this.checkIntervalId = null;
|
||||
}
|
||||
|
||||
init() {
|
||||
start() {
|
||||
this.outOfBoundsSince = {};
|
||||
if(this.checkIntervalId) {
|
||||
clearInterval(this.checkIntervalId)
|
||||
@@ -62,6 +62,7 @@ export class PenaltyController {
|
||||
}
|
||||
|
||||
watchZone() {
|
||||
console.log("watching zone")
|
||||
this.game.teams.forEach((team) => {
|
||||
if (team.captured) { return }
|
||||
//All the informations are not ready yet
|
||||
@@ -69,9 +70,11 @@ export class PenaltyController {
|
||||
return;
|
||||
}
|
||||
if (!isInCircle({lat: team.currentLocation[0], lng: team.currentLocation[1]}, this.game.zone.currentZone.center, this.game.zone.currentZone.radius)) {
|
||||
console.log("tema " + team.name + " out of zone")
|
||||
//The team was not previously out of the zone
|
||||
if (!this.outOfBoundsSince[team.id]) {
|
||||
this.outOfBoundsSince[team.id] = new Date();
|
||||
console.log("tema " + team.name + " warned")
|
||||
teamBroadcast(team.id, "warning", `You left the zone, you have ${process.env.ALLOWED_TIME_OUT_OF_ZONE_IN_MINUTES} minutes to get back in the marked area.`)
|
||||
} else {
|
||||
if (new Date() - this.outOfBoundsSince[team.id] > process.env.ALLOWED_TIME_OUT_OF_ZONE_IN_MINUTES * 60 * 1000) {
|
||||
|
||||
67
traque-front/Dockerfile
Normal file
67
traque-front/Dockerfile
Normal file
@@ -0,0 +1,67 @@
|
||||
FROM node:18-alpine AS base
|
||||
|
||||
# Install dependencies only when needed
|
||||
FROM base AS deps
|
||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies based on the preferred package manager
|
||||
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
|
||||
RUN \
|
||||
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
||||
elif [ -f package-lock.json ]; then npm ci; \
|
||||
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
|
||||
else echo "Lockfile not found." && exit 1; \
|
||||
fi
|
||||
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Next.js collects completely anonymous telemetry data about general usage.
|
||||
# Learn more here: https://nextjs.org/telemetry
|
||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||
# ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN \
|
||||
if [ -f yarn.lock ]; then yarn run build; \
|
||||
elif [ -f package-lock.json ]; then npm run build; \
|
||||
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
|
||||
else echo "Lockfile not found." && exit 1; \
|
||||
fi
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV production
|
||||
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||
# ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# Set the correct permission for prerender cache
|
||||
RUN mkdir .next
|
||||
RUN chown nextjs:nodejs .next
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT 3000
|
||||
|
||||
# server.js is created by next build from the standalone output
|
||||
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
|
||||
CMD HOSTNAME="0.0.0.0" node server.js
|
||||
@@ -4,6 +4,7 @@ import BlueButton, { GreenButton, RedButton } from "../util/button";
|
||||
import TextInput from "../util/textInput";
|
||||
import { useTeamConnexion } from "@/context/teamConnexionContext";
|
||||
import { EnemyTeamModal } from "./enemyTeamModal";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function ActionDrawer() {
|
||||
const [visible, setVisible] = useState(false);
|
||||
@@ -29,10 +30,10 @@ export default function ActionDrawer() {
|
||||
|
||||
return (
|
||||
<div className={"fixed w-screen bottom-0 z-10 bg-gray-100 flex justify-center rounded-t-2xl transition-all duration-200 flex flex-col " + (visible ? "h-full" : "h-20")}>
|
||||
<img src="/icons/arrow_up.png" className={"w-full object-scale-down h-ful max-h-20 transition-all cursor-pointer duration-200 " + (visible && "rotate-180")} onClick={() => setVisible(!visible)} />
|
||||
<Image src="/icons/arrow_up.png" className={"w-full object-scale-down h-ful max-h-20 transition-all cursor-pointer duration-200 " + (visible && "rotate-180")} onClick={() => setVisible(!visible)} />
|
||||
{visible && <div className="flex justify-between flex-col w-full h-full">
|
||||
<div className="flex flex-row justify-around">
|
||||
<img src="/icons/logout.png" onClick={logout} className='p-3 mx-2 w-14 h-14 bg-red-500 rounded-lg cursor-pointer bg-red z-20' />
|
||||
<Image src="/icons/logout.png" onClick={logout} className='p-3 mx-2 w-14 h-14 bg-red-500 rounded-lg cursor-pointer bg-red z-20' />
|
||||
</div>
|
||||
<div className='shadow-2xl bg-white p-1 flex flex-col text-center mb-1 mx-auto w-4/5 rounded'>
|
||||
<div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import useGame from "@/hook/useGame";
|
||||
import { RedButton } from "../util/button";
|
||||
import { useEffect, useRef } from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
export function EnemyTeamModal({ visible, onClose }) {
|
||||
const { teamId, enemyName } = useGame();
|
||||
@@ -22,7 +23,7 @@ export function EnemyTeamModal({ visible, onClose }) {
|
||||
<div className='fixed w-screen h-screen bg-black bg-opacity-50 z-10 text-center'></div>
|
||||
<div className='fixed w-11/12 h-5/6 p-5 z-20 mx-auto inset-x-0 my-auto inset-y-0 flex flex-col justify-center rounded-xl transition-all shadow-xl bg-white '>
|
||||
<h1 className="w-full text-center text-3xl mb-5">{enemyName}</h1>
|
||||
<img ref={imageRef} src={SERVER_URL + "/photo/enemy?team=" + teamId.toString()} className='w-full h-full object-contain' />
|
||||
<Image ref={imageRef} src={SERVER_URL + "/photo/enemy?team=" + teamId.toString()} className='w-full h-full object-contain' />
|
||||
<div className="h-20">
|
||||
<RedButton onClick={onClose}>Close</RedButton>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +71,7 @@ export function LiveMap({ ...props }) {
|
||||
shadowSize: [41, 41]
|
||||
})}>
|
||||
<Popup>
|
||||
Position de l'ennemi
|
||||
Position de l&aposennemi
|
||||
</Popup>
|
||||
</Marker>}
|
||||
<MapPan center={currentPosition} />
|
||||
|
||||
@@ -41,7 +41,7 @@ export function Notification({socket }) {
|
||||
return (
|
||||
Object.keys(bgColorMap).map((key) =>
|
||||
notification?.type == key &&
|
||||
<div className={classNames + bgColorMap[key]} onClick={() => setVisible(false)}>
|
||||
<div key={key} className={classNames + bgColorMap[key]} onClick={() => setVisible(false)}>
|
||||
<p className='text-center text-xl'>{notification?.text}</p>
|
||||
</div>
|
||||
));
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useTeamConnexion } from "@/context/teamConnexionContext";
|
||||
import useGame from "@/hook/useGame"
|
||||
import Image from "next/image";
|
||||
|
||||
export default function PlacementOverlay() {
|
||||
const { name, ready } = useGame();
|
||||
const {logout} = useTeamConnexion();
|
||||
return (
|
||||
<>
|
||||
<img src="/icons/logout.png" onClick={logout} className='w-12 h-12 bg-red-500 p-2 top-1 right-1 rounded-lg cursor-pointer bg-red fixed z-20' />
|
||||
<Image src="/icons/logout.png" onClick={logout} className='w-12 h-12 bg-red-500 p-2 top-1 right-1 rounded-lg cursor-pointer bg-red fixed z-20' />
|
||||
<div className='fixed top-0 p-3 w-full bg-gray-300 shadow-xl rounded-b-xl flex flex-col z-10 justify-center items-center'>
|
||||
<div className='text-2xl my-3'>Placement</div>
|
||||
<div className='text-md'>{name}</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import useGame from "@/hook/useGame"
|
||||
import { GreenButton, LogoutButton } from "../util/button";
|
||||
import { useRef } from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
export function WaitingScreen() {
|
||||
const { name, teamId } = useGame();
|
||||
@@ -35,13 +36,13 @@ export function WaitingScreen() {
|
||||
Jeu en préparation, veuillez patienter...
|
||||
</div>
|
||||
<div className='text-2xl text-center my-10'>
|
||||
<p>Uploadez une photo où tous les membres de l'équipe sont visibles</p>
|
||||
<p>Uploadez une photo où tous les membres de l&aposéquipe sont visibles</p>
|
||||
<input type="file" name="file" accept="image/*" className=" my-5 block w-full text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"/>
|
||||
<div className="h-20">
|
||||
<GreenButton onClick={sendImage}>Envoyer</GreenButton>
|
||||
</div>
|
||||
</div>
|
||||
{teamId && <img ref={imageRef} src={SERVER_URL + "/photo/my?team=" + teamId.toString()} className='w-screen h-1/2 object-contain' />}
|
||||
{teamId && <Image ref={imageRef} src={SERVER_URL + "/photo/my?team=" + teamId.toString()} className='w-screen h-1/2 object-contain' />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useTeamConnexion } from "@/context/teamConnexionContext";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function BlueButton({ children, ...props }) {
|
||||
return (<button {...props} className="bg-blue-600 hover:bg-blue-500 text-lg ease-out duration-200 text-white w-full h-full p-4 shadow-sm rounded">
|
||||
@@ -20,5 +21,5 @@ export function GreenButton({ children, ...props }) {
|
||||
|
||||
export function LogoutButton() {
|
||||
const { logout } = useTeamConnexion();
|
||||
return <img src="/icons/logout.png" onClick={logout} className='w-12 h-12 bg-red-500 p-2 top-1 right-1 rounded-lg cursor-pointer bg-red fixed z-20' />
|
||||
return <Image src="/icons/logout.png" onClick={logout} className='w-12 h-12 bg-red-500 p-2 top-1 right-1 rounded-lg cursor-pointer bg-red fixed z-20' />
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
const nextConfig = {
|
||||
experimental: {
|
||||
outputStandalone: true
|
||||
}
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
182
traque-front/package-lock.json
generated
182
traque-front/package-lock.json
generated
@@ -46,9 +46,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz",
|
||||
"integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
|
||||
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@@ -130,54 +130,6 @@
|
||||
"react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@hello-pangea/dnd/node_modules/memoize-one": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
|
||||
},
|
||||
"node_modules/@hello-pangea/dnd/node_modules/react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
|
||||
},
|
||||
"node_modules/@hello-pangea/dnd/node_modules/react-redux": {
|
||||
"version": "8.1.3",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz",
|
||||
"integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.1",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/use-sync-external-store": "^0.0.3",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"react-is": "^18.0.0",
|
||||
"use-sync-external-store": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8 || ^17.0 || ^18.0",
|
||||
"@types/react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-native": ">=0.59",
|
||||
"redux": "^4 || ^5.0.0-beta.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
@@ -206,9 +158,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
@@ -508,15 +460,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/eslint-patch": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz",
|
||||
"integrity": "sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==",
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz",
|
||||
"integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.1.tgz",
|
||||
"integrity": "sha512-dzJtaDAAoXx4GCOJpbB2eG/Qj8VDpdwkLsWGzGm+0L7E8/434RyMbAHmk9ubXWVAb9nXmc44jUf8GKqVDiKezg=="
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.2",
|
||||
@@ -547,20 +499,14 @@
|
||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.2.69",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.69.tgz",
|
||||
"integrity": "sha512-W1HOMUWY/1Yyw0ba5TkCV+oqynRjG7BnteBB+B7JmAK7iw3l2SW+VGOxL+akPweix6jk2NNJtyJKpn4TkpfK3Q==",
|
||||
"version": "18.2.79",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz",
|
||||
"integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/scheduler": {
|
||||
"version": "0.16.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
|
||||
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A=="
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||
@@ -1165,9 +1111,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001600",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz",
|
||||
"integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==",
|
||||
"version": "1.0.30001612",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
|
||||
"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -1477,9 +1423,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.715",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz",
|
||||
"integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==",
|
||||
"version": "1.4.747",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz",
|
||||
"integrity": "sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
@@ -1522,9 +1468,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.23.2",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz",
|
||||
"integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==",
|
||||
"version": "1.23.3",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
|
||||
"integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"array-buffer-byte-length": "^1.0.1",
|
||||
@@ -1566,11 +1512,11 @@
|
||||
"safe-regex-test": "^1.0.3",
|
||||
"string.prototype.trim": "^1.2.9",
|
||||
"string.prototype.trimend": "^1.0.8",
|
||||
"string.prototype.trimstart": "^1.0.7",
|
||||
"string.prototype.trimstart": "^1.0.8",
|
||||
"typed-array-buffer": "^1.0.2",
|
||||
"typed-array-byte-length": "^1.0.1",
|
||||
"typed-array-byte-offset": "^1.0.2",
|
||||
"typed-array-length": "^1.0.5",
|
||||
"typed-array-length": "^1.0.6",
|
||||
"unbox-primitive": "^1.0.2",
|
||||
"which-typed-array": "^1.1.15"
|
||||
},
|
||||
@@ -2413,9 +2359,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -3241,6 +3187,11 @@
|
||||
"node": "14 || >=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/memoize-one": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -3664,12 +3615,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
|
||||
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
|
||||
"integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^9.1.1 || ^10.0.0",
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -3976,6 +3927,49 @@
|
||||
"react-dom": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "8.1.3",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz",
|
||||
"integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.1",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/use-sync-external-store": "^0.0.3",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"react-is": "^18.0.0",
|
||||
"use-sync-external-store": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8 || ^17.0 || ^18.0",
|
||||
"@types/react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-native": ">=0.59",
|
||||
"redux": "^4 || ^5.0.0-beta.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-redux/node_modules/react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
@@ -4611,9 +4605,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||
"integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
|
||||
"integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
@@ -4624,7 +4618,7 @@
|
||||
"fast-glob": "^3.3.0",
|
||||
"glob-parent": "^6.0.2",
|
||||
"is-glob": "^4.0.3",
|
||||
"jiti": "^1.19.1",
|
||||
"jiti": "^1.21.0",
|
||||
"lilconfig": "^2.1.0",
|
||||
"micromatch": "^4.0.5",
|
||||
"normalize-path": "^3.0.0",
|
||||
@@ -4833,9 +4827,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.4.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz",
|
||||
"integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
|
||||
Reference in New Issue
Block a user