mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-04-10 16:30:18 +02:00
Server heavy refactoring 3 (not functionnal)
This commit is contained in:
@@ -1,15 +1,11 @@
|
|||||||
services:
|
services:
|
||||||
proxy:
|
proxy:
|
||||||
build: ./proxy
|
build: ./proxy
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
|
|
||||||
front:
|
front:
|
||||||
build:
|
build:
|
||||||
context: ./traque-front
|
context: ./traque-front
|
||||||
dockerfile: Dockerfile.dev
|
target: dev
|
||||||
restart: always
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./traque-front:/app
|
- ./traque-front:/app
|
||||||
- /app/node_modules
|
- /app/node_modules
|
||||||
@@ -19,14 +15,7 @@ services:
|
|||||||
back:
|
back:
|
||||||
build:
|
build:
|
||||||
context: ./traque-back
|
context: ./traque-back
|
||||||
dockerfile: Dockerfile.dev
|
target: dev
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "3001:3001"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./traque-back:/app
|
- ./traque-back:/app
|
||||||
- /app/node_modules
|
- /app/node_modules
|
||||||
environment:
|
|
||||||
ADMIN_PASSWORD_HASH: '23e3c6886ff8fcba302deac05c46612ed3af99e40a2a14252810f540f3c186aa'
|
|
||||||
HOST: '0.0.0.0'
|
|
||||||
PORT: 3001
|
|
||||||
|
|||||||
11
server/docker-compose.prod.yaml
Normal file
11
server/docker-compose.prod.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
proxy:
|
||||||
|
image: git.rezel.net/ludotech/traque-proxy:latest
|
||||||
|
|
||||||
|
front:
|
||||||
|
image: git.rezel.net/ludotech/traque-front:latest
|
||||||
|
environment:
|
||||||
|
NEXT_PUBLIC_SOCKET_HOST: 'traque.rezel.net'
|
||||||
|
|
||||||
|
back:
|
||||||
|
image: git.rezel.net/ludotech/traque-back:latest
|
||||||
@@ -1,22 +1,25 @@
|
|||||||
services:
|
services:
|
||||||
proxy:
|
proxy:
|
||||||
image: git.rezel.net/ludotech/traque-proxy:latest
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
restart: always
|
networks:
|
||||||
|
- traque-net
|
||||||
|
|
||||||
front:
|
front:
|
||||||
image: git.rezel.net/ludotech/traque-front:latest
|
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
networks:
|
||||||
NEXT_PUBLIC_SOCKET_HOST: 'traque.rezel.net'
|
- traque-net
|
||||||
|
|
||||||
back:
|
back:
|
||||||
image: git.rezel.net/ludotech/traque-back:latest
|
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
|
||||||
- "3001:3001"
|
|
||||||
environment:
|
environment:
|
||||||
ADMIN_PASSWORD_HASH: '23e3c6886ff8fcba302deac05c46612ed3af99e40a2a14252810f540f3c186aa'
|
ADMIN_PASSWORD_HASH: '23e3c6886ff8fcba302deac05c46612ed3af99e40a2a14252810f540f3c186aa'
|
||||||
HOST: '0.0.0.0'
|
HOST: '0.0.0.0'
|
||||||
PORT: 3001
|
PORT: 3001
|
||||||
|
networks:
|
||||||
|
- traque-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traque-net:
|
||||||
|
driver: bridge
|
||||||
|
|||||||
6
server/package-lock.json
generated
Normal file
6
server/package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "server",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
||||||
1
server/package.json
Normal file
1
server/package.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
# nginx/Dockerfile
|
|
||||||
|
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# nginx/nginx.conf
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
}
|
}
|
||||||
@@ -14,15 +13,14 @@ http {
|
|||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /back/ {
|
location /back/ {
|
||||||
proxy_pass http://back:3001/;
|
proxy_pass http://back:3001/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "Upgrade";
|
proxy_set_header Connection "Upgrade";
|
||||||
proxy_set_header Host $host;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
Dockerfile
|
Dockerfile
|
||||||
.dockerignore
|
.dockerignore
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
|
||||||
README.md
|
|
||||||
.next
|
.next
|
||||||
.git
|
.git
|
||||||
.vscode
|
.vscode
|
||||||
|
.env
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
# Use Node 22 alpine as parent image
|
# Étape commune
|
||||||
FROM node:22-alpine
|
FROM node:22-slim AS base
|
||||||
|
|
||||||
# Change the working directory on the Docker image to /app
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
# Copy package.json and package-lock.json to the /app directory
|
# Étape développement
|
||||||
COPY package.json package-lock.json* ./
|
FROM base AS dev
|
||||||
|
ENV NODE_ENV=development
|
||||||
# Install dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Copy the rest of project files into this image
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Create those folders if they don't already exist
|
|
||||||
RUN if [ ! -d uploads ]; then mkdir uploads; fi
|
|
||||||
RUN if [ ! -d trajectories ]; then mkdir trajectories; fi
|
|
||||||
|
|
||||||
# Expose the port
|
|
||||||
EXPOSE 3001
|
EXPOSE 3001
|
||||||
|
CMD ["npm", "run", "dev"]
|
||||||
|
|
||||||
# Start the application
|
# Étape builder
|
||||||
CMD ["npm", "run", "start"]
|
FROM base AS builder
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build && npm prune --omit=dev
|
||||||
|
|
||||||
|
# Étape production
|
||||||
|
FROM node:22-slim AS prod
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
COPY --from=builder --chown=node:node /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder --chown=node:node /app/dist ./dist
|
||||||
|
COPY --from=builder --chown=node:node /app/package.json ./package.json
|
||||||
|
USER node
|
||||||
|
EXPOSE 3001
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
# Use Node 22 alpine as parent image
|
|
||||||
FROM node:22-alpine
|
|
||||||
|
|
||||||
# Change the working directory on the Docker image to /app
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Change specified variables
|
|
||||||
ENV NODE_ENV=development
|
|
||||||
|
|
||||||
# Copy package.json and package-lock.json to the /app directory
|
|
||||||
COPY package.json package-lock.json* ./
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Copy the rest of project files into this image
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Create those folders if they don't already exist
|
|
||||||
RUN if [ ! -d uploads ]; then mkdir uploads; fi
|
|
||||||
RUN if [ ! -d trajectories ]; then mkdir trajectories; fi
|
|
||||||
|
|
||||||
# Expose the port
|
|
||||||
EXPOSE 3001
|
|
||||||
|
|
||||||
# Start the server in dev mode
|
|
||||||
CMD ["npm", "run", "dev"]
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"#*": ["src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
|
|||||||
377
server/traque-back/package-lock.json
generated
377
server/traque-back/package-lock.json
generated
@@ -15,9 +15,6 @@
|
|||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"random-location": "^1.1.3",
|
"random-location": "^1.1.3",
|
||||||
"socket.io": "^4.7.5"
|
"socket.io": "^4.7.5"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"nodemon": "^3.1.10"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@socket.io/component-emitter": {
|
"node_modules/@socket.io/component-emitter": {
|
||||||
@@ -2131,20 +2128,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"normalize-path": "^3.0.0",
|
|
||||||
"picomatch": "^2.0.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/append-field": {
|
"node_modules/append-field": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||||
@@ -2165,16 +2148,6 @@
|
|||||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/balanced-match": {
|
|
||||||
"version": "4.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
|
||||||
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": "18 || 20 || >=22"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/base64id": {
|
"node_modules/base64id": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||||
@@ -2193,19 +2166,6 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/binary-extensions": {
|
|
||||||
"version": "2.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
|
||||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.20.4",
|
"version": "1.20.4",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
|
||||||
@@ -2230,32 +2190,6 @@
|
|||||||
"npm": "1.2.8000 || >= 1.4.16"
|
"npm": "1.2.8000 || >= 1.4.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
|
||||||
"version": "5.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
|
||||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^4.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "18 || 20 || >=22"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/braces": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"fill-range": "^7.1.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/buffer-from": {
|
"node_modules/buffer-from": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
@@ -2311,31 +2245,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chokidar": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://paulmillr.com/funding/"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "~2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
@@ -2673,19 +2582,6 @@
|
|||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
|
||||||
"version": "7.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
|
||||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"to-regex-range": "^5.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
||||||
@@ -2722,21 +2618,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fsevents": {
|
|
||||||
"version": "2.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
@@ -2825,19 +2706,6 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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,
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"is-glob": "^4.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/gopd": {
|
"node_modules/gopd": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
@@ -2850,16 +2718,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/has-flag": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
@@ -2916,13 +2774,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ignore-by-default": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/inherits": {
|
"node_modules/inherits": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
@@ -2938,52 +2789,6 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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,
|
|
||||||
"license": "MIT",
|
|
||||||
"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,
|
|
||||||
"license": "MIT",
|
|
||||||
"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,
|
|
||||||
"license": "MIT",
|
|
||||||
"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,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.12.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/isarray": {
|
"node_modules/isarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
@@ -3074,22 +2879,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
|
||||||
"version": "10.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
|
|
||||||
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "BlueOak-1.0.0",
|
|
||||||
"dependencies": {
|
|
||||||
"brace-expansion": "^5.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "18 || 20 || >=22"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.8",
|
"version": "1.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||||
@@ -3145,70 +2934,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nodemon": {
|
|
||||||
"version": "3.1.14",
|
|
||||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz",
|
|
||||||
"integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"chokidar": "^3.5.2",
|
|
||||||
"debug": "^4",
|
|
||||||
"ignore-by-default": "^1.0.1",
|
|
||||||
"minimatch": "^10.2.1",
|
|
||||||
"pstree.remy": "^1.1.8",
|
|
||||||
"semver": "^7.5.3",
|
|
||||||
"simple-update-notifier": "^2.0.0",
|
|
||||||
"supports-color": "^5.5.0",
|
|
||||||
"touch": "^3.1.0",
|
|
||||||
"undefsafe": "^2.0.5"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"nodemon": "bin/nodemon.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/nodemon"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/nodemon/node_modules/debug": {
|
|
||||||
"version": "4.4.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
|
||||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "^2.1.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"supports-color": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/nodemon/node_modules/ms": {
|
|
||||||
"version": "2.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"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,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/object-assign": {
|
"node_modules/object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
@@ -3257,19 +2982,6 @@
|
|||||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/point-in-polygon": {
|
"node_modules/point-in-polygon": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz",
|
||||||
@@ -3320,13 +3032,6 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pstree.remy": {
|
|
||||||
"version": "1.1.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
|
||||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.14.2",
|
"version": "6.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||||
@@ -3408,19 +3113,6 @@
|
|||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/readdirp": {
|
|
||||||
"version": "3.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
|
||||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"picomatch": "^2.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/robust-predicates": {
|
"node_modules/robust-predicates": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz",
|
||||||
@@ -3453,19 +3145,6 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
|
||||||
"version": "7.7.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
|
||||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"bin": {
|
|
||||||
"semver": "bin/semver.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/send": {
|
"node_modules/send": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
|
||||||
@@ -3589,19 +3268,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/simple-update-notifier": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"semver": "^7.5.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/skmeans": {
|
"node_modules/skmeans": {
|
||||||
"version": "0.9.7",
|
"version": "0.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz",
|
"resolved": "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz",
|
||||||
@@ -3756,19 +3422,6 @@
|
|||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/supports-color": {
|
|
||||||
"version": "5.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
|
||||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"has-flag": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sweepline-intersections": {
|
"node_modules/sweepline-intersections": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/sweepline-intersections/-/sweepline-intersections-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/sweepline-intersections/-/sweepline-intersections-1.5.0.tgz",
|
||||||
@@ -3784,19 +3437,6 @@
|
|||||||
"integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==",
|
"integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"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,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"is-number": "^7.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/toidentifier": {
|
"node_modules/toidentifier": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
@@ -3832,16 +3472,6 @@
|
|||||||
"geo2topo": "bin/geo2topo"
|
"geo2topo": "bin/geo2topo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/touch": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"bin": {
|
|
||||||
"nodetouch": "bin/nodetouch.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
@@ -3867,13 +3497,6 @@
|
|||||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/undefsafe": {
|
|
||||||
"version": "2.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
|
||||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "7.18.2",
|
"version": "7.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "traque-back",
|
"name": "traque-back",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"private": true,
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
|
||||||
"start": "node src/index.js",
|
"start": "node src/index.js",
|
||||||
"dev": "nodemon src/index.js"
|
"dev": "node --watch src/index.js"
|
||||||
|
},
|
||||||
|
"imports": {
|
||||||
|
"#*": "./src/*"
|
||||||
},
|
},
|
||||||
"author": "Quentin Roussel",
|
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -18,8 +19,5 @@
|
|||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"random-location": "^1.1.3",
|
"random-location": "^1.1.3",
|
||||||
"socket.io": "^4.7.5"
|
"socket.io": "^4.7.5"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"nodemon": "^3.1.10"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DEFAULT_ZONES_SETTINGS } from "@/config/zone.js";
|
import { DEFAULT_ZONES_SETTINGS } from "#config/zone.js";
|
||||||
import { DefaultState, PlacementState, PlayingState, FinishedState } from '@/core/states/game/index.js';
|
import { DefaultState, PlacementState, PlayingState, FinishedState } from '#core/states/game/index.js';
|
||||||
|
|
||||||
export const STATE_SETTINGS = {
|
export const STATE_SETTINGS = {
|
||||||
ENTRY_STATE_CLASS: DefaultState,
|
ENTRY_STATE_CLASS: DefaultState,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as turf from '@turf/turf';
|
import * as turf from '@turf/turf';
|
||||||
import { ZoneWithDuration } from '@/core/models/zone.js';
|
import { ZoneWithDuration } from '#core/models/zone.js';
|
||||||
import { TURF_BUFFER_SIZE, TURF_CIRCLE_STEPS, TURF_DISTANCE_UNIT, ZONE_TYPES } from '@/config/zone.js';
|
import { TURF_BUFFER_SIZE, TURF_CIRCLE_STEPS, TURF_DISTANCE_UNIT, ZONE_TYPES } from '#config/zone.js';
|
||||||
|
|
||||||
export const settingsToZoneList = (settings) => {
|
export const settingsToZoneList = (settings) => {
|
||||||
if (!settings) return [];
|
if (!settings) return [];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as turf from '@turf/turf';
|
import * as turf from '@turf/turf';
|
||||||
import { Zone } from '@/core/models/zone.js';
|
import { Zone } from '#core/models/zone.js';
|
||||||
import { TURF_CIRCLE_STEPS, TURF_DISTANCE_UNIT } from '@/config/zone.js';
|
import { TURF_CIRCLE_STEPS, TURF_DISTANCE_UNIT } from '#config/zone.js';
|
||||||
|
|
||||||
export const settingsToZone = (settings) => {
|
export const settingsToZone = (settings) => {
|
||||||
if (!settings) return null;
|
if (!settings) return null;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { ZoneManager } from "@/core/managers/zone_manager.js";
|
import { ZoneManager } from "#core/managers/zone_manager.js";
|
||||||
import { TeamManager } from '@/core/managers/team_manager.js';
|
import { TeamManager } from '#core/managers/team_manager.js';
|
||||||
import { GAME_MANAGER_EVENTS } from "@/config/events.js";
|
import { GAME_MANAGER_EVENTS } from "#config/events.js";
|
||||||
|
|
||||||
|
|
||||||
export class GameManager extends EventEmitter {
|
export class GameManager extends EventEmitter {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Team } from "@/core/models/team.js";
|
import { Team } from "#core/models/team.js";
|
||||||
|
|
||||||
export class TeamManager {
|
export class TeamManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -36,7 +36,7 @@ export class TeamManager {
|
|||||||
const team = new Team(id, teamName);
|
const team = new Team(id, teamName);
|
||||||
if (!this.has(id)) this.order.push(id);
|
if (!this.has(id)) this.order.push(id);
|
||||||
this._map.set(id, team);
|
this._map.set(id, team);
|
||||||
return id;
|
return team;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(id) {
|
delete(id) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Scheduler } from "@/util/scheduler.js";
|
import { Scheduler } from "#util/scheduler.js";
|
||||||
import { settingsToZoneList } from "@/core/factories/game_zone_factory.js";
|
import { settingsToZoneList } from "#core/factories/game_zone_factory.js";
|
||||||
|
|
||||||
export class ZoneManager {
|
export class ZoneManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CAPTURE_CODE_LENGTH, TEAM_ID_LENGTH } from "@/config/game.js";
|
import { CAPTURE_CODE_LENGTH, TEAM_ID_LENGTH } from "#config/game.js";
|
||||||
import { randint } from "@/util/random.js";
|
import { randint } from "#util/random.js";
|
||||||
|
|
||||||
export class Team {
|
export class Team {
|
||||||
constructor(id, teamName) {
|
constructor(id, teamName) {
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { DefaultTeam } from "@/core/states/teams/default_team.js";
|
import { DefaultTeam } from "#core/states/teams/default_team.js";
|
||||||
|
|
||||||
export class DefaultState {
|
export class DefaultState {
|
||||||
|
static name = "default";
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
return this.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(teams, zoneManager) {
|
constructor(teams, zoneManager) {
|
||||||
this.teams = teams;
|
this.teams = teams;
|
||||||
this.zoneManager = zoneManager;
|
this.zoneManager = zoneManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
|
||||||
return "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --------------- LIFE CYCLE --------------- //
|
// --------------- LIFE CYCLE --------------- //
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { FinishedTeam } from "@/core/states/teams/finished_team.js";
|
import { FinishedTeam } from "#core/states/teams/finished_team.js";
|
||||||
|
|
||||||
export class FinishedState {
|
export class FinishedState {
|
||||||
|
static name = "finished";
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
return this.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(teams, zoneManager) {
|
constructor(teams, zoneManager) {
|
||||||
this.teams = teams;
|
this.teams = teams;
|
||||||
this.zoneManager = zoneManager;
|
this.zoneManager = zoneManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
|
||||||
return "finished";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --------------- LIFE CYCLE --------------- //
|
// --------------- LIFE CYCLE --------------- //
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { DefaultState } from '@/core/states/game/default_state.js';
|
export { DefaultState } from '#core/states/game/default_state.js';
|
||||||
export { PlacementState } from '@/core/states/game/placement_state.js';
|
export { PlacementState } from '#core/states/game/placement_state.js';
|
||||||
export { PlayingState } from '@/core/states/game/playing_state.js';
|
export { PlayingState } from '#core/states/game/playing_state.js';
|
||||||
export { FinishedState } from '@/core/states/game/finished_state.js';
|
export { FinishedState } from '#core/states/game/finished_state.js';
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { PlacementTeam } from "@/core/states/teams/placement_team.js";
|
import { PlacementTeam } from "#core/states/teams/placement_team.js";
|
||||||
|
|
||||||
export class PlacementState {
|
export class PlacementState {
|
||||||
|
static name = "placement";
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
return this.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(teams, zoneManager) {
|
constructor(teams, zoneManager) {
|
||||||
this.teams = teams;
|
this.teams = teams;
|
||||||
this.zoneManager = zoneManager;
|
this.zoneManager = zoneManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
|
||||||
return "placement";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --------------- LIFE CYCLE --------------- //
|
// --------------- LIFE CYCLE --------------- //
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { PlayingTeam } from "@/core/states/teams/playing_team.js";
|
import { PlayingTeam } from "#core/states/teams/playing_team.js";
|
||||||
|
|
||||||
export class PlayingState {
|
export class PlayingState {
|
||||||
|
static name = "playing";
|
||||||
|
|
||||||
|
get name () {
|
||||||
|
return this.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(teams, zoneManager) {
|
constructor(teams, zoneManager) {
|
||||||
this.teams = teams;
|
this.teams = teams;
|
||||||
this.zoneManager = zoneManager;
|
this.zoneManager = zoneManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
|
||||||
return "playing";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --------------- LIFE CYCLE --------------- //
|
// --------------- LIFE CYCLE --------------- //
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { settingsToZone } from "@/core/factories/placement_zone_factory.js";
|
import { settingsToZone } from "#core/factories/placement_zone_factory.js";
|
||||||
|
|
||||||
export class PlacementTeam {
|
export class PlacementTeam {
|
||||||
constructor(team) {
|
constructor(team) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Team } from "@/core/models/team.js";
|
import { Team } from "#core/models/team.js";
|
||||||
import { ScheduledTask } from "@/util/scheduler.js";
|
import { ScheduledTask } from "#util/scheduler.js";
|
||||||
import { RESTART_TIMERS } from "@/config/game.js";
|
import { RESTART_TIMERS } from "#config/game.js";
|
||||||
|
|
||||||
export class PlayingTeam {
|
export class PlayingTeam {
|
||||||
constructor(team, zoneManager) {
|
constructor(team, zoneManager) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
import { ADMIN_PASSWORD_HASH } from "@/config/server.js";
|
import { ADMIN_PASSWORD_HASH } from "#config/server.js";
|
||||||
import { ADMIN_HANDLER_EVENTS } from "@/config/events.js";
|
import { ADMIN_HANDLER_EVENTS } from "#config/events.js";
|
||||||
|
|
||||||
export class AdminHandler {
|
export class AdminHandler {
|
||||||
constructor(gameManager) {
|
constructor(gameManager) {
|
||||||
@@ -29,7 +29,7 @@ class AdminConnection {
|
|||||||
if (this._isLoggedIn) return;
|
if (this._isLoggedIn) return;
|
||||||
|
|
||||||
const hash = createHash('sha256').update(password).digest('hex');
|
const hash = createHash('sha256').update(password).digest('hex');
|
||||||
if (hash !== ADMIN_PASSWORD_HASH) return false;
|
if (false && hash !== ADMIN_PASSWORD_HASH) return false; // TODO : temporaire
|
||||||
|
|
||||||
this._isLoggedIn = true;
|
this._isLoggedIn = true;
|
||||||
this._gameManager.onAdminLogin(this._socket.id);
|
this._gameManager.onAdminLogin(this._socket.id);
|
||||||
@@ -49,9 +49,8 @@ class AdminConnection {
|
|||||||
this._logout()
|
this._logout()
|
||||||
});
|
});
|
||||||
|
|
||||||
this._socket.on(ADMIN_HANDLER_EVENTS.LOGIN, (password, callback) => {
|
this._socket.on(ADMIN_HANDLER_EVENTS.LOGIN, (password) => {
|
||||||
this._login(password);
|
this._login(password);
|
||||||
callback(this._isLoggedIn);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this._socket.on(ADMIN_HANDLER_EVENTS.LOGOUT, () => {
|
this._socket.on(ADMIN_HANDLER_EVENTS.LOGOUT, () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PLAYER_HANDLER_EVENTS } from "@/config/events.js";
|
import { PLAYER_HANDLER_EVENTS } from "#config/events.js";
|
||||||
|
|
||||||
export class PlayerHandler {
|
export class PlayerHandler {
|
||||||
constructor(gameManager) {
|
constructor(gameManager) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DefaultState, PlacementState, PlayingState, FinishedState } from "@/core/states/game/index.js";
|
import { DefaultState, PlacementState, PlayingState, FinishedState } from "#core/states/game/index.js";
|
||||||
|
|
||||||
const TEAM_STATE_MAP = {
|
const TEAM_STATE_MAP = {
|
||||||
[DefaultState.name]: (_team, _gameState) => ({}),
|
[DefaultState.name]: (_team, _gameState) => ({}),
|
||||||
@@ -55,9 +55,8 @@ export class AdminMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stateName: stateName,
|
gameState: stateName,
|
||||||
teams: teamsDto,
|
teams: this.gameManager.teams.order.map(teamId => teamsDto[teamId]),
|
||||||
teamsOrder: this.gameManager.teams.order,
|
|
||||||
zones: zonesDto,
|
zones: zonesDto,
|
||||||
settings: this.gameManager.settings
|
settings: this.gameManager.settings
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DefaultState, PlacementState, PlayingState, FinishedState } from "@/core/states/game/index.js";
|
import { DefaultState, PlacementState, PlayingState, FinishedState } from "#core/states/game/index.js";
|
||||||
|
|
||||||
const TEAM_STATE_MAP = {
|
const TEAM_STATE_MAP = {
|
||||||
[DefaultState.name]: (_team, _gameState) => ({}),
|
[DefaultState.name]: (_team, _gameState) => ({}),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { AdminMapper } from "@/externals/mappers/admin_mapper.js";
|
import { AdminMapper } from "#externals/mappers/admin_mapper.js";
|
||||||
import { StateTracker } from "@/util/state_tracker.js";
|
import { StateTracker } from "#util/state_tracker.js";
|
||||||
import { GAME_MANAGER_EVENTS, ADMIN_SYNCHRONIZER_EVENTS } from "@/config/events.js";
|
import { GAME_MANAGER_EVENTS, ADMIN_SYNCHRONIZER_EVENTS } from "#config/events.js";
|
||||||
|
|
||||||
export class AdminSynchronizer {
|
export class AdminSynchronizer {
|
||||||
constructor(gameManager) {
|
constructor(gameManager) {
|
||||||
@@ -11,11 +11,16 @@ export class AdminSynchronizer {
|
|||||||
init(io) {
|
init(io) {
|
||||||
this.gameManager.on(GAME_MANAGER_EVENTS.INIT_ADMIN, (socketId) => {
|
this.gameManager.on(GAME_MANAGER_EVENTS.INIT_ADMIN, (socketId) => {
|
||||||
const { dto } = this.gameStateTracker.getSyncDto();
|
const { dto } = this.gameStateTracker.getSyncDto();
|
||||||
|
console.log("INIT ADMIN");
|
||||||
|
console.log(dto);
|
||||||
io.to(socketId).emit(ADMIN_SYNCHRONIZER_EVENTS.UPDATE_FULL, dto);
|
io.to(socketId).emit(ADMIN_SYNCHRONIZER_EVENTS.UPDATE_FULL, dto);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gameManager.on(GAME_MANAGER_EVENTS.UPDATE_GAME, () => {
|
this.gameManager.on(GAME_MANAGER_EVENTS.UPDATE_GAME, () => {
|
||||||
const { dto, hasChanged } = this.gameStateTracker.getSyncDto();
|
const { dto, hasChanged } = this.gameStateTracker.getSyncDto();
|
||||||
|
console.log("UPDATE ADMIN");
|
||||||
|
console.log(hasChanged);
|
||||||
|
console.log(dto);
|
||||||
if (hasChanged) io.emit(ADMIN_SYNCHRONIZER_EVENTS.UPDATE_FULL, dto);
|
if (hasChanged) io.emit(ADMIN_SYNCHRONIZER_EVENTS.UPDATE_FULL, dto);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { GAME_MANAGER_EVENTS, PLAYER_SYNCHRONIZER_EVENTS } from "@/config/events.js";
|
import { GAME_MANAGER_EVENTS, PLAYER_SYNCHRONIZER_EVENTS } from "#config/events.js";
|
||||||
import { PlayerMapper } from "@/externals/mappers/player_mapper.js";
|
import { PlayerMapper } from "#externals/mappers/player_mapper.js";
|
||||||
import { StateTracker } from "@/util/state_tracker.js";
|
import { StateTracker } from "#util/state_tracker.js";
|
||||||
|
|
||||||
export class PlayerSynchronizer {
|
export class PlayerSynchronizer {
|
||||||
constructor(gameManager) {
|
constructor(gameManager) {
|
||||||
|
|||||||
@@ -2,16 +2,16 @@ import { createServer } from "http";
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import { Server } from "socket.io";
|
import { Server } from "socket.io";
|
||||||
// Core
|
// Core
|
||||||
import { GameManager } from "@/core/managers/game_manager.js";
|
import { GameManager } from "#core/managers/game_manager.js";
|
||||||
// Externals
|
// Externals
|
||||||
import { PhotoService } from "@/externals/api/photo.js";
|
import { PhotoService } from "#externals/api/photo.js";
|
||||||
import { PlayerSynchronizer } from "@/externals/synchronizers/player_synchronizer.js";
|
import { PlayerSynchronizer } from "#externals/synchronizers/player_synchronizer.js";
|
||||||
import { PlayerHandler } from "@/externals/handlers/playerHandler.js";
|
import { PlayerHandler } from "#externals/handlers/playerHandler.js";
|
||||||
import { AdminSynchronizer } from "@/externals/synchronizers/admin_synchronizer.js";
|
import { AdminSynchronizer } from "#externals/synchronizers/admin_synchronizer.js";
|
||||||
import { AdminHandler } from "@/externals/handlers/adminHandler.js";
|
import { AdminHandler } from "#externals/handlers/adminHandler.js";
|
||||||
// Config
|
// Config
|
||||||
import { PORT, HOST } from "@/config/server.js";
|
import { PORT, HOST } from "#config/server.js";
|
||||||
import { DEFAULT_GAME_SETTINGS, STATE_SETTINGS } from "@/config/game.js";
|
import { DEFAULT_GAME_SETTINGS, STATE_SETTINGS } from "#config/game.js";
|
||||||
|
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
@@ -21,7 +21,6 @@ const io = new Server(httpServer, {
|
|||||||
cors: { origin: "*", methods: ["GET", "POST"] }
|
cors: { origin: "*", methods: ["GET", "POST"] }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
const gameManager = new GameManager(STATE_SETTINGS, DEFAULT_GAME_SETTINGS);
|
const gameManager = new GameManager(STATE_SETTINGS, DEFAULT_GAME_SETTINGS);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
Dockerfile
|
Dockerfile
|
||||||
.dockerignore
|
.dockerignore
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
|
||||||
README.md
|
|
||||||
.next
|
.next
|
||||||
.git
|
.git
|
||||||
.vscode
|
.vscode
|
||||||
|
.env
|
||||||
|
|||||||
@@ -1,18 +1,31 @@
|
|||||||
# Use Node 22 alpine as parent image
|
# Étape commune
|
||||||
FROM node:22-alpine AS base
|
FROM node:22-slim AS base
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
RUN apk add --no-cache libc6-compat
|
# Étape développement
|
||||||
|
FROM base AS dev
|
||||||
COPY package.json package-lock.json* ./
|
ENV NODE_ENV=development
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
ENV NODE_ENV development
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED 1
|
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD ["npm", "run", "dev"]
|
CMD ["npm", "run", "dev"]
|
||||||
|
|
||||||
|
# Étape builder
|
||||||
|
FROM base AS builder
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Étape production
|
||||||
|
FROM node:22-slim AS prod
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
COPY --from=builder --chown=node:node /app/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=node:node /app/.next/static ./.next/static
|
||||||
|
COPY --from=builder --chown=node:node /app/public ./public
|
||||||
|
USER node
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["node", "server.js"]
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
# Use Node 22 alpine as parent image
|
|
||||||
FROM node:22-alpine
|
|
||||||
|
|
||||||
# Change the working directory on the Docker image to /app
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Installs glibc compatibility on Alpine to support native Node.js modules that require glibc
|
|
||||||
RUN apk add --no-cache libc6-compat
|
|
||||||
|
|
||||||
# Change specified variables
|
|
||||||
ENV NODE_ENV=development
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
|
||||||
|
|
||||||
# Copy package.json and package-lock.json to the /app directory
|
|
||||||
COPY package.json package-lock.json* ./
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Copy the rest of project files into this image
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Expose the port
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Start the server in dev mode
|
|
||||||
CMD ["npm", "run", "dev"]
|
|
||||||
@@ -2,18 +2,18 @@ import { Fragment, useEffect, useState } from "react";
|
|||||||
import { Arrow, CircleZone, PolygonZone, Position, Tag } from "@/components/layer";
|
import { Arrow, CircleZone, PolygonZone, Position, Tag } from "@/components/layer";
|
||||||
import { CustomMapContainer, MapEventListener, MapPan } from "@/components/map";
|
import { CustomMapContainer, MapEventListener, MapPan } from "@/components/map";
|
||||||
import useAdmin from "@/hook/useAdmin";
|
import useAdmin from "@/hook/useAdmin";
|
||||||
import { GameState, ZoneTypes } from "@/util/types";
|
import { GameState } from "@/util/types";
|
||||||
import { mapZooms } from "@/util/configurations";
|
import { mapZooms } from "@/util/configurations";
|
||||||
|
|
||||||
export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsFocusing, mapStyle, showZones, showNames, showArrows }) {
|
export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsFocusing, mapStyle, showZones, showNames, showArrows }) {
|
||||||
const { zoneType, zoneExtremities, teams, nextZoneDate, getTeam, gameState } = useAdmin();
|
const { zones, teams, getTeam, gameState } = useAdmin();
|
||||||
const [timeLeftNextZone, setTimeLeftNextZone] = useState(null);
|
const [timeLeftNextZone, setTimeLeftNextZone] = useState(null);
|
||||||
const [isFullScreen, setIsFullScreen] = useState(false);
|
const [isFullScreen, setIsFullScreen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (nextZoneDate) {
|
if (zones?.zoneTransitionDate) {
|
||||||
const updateTime = () => {
|
const updateTime = () => {
|
||||||
setTimeLeftNextZone(Math.max(0, Math.floor((nextZoneDate - Date.now()) / 1000)));
|
setTimeLeftNextZone(Math.max(0, Math.floor((zones.zoneTransitionDate - Date.now()) / 1000)));
|
||||||
};
|
};
|
||||||
|
|
||||||
updateTime();
|
updateTime();
|
||||||
@@ -21,7 +21,7 @@ export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsF
|
|||||||
|
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}
|
}
|
||||||
}, [nextZoneDate]);
|
}, [zones?.zoneTransitionDate]);
|
||||||
|
|
||||||
function formatTime(time) {
|
function formatTime(time) {
|
||||||
// time is in seconds
|
// time is in seconds
|
||||||
@@ -34,20 +34,10 @@ export default function LiveMap({ selectedTeamId, onSelected, isFocusing, setIsF
|
|||||||
function Zones() {
|
function Zones() {
|
||||||
if (!(showZones && gameState == GameState.PLAYING)) return null;
|
if (!(showZones && gameState == GameState.PLAYING)) return null;
|
||||||
|
|
||||||
switch (zoneType) {
|
return (<>
|
||||||
case ZoneTypes.CIRCLE:
|
<PolygonZone polygon={zones.currentZone} color={mapStyle.currentZoneColor} />
|
||||||
return (<>
|
<PolygonZone polygon={zones.nextZone} color={mapStyle.nextZoneColor} />
|
||||||
<CircleZone circle={zoneExtremities.begin} color={mapStyle.currentZoneColor} />
|
</>);
|
||||||
<CircleZone circle={zoneExtremities.end} color={mapStyle.nextZoneColor} />
|
|
||||||
</>);
|
|
||||||
case ZoneTypes.POLYGON:
|
|
||||||
return (<>
|
|
||||||
<PolygonZone polygon={zoneExtremities.begin?.polygon} color={mapStyle.currentZoneColor} />
|
|
||||||
<PolygonZone polygon={zoneExtremities.end?.polygon} color={mapStyle.nextZoneColor} />
|
|
||||||
</>);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function IconValue({ color, icon, value }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function TeamSidePanel({ selectedTeamId, onClose }) {
|
export default function TeamSidePanel({ selectedTeamId, onClose }) {
|
||||||
const { getTeam, startDate, gameState } = useAdmin();
|
const { getTeam, gameState } = useAdmin();
|
||||||
const [imgSrc, setImgSrc] = useState("");
|
const [imgSrc, setImgSrc] = useState("");
|
||||||
const [_, setRefreshKey] = useState(0);
|
const [_, setRefreshKey] = useState(0);
|
||||||
const team = getTeam(selectedTeamId);
|
const team = getTeam(selectedTeamId);
|
||||||
@@ -106,11 +106,11 @@ export default function TeamSidePanel({ selectedTeamId, onClose }) {
|
|||||||
<DotLine label="Chassé par" value={getTeam(team.chased)?.name ?? NO_VALUE} />
|
<DotLine label="Chassé par" value={getTeam(team.chased)?.name ?? NO_VALUE} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{ (gameState == GameState.PLAYING || gameState == GameState.FINISHED) &&
|
{ (gameState == GameState.PLAYING || gameState == GameState.FINISHED) && false &&
|
||||||
<div>
|
<div>
|
||||||
<DotLine label="Distance" value={formatDistance(team.distance)} />
|
<DotLine label="Distance" value={formatDistance(team.distance)} />
|
||||||
<DotLine label="Temps de survie" value={formatTime(startDate, team.finishDate || Date.now())} />
|
<DotLine label="Temps de survie" value={formatTime(0, team.finishDate || Date.now())} />
|
||||||
<DotLine label="Vitesse moyenne" value={formatSpeed(team.distance, startDate, team.finishDate || Date.now())} />
|
<DotLine label="Vitesse moyenne" value={formatSpeed(team.distance, 0, team.finishDate || Date.now())} />
|
||||||
<DotLine label="Captures" value={team.nCaptures ?? NO_VALUE} />
|
<DotLine label="Captures" value={team.nCaptures ?? NO_VALUE} />
|
||||||
<DotLine label="Observations" value={team.nSentLocation ?? NO_VALUE} />
|
<DotLine label="Observations" value={team.nSentLocation ?? NO_VALUE} />
|
||||||
<DotLine label="Observé" value={team.nObserved ?? NO_VALUE} />
|
<DotLine label="Observé" value={team.nObserved ?? NO_VALUE} />
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ function Drawings({ minZone, setMinZone, maxZone, setMaxZone, editMode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function CircleZoneSelector({ display }) {
|
export default function CircleZoneSelector({ display }) {
|
||||||
const {zoneSettings, outOfZoneDelay, updateSettings} = useAdmin();
|
const {settings, updateSettings} = useAdmin();
|
||||||
const [localZoneSettings, setLocalZoneSettings, applyLocalZoneSettings] = useLocalVariable(zoneSettings, (e) => updateSettings({zone: e}));
|
const [localZoneSettings, setLocalZoneSettings, applyLocalZoneSettings] = useLocalVariable(settings.playingZones, (e) => updateSettings({playingZones: e}));
|
||||||
const [localOutOfZoneDelay, setLocalOutOfZoneDelay, applyLocalOutOfZoneDelay] = useLocalVariable(outOfZoneDelay, (e) => updateSettings({outOfZoneDelay: e}));
|
const [localOutOfZoneDelay, setLocalOutOfZoneDelay, applyLocalOutOfZoneDelay] = useLocalVariable(settings.outOfZoneDelay, (e) => updateSettings({outOfZoneDelay: e}));
|
||||||
const [editMode, setEditMode] = useState(EditMode.MAX);
|
const [editMode, setEditMode] = useState(EditMode.MAX);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,30 +1,8 @@
|
|||||||
import { Section } from "@/components/section";
|
import { Section } from "@/components/section";
|
||||||
import useAdmin from "@/hook/useAdmin";
|
|
||||||
import useLocalVariable from "@/hook/useLocalVariable";
|
|
||||||
|
|
||||||
function MessageInput({title, ...props}) {
|
|
||||||
return (
|
|
||||||
<div className="w-full flex flex-row gap-3 items-center">
|
|
||||||
<p>{title}</p>
|
|
||||||
<input className="w-full p-1 rounded ring-1 ring-inset ring-gray-400 placeholder:text-gray-600" {...props} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Messages() {
|
export default function Messages() {
|
||||||
const {messages, updateSettings} = useAdmin();
|
|
||||||
const [localGameSettings, setLocalGameSettings, applyLocalGameSettings] = useLocalVariable(messages, (e) => updateSettings({messages: e}));
|
|
||||||
|
|
||||||
function modifyLocalZoneSettings(key, value) {
|
|
||||||
setLocalGameSettings(prev => ({...prev, [key]: value}));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section title="Messages" innerClassName="w-full h-full flex flex-col gap-3 items-center">
|
<Section title="Messages" innerClassName="w-full h-full flex flex-col gap-3 items-center">
|
||||||
<MessageInput id="waiting" title="Attente :" value={localGameSettings?.waiting ?? ""} onChange={(e) => modifyLocalZoneSettings("waiting", e.target.value)} onBlur={applyLocalGameSettings}/>
|
|
||||||
<MessageInput id="captured" title="Capture :" value={localGameSettings?.captured ?? ""} onChange={(e) => modifyLocalZoneSettings("captured", e.target.value)} onBlur={applyLocalGameSettings}/>
|
|
||||||
<MessageInput id="winner" title="Victoire :" value={localGameSettings?.winner ?? ""} onChange={(e) => modifyLocalZoneSettings("winner", e.target.value)} onBlur={applyLocalGameSettings}/>
|
|
||||||
<MessageInput id="loser" title="Défaite :" value={localGameSettings?.loser ?? ""} onChange={(e) => modifyLocalZoneSettings("loser", e.target.value)} onBlur={applyLocalGameSettings}/>
|
|
||||||
</Section>
|
</Section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,19 +19,17 @@ function ZoneTypeButton({title, onClick, isSelected}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PlayingZoneSelector({ display }) {
|
export default function PlayingZoneSelector({ display }) {
|
||||||
const { zoneType } = useAdmin();
|
|
||||||
const [localZoneType, setLocalZoneType] = useLocalVariable(zoneType, () => {});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={display ? 'w-full h-full gap-3 flex flex-col' : "hidden"}>
|
<div className={display ? 'w-full h-full gap-3 flex flex-col' : "hidden"}>
|
||||||
<div className="w-full flex flex-row gap-3 items-center">
|
<div className="w-full flex flex-row gap-3 items-center">
|
||||||
<p className="text-l">Type de zone :</p>
|
<p className="text-l">Type de zone :</p>
|
||||||
<ZoneTypeButton title="Cercles" onClick={() => setLocalZoneType(ZoneTypes.CIRCLE)} isSelected={localZoneType == ZoneTypes.CIRCLE} />
|
<ZoneTypeButton title="Cercles" onClick={() => setLocalZoneType(ZoneTypes.CIRCLE)} isSelected={ZoneTypes.POLYGON == ZoneTypes.CIRCLE} />
|
||||||
<ZoneTypeButton title="Polygones" onClick={() => setLocalZoneType(ZoneTypes.POLYGON)} isSelected={localZoneType == ZoneTypes.POLYGON} />
|
<ZoneTypeButton title="Polygones" onClick={() => setLocalZoneType(ZoneTypes.POLYGON)} isSelected={ZoneTypes.POLYGON == ZoneTypes.POLYGON} />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex-1">
|
<div className="w-full flex-1">
|
||||||
<CircleZoneSelector display={localZoneType == ZoneTypes.CIRCLE} />
|
<CircleZoneSelector display={ZoneTypes.POLYGON == ZoneTypes.CIRCLE} />
|
||||||
<PolygonZoneSelector display={localZoneType == ZoneTypes.POLYGON} />
|
<PolygonZoneSelector display={ZoneTypes.POLYGON == ZoneTypes.POLYGON} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ function Drawings({ localZoneSettings, addZone, removeZone }) {
|
|||||||
|
|
||||||
export default function PolygonZoneSelector({ display }) {
|
export default function PolygonZoneSelector({ display }) {
|
||||||
const defaultDuration = 10;
|
const defaultDuration = 10;
|
||||||
const {zoneSettings, outOfZoneDelay, updateSettings} = useAdmin();
|
const {settings, updateSettings} = useAdmin();
|
||||||
const [localZoneSettings, setLocalZoneSettings, applyLocalZoneSettings] = useLocalVariable(zoneSettings, (e) => updateSettings({zone: e}));
|
const [localZoneSettings, setLocalZoneSettings, applyLocalZoneSettings] = useLocalVariable(settings.zones, (e) => updateSettings({zone: e}));
|
||||||
const [localOutOfZoneDelay, setLocalOutOfZoneDelay, applyLocalOutOfZoneDelay] = useLocalVariable(outOfZoneDelay, (e) => updateSettings({outOfZoneDelay: e}));
|
const [localOutOfZoneDelay, setLocalOutOfZoneDelay, applyLocalOutOfZoneDelay] = useLocalVariable(settings.outOfZoneDelay, (e) => updateSettings({outOfZoneDelay: e}));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!localZoneSettings || localZoneSettings.type != ZoneTypes.POLYGON) {
|
if (!localZoneSettings || localZoneSettings.type != ZoneTypes.POLYGON) {
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ function TeamManagerItem({ team }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function TeamManager() {
|
export default function TeamManager() {
|
||||||
const { teams, addTeam, reorderTeams, sendPositionDelay, updateSettings } = useAdmin();
|
const { teams, addTeam, reorderTeams, settings, updateSettings } = useAdmin();
|
||||||
const [teamName, setTeamName] = useState('');
|
const [teamName, setTeamName] = useState('');
|
||||||
const [localSendPositionDelay, setLocalSendPositionDelay, applyLocalSendPositionDelay] = useLocalVariable(sendPositionDelay, (e) => updateSettings({sendPositionDelay: e}));
|
const [localSendPositionDelay, setLocalSendPositionDelay, applyLocalSendPositionDelay] = useLocalVariable(settings.scanDelay, (e) => updateSettings({scanDelay: e}));
|
||||||
|
|
||||||
function handleTeamSubmit(e) {
|
function handleTeamSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -8,44 +8,21 @@ const adminContext = createContext();
|
|||||||
|
|
||||||
export function AdminProvider({ children }) {
|
export function AdminProvider({ children }) {
|
||||||
const { adminSocket } = useSocket();
|
const { adminSocket } = useSocket();
|
||||||
// teams
|
|
||||||
const [teams, setTeams] = useState([]);
|
|
||||||
// game_state
|
|
||||||
const [gameState, setGameState] = useState(GameState.SETUP);
|
const [gameState, setGameState] = useState(GameState.SETUP);
|
||||||
const [startDate, setStartDate] = useState(null);
|
const [teams, setTeams] = useState([]);
|
||||||
// current_zone
|
const [zones, setZones] = useState(null);
|
||||||
const [zoneType, setZoneType] = useState(null);
|
const [settings, setSettings] = useState(null);
|
||||||
const [zoneExtremities, setZoneExtremities] = useState(null);
|
|
||||||
const [nextZoneDate, setNextZoneDate] = useState(null);
|
|
||||||
// settings
|
|
||||||
const [messages, setMessages] = useState(null);
|
|
||||||
const [zoneSettings, setZoneSettings] = useState(null)
|
|
||||||
const [sendPositionDelay, setSendPositionDelay] = useState(null);
|
|
||||||
const [outOfZoneDelay, setOutOfZoneDelay] = useState(null);
|
|
||||||
|
|
||||||
useSocketListener(adminSocket, "teams", setTeams);
|
useSocketListener(adminSocket, "update-full", ({ gameState, teams, zones, settings }) => {
|
||||||
|
setGameState(gameState);
|
||||||
useSocketListener(adminSocket, "game_state", (data) => {
|
setTeams(teams);
|
||||||
setGameState(data.state);
|
setZones(zones);
|
||||||
setStartDate(data.date);
|
setSettings(settings);
|
||||||
});
|
|
||||||
|
|
||||||
useSocketListener(adminSocket, "current_zone", (data) => {
|
|
||||||
setZoneExtremities({begin: data.begin, end: data.end});
|
|
||||||
setNextZoneDate(data.endDate);
|
|
||||||
});
|
|
||||||
|
|
||||||
useSocketListener(adminSocket, "settings", (data) => {
|
|
||||||
setMessages(data.messages);
|
|
||||||
setZoneSettings(data.zone);
|
|
||||||
setZoneType(data.zone.type);
|
|
||||||
setSendPositionDelay(data.sendPositionDelay);
|
|
||||||
setOutOfZoneDelay(data.outOfZoneDelay);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const value = useMemo(() => (
|
const value = useMemo(() => (
|
||||||
{ zoneSettings, teams, gameState, zoneType, zoneExtremities, sendPositionDelay, outOfZoneDelay, messages, nextZoneDate, startDate }
|
{ gameState, teams, zones, settings }
|
||||||
), [zoneSettings, teams, gameState, zoneType, zoneExtremities, sendPositionDelay, outOfZoneDelay, messages, nextZoneDate, startDate]);
|
), [gameState, teams, zones, settings]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<adminContext.Provider value={value}>
|
<adminContext.Provider value={value}>
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ export default function useAdmin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addTeam(teamName) {
|
function addTeam(teamName) {
|
||||||
adminSocket.emit("add_team", teamName);
|
adminSocket.emit("add-team", teamName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeTeam(teamId) {
|
function removeTeam(teamId) {
|
||||||
adminSocket.emit("remove_team", teamId);
|
adminSocket.emit("remove-team", teamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reorderTeams(newOrder) {
|
function reorderTeams(newOrder) {
|
||||||
adminSocket.emit("reorder_teams", newOrder);
|
adminSocket.emit("reorder-teams", newOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
function captureTeam(teamId) {
|
function captureTeam(teamId) {
|
||||||
@@ -32,11 +32,11 @@ export default function useAdmin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function changeState(state) {
|
function changeState(state) {
|
||||||
adminSocket.emit("change_state", state);
|
adminSocket.emit("state", state);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSettings(settings) {
|
function updateSettings(settings) {
|
||||||
adminSocket.emit("update_settings", settings);
|
adminSocket.emit("settings", settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...adminContext, getTeam, reorderTeams, addTeam, removeTeam, captureTeam, placementTeam, changeState, updateSettings };
|
return { ...adminContext, getTeam, reorderTeams, addTeam, removeTeam, captureTeam, placementTeam, changeState, updateSettings };
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
|
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
output: 'standalone',
|
||||||
|
|
||||||
output: 'standalone',
|
async redirects() {
|
||||||
|
return [
|
||||||
async redirects() {
|
{
|
||||||
return [
|
source: '/',
|
||||||
{
|
destination: '/admin',
|
||||||
source: '/',
|
permanent: false,
|
||||||
destination: '/admin',
|
},
|
||||||
permanent: false, // The browser will not save the redirect in its cache
|
]
|
||||||
},
|
},
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
6351
server/traque-front/package-lock.json
generated
Normal file
6351
server/traque-front/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@
|
|||||||
"name": "traque-front",
|
"name": "traque-front",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Quentin Roussel",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const Colors = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const GameState = {
|
export const GameState = {
|
||||||
SETUP: "setup",
|
SETUP: "default",
|
||||||
PLACEMENT: "placement",
|
PLACEMENT: "placement",
|
||||||
PLAYING: "playing",
|
PLAYING: "playing",
|
||||||
FINISHED: "finished"
|
FINISHED: "finished"
|
||||||
|
|||||||
Reference in New Issue
Block a user