Spaces:
Running
Running
Persist
Browse files- .dockerignore +7 -0
- .gitignore +1 -0
- Dockerfile +15 -0
- README.md +16 -3
- data/.gitkeep +0 -0
- package-lock.json +725 -188
- package.json +9 -0
- server/index.js +204 -0
- src/App.css +10 -0
- src/App.js +88 -33
- src/App.test.js +12 -2
- src/utils/storage.js +36 -10
.dockerignore
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
node_modules
|
| 2 |
+
build
|
| 3 |
+
.git
|
| 4 |
+
.gitignore
|
| 5 |
+
npm-debug.log*
|
| 6 |
+
yarn-debug.log*
|
| 7 |
+
yarn-error.log*
|
.gitignore
CHANGED
|
@@ -10,6 +10,7 @@
|
|
| 10 |
|
| 11 |
# production
|
| 12 |
/build
|
|
|
|
| 13 |
|
| 14 |
# misc
|
| 15 |
.DS_Store
|
|
|
|
| 10 |
|
| 11 |
# production
|
| 12 |
/build
|
| 13 |
+
/data/sessions.json
|
| 14 |
|
| 15 |
# misc
|
| 16 |
.DS_Store
|
Dockerfile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM node:20-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
COPY package.json package-lock.json ./
|
| 6 |
+
RUN npm ci
|
| 7 |
+
|
| 8 |
+
COPY . .
|
| 9 |
+
RUN npm run build
|
| 10 |
+
|
| 11 |
+
ENV NODE_ENV=production
|
| 12 |
+
ENV PORT=7860
|
| 13 |
+
EXPOSE 7860
|
| 14 |
+
|
| 15 |
+
CMD ["node", "server/index.js"]
|
README.md
CHANGED
|
@@ -3,14 +3,27 @@ title: Climbing Dashboard
|
|
| 3 |
emoji: 🐠
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: red
|
| 6 |
-
sdk:
|
| 7 |
pinned: false
|
| 8 |
-
app_build_command: npm run build
|
| 9 |
-
app_file: build/index.html
|
| 10 |
---
|
| 11 |
|
| 12 |
# Getting Started with Create React App
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
| 15 |
|
| 16 |
## Available Scripts
|
|
|
|
| 3 |
emoji: 🐠
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: red
|
| 6 |
+
sdk: docker
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
# Getting Started with Create React App
|
| 11 |
|
| 12 |
+
## Shared Storage Setup
|
| 13 |
+
|
| 14 |
+
The dashboard now uses a backend API. By default it writes sessions to `data/sessions.json` locally. If you set Hugging Face dataset credentials, it stores the same `sessions.json` in a dataset repo instead.
|
| 15 |
+
|
| 16 |
+
- Run frontend + backend in development:
|
| 17 |
+
- `npm run dev`
|
| 18 |
+
- Run backend only:
|
| 19 |
+
- `npm run server`
|
| 20 |
+
- Use a dataset repo for persistent storage:
|
| 21 |
+
- set `HF_TOKEN`
|
| 22 |
+
- set `HF_DATASET_REPO` to something like `your-name/climbing-dashboard-data`
|
| 23 |
+
- optional: set `HF_DATASET_FILE` if you want a path other than `sessions.json`
|
| 24 |
+
|
| 25 |
+
Without `HF_TOKEN` and `HF_DATASET_REPO`, the app falls back to the local file in `data/sessions.json`.
|
| 26 |
+
|
| 27 |
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
| 28 |
|
| 29 |
## Available Scripts
|
data/.gitkeep
ADDED
|
File without changes
|
package-lock.json
CHANGED
|
@@ -8,15 +8,21 @@
|
|
| 8 |
"name": "react-template",
|
| 9 |
"version": "0.1.0",
|
| 10 |
"dependencies": {
|
|
|
|
| 11 |
"@testing-library/dom": "^10.4.0",
|
| 12 |
"@testing-library/jest-dom": "^6.6.3",
|
| 13 |
"@testing-library/react": "^16.3.0",
|
| 14 |
"@testing-library/user-event": "^13.5.0",
|
|
|
|
|
|
|
| 15 |
"react": "^19.1.0",
|
| 16 |
"react-dom": "^19.1.0",
|
| 17 |
"react-scripts": "5.0.1",
|
| 18 |
"recharts": "^3.7.0",
|
| 19 |
"web-vitals": "^2.1.4"
|
|
|
|
|
|
|
|
|
|
| 20 |
}
|
| 21 |
},
|
| 22 |
"node_modules/@adobe/css-tools": {
|
|
@@ -2457,6 +2463,30 @@
|
|
| 2457 |
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
| 2458 |
}
|
| 2459 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2460 |
"node_modules/@humanwhocodes/config-array": {
|
| 2461 |
"version": "0.13.0",
|
| 2462 |
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
|
@@ -2938,6 +2968,22 @@
|
|
| 2938 |
"node": ">= 8"
|
| 2939 |
}
|
| 2940 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2941 |
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
|
| 2942 |
"version": "0.5.17",
|
| 2943 |
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.17.tgz",
|
|
@@ -5249,56 +5295,45 @@
|
|
| 5249 |
"license": "MIT"
|
| 5250 |
},
|
| 5251 |
"node_modules/body-parser": {
|
| 5252 |
-
"version": "
|
| 5253 |
-
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-
|
| 5254 |
-
"integrity": "sha512-
|
| 5255 |
"license": "MIT",
|
| 5256 |
"dependencies": {
|
| 5257 |
-
"bytes": "
|
| 5258 |
-
"content-type": "
|
| 5259 |
-
"debug": "
|
| 5260 |
-
"
|
| 5261 |
-
"
|
| 5262 |
-
"
|
| 5263 |
-
"
|
| 5264 |
-
"
|
| 5265 |
-
"
|
| 5266 |
-
"raw-body": "~2.5.3",
|
| 5267 |
-
"type-is": "~1.6.18",
|
| 5268 |
-
"unpipe": "~1.0.0"
|
| 5269 |
},
|
| 5270 |
"engines": {
|
| 5271 |
-
"node": ">=
|
| 5272 |
-
|
| 5273 |
-
|
| 5274 |
-
|
| 5275 |
-
|
| 5276 |
-
"version": "2.6.9",
|
| 5277 |
-
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
| 5278 |
-
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
| 5279 |
-
"license": "MIT",
|
| 5280 |
-
"dependencies": {
|
| 5281 |
-
"ms": "2.0.0"
|
| 5282 |
}
|
| 5283 |
},
|
| 5284 |
"node_modules/body-parser/node_modules/iconv-lite": {
|
| 5285 |
-
"version": "0.
|
| 5286 |
-
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.
|
| 5287 |
-
"integrity": "sha512-
|
| 5288 |
"license": "MIT",
|
| 5289 |
"dependencies": {
|
| 5290 |
-
"safer-buffer": ">= 2.1.2 < 3"
|
| 5291 |
},
|
| 5292 |
"engines": {
|
| 5293 |
"node": ">=0.10.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5294 |
}
|
| 5295 |
},
|
| 5296 |
-
"node_modules/body-parser/node_modules/ms": {
|
| 5297 |
-
"version": "2.0.0",
|
| 5298 |
-
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
| 5299 |
-
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
| 5300 |
-
"license": "MIT"
|
| 5301 |
-
},
|
| 5302 |
"node_modules/bonjour-service": {
|
| 5303 |
"version": "1.3.0",
|
| 5304 |
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz",
|
|
@@ -5673,6 +5708,19 @@
|
|
| 5673 |
"node": ">=0.10.0"
|
| 5674 |
}
|
| 5675 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5676 |
"node_modules/cliui": {
|
| 5677 |
"version": "7.0.4",
|
| 5678 |
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
|
@@ -5911,6 +5959,86 @@
|
|
| 5911 |
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
| 5912 |
"license": "MIT"
|
| 5913 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5914 |
"node_modules/confusing-browser-globals": {
|
| 5915 |
"version": "1.0.11",
|
| 5916 |
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
|
|
@@ -5927,15 +6055,16 @@
|
|
| 5927 |
}
|
| 5928 |
},
|
| 5929 |
"node_modules/content-disposition": {
|
| 5930 |
-
"version": "0.
|
| 5931 |
-
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.
|
| 5932 |
-
"integrity": "sha512-
|
| 5933 |
"license": "MIT",
|
| 5934 |
-
"dependencies": {
|
| 5935 |
-
"safe-buffer": "5.2.1"
|
| 5936 |
-
},
|
| 5937 |
"engines": {
|
| 5938 |
-
"node": ">=
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5939 |
}
|
| 5940 |
},
|
| 5941 |
"node_modules/content-type": {
|
|
@@ -5963,10 +6092,13 @@
|
|
| 5963 |
}
|
| 5964 |
},
|
| 5965 |
"node_modules/cookie-signature": {
|
| 5966 |
-
"version": "1.
|
| 5967 |
-
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.
|
| 5968 |
-
"integrity": "sha512-
|
| 5969 |
-
"license": "MIT"
|
|
|
|
|
|
|
|
|
|
| 5970 |
},
|
| 5971 |
"node_modules/core-js": {
|
| 5972 |
"version": "3.48.0",
|
|
@@ -8036,65 +8168,94 @@
|
|
| 8036 |
}
|
| 8037 |
},
|
| 8038 |
"node_modules/express": {
|
| 8039 |
-
"version": "
|
| 8040 |
-
"resolved": "https://registry.npmjs.org/express/-/express-
|
| 8041 |
-
"integrity": "sha512-
|
| 8042 |
-
"license": "MIT",
|
| 8043 |
-
"dependencies": {
|
| 8044 |
-
"accepts": "
|
| 8045 |
-
"
|
| 8046 |
-
"
|
| 8047 |
-
"content-
|
| 8048 |
-
"
|
| 8049 |
-
"cookie": "
|
| 8050 |
-
"
|
| 8051 |
-
"
|
| 8052 |
-
"
|
| 8053 |
-
"
|
| 8054 |
-
"
|
| 8055 |
-
"
|
| 8056 |
-
"
|
| 8057 |
-
"
|
| 8058 |
-
"
|
| 8059 |
-
"
|
| 8060 |
-
"
|
| 8061 |
-
"
|
| 8062 |
-
"parseurl": "
|
| 8063 |
-
"
|
| 8064 |
-
"
|
| 8065 |
-
"
|
| 8066 |
-
"
|
| 8067 |
-
"
|
| 8068 |
-
"
|
| 8069 |
-
"
|
| 8070 |
-
"
|
| 8071 |
-
"
|
| 8072 |
-
"type-is": "~1.6.18",
|
| 8073 |
-
"utils-merge": "1.0.1",
|
| 8074 |
-
"vary": "~1.1.2"
|
| 8075 |
},
|
| 8076 |
"engines": {
|
| 8077 |
-
"node": ">=
|
| 8078 |
},
|
| 8079 |
"funding": {
|
| 8080 |
"type": "opencollective",
|
| 8081 |
"url": "https://opencollective.com/express"
|
| 8082 |
}
|
| 8083 |
},
|
| 8084 |
-
"node_modules/express/node_modules/
|
| 8085 |
-
"version": "2.
|
| 8086 |
-
"resolved": "https://registry.npmjs.org/
|
| 8087 |
-
"integrity": "sha512-
|
| 8088 |
"license": "MIT",
|
| 8089 |
"dependencies": {
|
| 8090 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8091 |
}
|
| 8092 |
},
|
| 8093 |
-
"node_modules/express/node_modules/
|
| 8094 |
-
"version": "
|
| 8095 |
-
"resolved": "https://registry.npmjs.org/
|
| 8096 |
-
"integrity": "sha512-
|
| 8097 |
-
"license": "MIT"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8098 |
},
|
| 8099 |
"node_modules/fast-deep-equal": {
|
| 8100 |
"version": "3.1.3",
|
|
@@ -8290,38 +8451,26 @@
|
|
| 8290 |
}
|
| 8291 |
},
|
| 8292 |
"node_modules/finalhandler": {
|
| 8293 |
-
"version": "1.
|
| 8294 |
-
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.
|
| 8295 |
-
"integrity": "sha512-
|
| 8296 |
"license": "MIT",
|
| 8297 |
"dependencies": {
|
| 8298 |
-
"debug": "
|
| 8299 |
-
"encodeurl": "
|
| 8300 |
-
"escape-html": "
|
| 8301 |
-
"on-finished": "
|
| 8302 |
-
"parseurl": "
|
| 8303 |
-
"statuses": "
|
| 8304 |
-
"unpipe": "~1.0.0"
|
| 8305 |
},
|
| 8306 |
"engines": {
|
| 8307 |
-
"node": ">= 0.
|
| 8308 |
-
}
|
| 8309 |
-
|
| 8310 |
-
|
| 8311 |
-
|
| 8312 |
-
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
| 8313 |
-
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
| 8314 |
-
"license": "MIT",
|
| 8315 |
-
"dependencies": {
|
| 8316 |
-
"ms": "2.0.0"
|
| 8317 |
}
|
| 8318 |
},
|
| 8319 |
-
"node_modules/finalhandler/node_modules/ms": {
|
| 8320 |
-
"version": "2.0.0",
|
| 8321 |
-
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
| 8322 |
-
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
| 8323 |
-
"license": "MIT"
|
| 8324 |
-
},
|
| 8325 |
"node_modules/find-cache-dir": {
|
| 8326 |
"version": "3.3.2",
|
| 8327 |
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
|
|
@@ -8543,12 +8692,12 @@
|
|
| 8543 |
}
|
| 8544 |
},
|
| 8545 |
"node_modules/fresh": {
|
| 8546 |
-
"version": "0.
|
| 8547 |
-
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.
|
| 8548 |
-
"integrity": "sha512-
|
| 8549 |
"license": "MIT",
|
| 8550 |
"engines": {
|
| 8551 |
-
"node": ">= 0.
|
| 8552 |
}
|
| 8553 |
},
|
| 8554 |
"node_modules/fs-extra": {
|
|
@@ -9783,6 +9932,12 @@
|
|
| 9783 |
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
|
| 9784 |
"license": "MIT"
|
| 9785 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9786 |
"node_modules/is-regex": {
|
| 9787 |
"version": "1.2.1",
|
| 9788 |
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
|
@@ -11457,12 +11612,12 @@
|
|
| 11457 |
"license": "CC0-1.0"
|
| 11458 |
},
|
| 11459 |
"node_modules/media-typer": {
|
| 11460 |
-
"version": "
|
| 11461 |
-
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-
|
| 11462 |
-
"integrity": "sha512-
|
| 11463 |
"license": "MIT",
|
| 11464 |
"engines": {
|
| 11465 |
-
"node": ">= 0.
|
| 11466 |
}
|
| 11467 |
},
|
| 11468 |
"node_modules/memfs": {
|
|
@@ -11478,10 +11633,13 @@
|
|
| 11478 |
}
|
| 11479 |
},
|
| 11480 |
"node_modules/merge-descriptors": {
|
| 11481 |
-
"version": "
|
| 11482 |
-
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-
|
| 11483 |
-
"integrity": "sha512-
|
| 11484 |
"license": "MIT",
|
|
|
|
|
|
|
|
|
|
| 11485 |
"funding": {
|
| 11486 |
"url": "https://github.com/sponsors/sindresorhus"
|
| 11487 |
}
|
|
@@ -12212,10 +12370,14 @@
|
|
| 12212 |
"license": "MIT"
|
| 12213 |
},
|
| 12214 |
"node_modules/path-to-regexp": {
|
| 12215 |
-
"version": "
|
| 12216 |
-
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-
|
| 12217 |
-
"integrity": "sha512-
|
| 12218 |
-
"license": "MIT"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12219 |
},
|
| 12220 |
"node_modules/path-type": {
|
| 12221 |
"version": "4.0.0",
|
|
@@ -12338,6 +12500,53 @@
|
|
| 12338 |
"node": ">=4"
|
| 12339 |
}
|
| 12340 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12341 |
"node_modules/possible-typed-array-names": {
|
| 12342 |
"version": "1.1.0",
|
| 12343 |
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
|
@@ -13748,9 +13957,9 @@
|
|
| 13748 |
}
|
| 13749 |
},
|
| 13750 |
"node_modules/qs": {
|
| 13751 |
-
"version": "6.
|
| 13752 |
-
"resolved": "https://registry.npmjs.org/qs/-/qs-6.
|
| 13753 |
-
"integrity": "sha512-
|
| 13754 |
"license": "BSD-3-Clause",
|
| 13755 |
"dependencies": {
|
| 13756 |
"side-channel": "^1.1.0"
|
|
@@ -13816,30 +14025,34 @@
|
|
| 13816 |
}
|
| 13817 |
},
|
| 13818 |
"node_modules/raw-body": {
|
| 13819 |
-
"version": "
|
| 13820 |
-
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-
|
| 13821 |
-
"integrity": "sha512-
|
| 13822 |
"license": "MIT",
|
| 13823 |
"dependencies": {
|
| 13824 |
"bytes": "~3.1.2",
|
| 13825 |
"http-errors": "~2.0.1",
|
| 13826 |
-
"iconv-lite": "~0.
|
| 13827 |
"unpipe": "~1.0.0"
|
| 13828 |
},
|
| 13829 |
"engines": {
|
| 13830 |
-
"node": ">= 0.
|
| 13831 |
}
|
| 13832 |
},
|
| 13833 |
"node_modules/raw-body/node_modules/iconv-lite": {
|
| 13834 |
-
"version": "0.
|
| 13835 |
-
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.
|
| 13836 |
-
"integrity": "sha512-
|
| 13837 |
"license": "MIT",
|
| 13838 |
"dependencies": {
|
| 13839 |
-
"safer-buffer": ">= 2.1.2 < 3"
|
| 13840 |
},
|
| 13841 |
"engines": {
|
| 13842 |
"node": ">=0.10.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13843 |
}
|
| 13844 |
},
|
| 13845 |
"node_modules/react": {
|
|
@@ -14587,6 +14800,22 @@
|
|
| 14587 |
"randombytes": "^2.1.0"
|
| 14588 |
}
|
| 14589 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14590 |
"node_modules/run-parallel": {
|
| 14591 |
"version": "1.2.0",
|
| 14592 |
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
|
@@ -14610,6 +14839,15 @@
|
|
| 14610 |
"queue-microtask": "^1.2.2"
|
| 14611 |
}
|
| 14612 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14613 |
"node_modules/safe-array-concat": {
|
| 14614 |
"version": "1.1.3",
|
| 14615 |
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
|
|
@@ -14841,43 +15079,55 @@
|
|
| 14841 |
}
|
| 14842 |
},
|
| 14843 |
"node_modules/send": {
|
| 14844 |
-
"version": "
|
| 14845 |
-
"resolved": "https://registry.npmjs.org/send/-/send-
|
| 14846 |
-
"integrity": "sha512-
|
| 14847 |
"license": "MIT",
|
| 14848 |
"dependencies": {
|
| 14849 |
-
"debug": "
|
| 14850 |
-
"
|
| 14851 |
-
"
|
| 14852 |
-
"
|
| 14853 |
-
"
|
| 14854 |
-
"
|
| 14855 |
-
"
|
| 14856 |
-
"
|
| 14857 |
-
"
|
| 14858 |
-
"
|
| 14859 |
-
"
|
| 14860 |
-
"range-parser": "~1.2.1",
|
| 14861 |
-
"statuses": "~2.0.2"
|
| 14862 |
},
|
| 14863 |
"engines": {
|
| 14864 |
-
"node": ">=
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14865 |
}
|
| 14866 |
},
|
| 14867 |
-
"node_modules/send/node_modules/
|
| 14868 |
-
"version": "
|
| 14869 |
-
"resolved": "https://registry.npmjs.org/
|
| 14870 |
-
"integrity": "sha512-
|
| 14871 |
"license": "MIT",
|
| 14872 |
-
"
|
| 14873 |
-
"
|
| 14874 |
}
|
| 14875 |
},
|
| 14876 |
-
"node_modules/send/node_modules/
|
| 14877 |
-
"version": "
|
| 14878 |
-
"resolved": "https://registry.npmjs.org/
|
| 14879 |
-
"integrity": "sha512-
|
| 14880 |
-
"license": "MIT"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14881 |
},
|
| 14882 |
"node_modules/serialize-javascript": {
|
| 14883 |
"version": "6.0.2",
|
|
@@ -14960,18 +15210,22 @@
|
|
| 14960 |
}
|
| 14961 |
},
|
| 14962 |
"node_modules/serve-static": {
|
| 14963 |
-
"version": "
|
| 14964 |
-
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-
|
| 14965 |
-
"integrity": "sha512-
|
| 14966 |
"license": "MIT",
|
| 14967 |
"dependencies": {
|
| 14968 |
-
"encodeurl": "
|
| 14969 |
-
"escape-html": "
|
| 14970 |
-
"parseurl": "
|
| 14971 |
-
"send": "
|
| 14972 |
},
|
| 14973 |
"engines": {
|
| 14974 |
-
"node": ">=
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14975 |
}
|
| 14976 |
},
|
| 14977 |
"node_modules/set-function-length": {
|
|
@@ -16220,6 +16474,15 @@
|
|
| 16220 |
"node": ">=8"
|
| 16221 |
}
|
| 16222 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16223 |
"node_modules/tryer": {
|
| 16224 |
"version": "1.0.1",
|
| 16225 |
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
|
|
@@ -16326,18 +16589,44 @@
|
|
| 16326 |
}
|
| 16327 |
},
|
| 16328 |
"node_modules/type-is": {
|
| 16329 |
-
"version": "
|
| 16330 |
-
"resolved": "https://registry.npmjs.org/type-is/-/type-is-
|
| 16331 |
-
"integrity": "sha512-
|
| 16332 |
"license": "MIT",
|
| 16333 |
"dependencies": {
|
| 16334 |
-
"
|
| 16335 |
-
"
|
|
|
|
| 16336 |
},
|
| 16337 |
"engines": {
|
| 16338 |
"node": ">= 0.6"
|
| 16339 |
}
|
| 16340 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16341 |
"node_modules/typed-array-buffer": {
|
| 16342 |
"version": "1.0.3",
|
| 16343 |
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
|
|
@@ -16903,6 +17192,254 @@
|
|
| 16903 |
}
|
| 16904 |
}
|
| 16905 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16906 |
"node_modules/webpack-dev-server/node_modules/ws": {
|
| 16907 |
"version": "8.19.0",
|
| 16908 |
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
|
|
|
| 8 |
"name": "react-template",
|
| 9 |
"version": "0.1.0",
|
| 10 |
"dependencies": {
|
| 11 |
+
"@huggingface/hub": "^2.6.4",
|
| 12 |
"@testing-library/dom": "^10.4.0",
|
| 13 |
"@testing-library/jest-dom": "^6.6.3",
|
| 14 |
"@testing-library/react": "^16.3.0",
|
| 15 |
"@testing-library/user-event": "^13.5.0",
|
| 16 |
+
"concurrently": "^9.2.1",
|
| 17 |
+
"express": "^5.1.0",
|
| 18 |
"react": "^19.1.0",
|
| 19 |
"react-dom": "^19.1.0",
|
| 20 |
"react-scripts": "5.0.1",
|
| 21 |
"recharts": "^3.7.0",
|
| 22 |
"web-vitals": "^2.1.4"
|
| 23 |
+
},
|
| 24 |
+
"devDependencies": {
|
| 25 |
+
"@playwright/test": "^1.58.2"
|
| 26 |
}
|
| 27 |
},
|
| 28 |
"node_modules/@adobe/css-tools": {
|
|
|
|
| 2463 |
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
| 2464 |
}
|
| 2465 |
},
|
| 2466 |
+
"node_modules/@huggingface/hub": {
|
| 2467 |
+
"version": "2.11.0",
|
| 2468 |
+
"resolved": "https://registry.npmjs.org/@huggingface/hub/-/hub-2.11.0.tgz",
|
| 2469 |
+
"integrity": "sha512-WS6QGaXYeBVFlaB4SOn6z4LGUpLB5kRZNL08uUni4izX353KxiwwZMK5+/AWX86MJh8SMZNa/JFcvFCcQsbszQ==",
|
| 2470 |
+
"license": "MIT",
|
| 2471 |
+
"dependencies": {
|
| 2472 |
+
"@huggingface/tasks": "^0.19.90"
|
| 2473 |
+
},
|
| 2474 |
+
"bin": {
|
| 2475 |
+
"hfjs": "dist/cli.js"
|
| 2476 |
+
},
|
| 2477 |
+
"engines": {
|
| 2478 |
+
"node": ">=18"
|
| 2479 |
+
},
|
| 2480 |
+
"optionalDependencies": {
|
| 2481 |
+
"cli-progress": "^3.12.0"
|
| 2482 |
+
}
|
| 2483 |
+
},
|
| 2484 |
+
"node_modules/@huggingface/tasks": {
|
| 2485 |
+
"version": "0.19.90",
|
| 2486 |
+
"resolved": "https://registry.npmjs.org/@huggingface/tasks/-/tasks-0.19.90.tgz",
|
| 2487 |
+
"integrity": "sha512-nfV9luJbvwGQ/5oKXkKhCV9h4X7mwh1YaGG3ORd6UMLDSwr1OFSSatcBX0O9OtBtmNK19aGSjbLFqqgcIR6+IA==",
|
| 2488 |
+
"license": "MIT"
|
| 2489 |
+
},
|
| 2490 |
"node_modules/@humanwhocodes/config-array": {
|
| 2491 |
"version": "0.13.0",
|
| 2492 |
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
|
|
|
| 2968 |
"node": ">= 8"
|
| 2969 |
}
|
| 2970 |
},
|
| 2971 |
+
"node_modules/@playwright/test": {
|
| 2972 |
+
"version": "1.58.2",
|
| 2973 |
+
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz",
|
| 2974 |
+
"integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
|
| 2975 |
+
"dev": true,
|
| 2976 |
+
"license": "Apache-2.0",
|
| 2977 |
+
"dependencies": {
|
| 2978 |
+
"playwright": "1.58.2"
|
| 2979 |
+
},
|
| 2980 |
+
"bin": {
|
| 2981 |
+
"playwright": "cli.js"
|
| 2982 |
+
},
|
| 2983 |
+
"engines": {
|
| 2984 |
+
"node": ">=18"
|
| 2985 |
+
}
|
| 2986 |
+
},
|
| 2987 |
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
|
| 2988 |
"version": "0.5.17",
|
| 2989 |
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.17.tgz",
|
|
|
|
| 5295 |
"license": "MIT"
|
| 5296 |
},
|
| 5297 |
"node_modules/body-parser": {
|
| 5298 |
+
"version": "2.2.2",
|
| 5299 |
+
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
|
| 5300 |
+
"integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
|
| 5301 |
"license": "MIT",
|
| 5302 |
"dependencies": {
|
| 5303 |
+
"bytes": "^3.1.2",
|
| 5304 |
+
"content-type": "^1.0.5",
|
| 5305 |
+
"debug": "^4.4.3",
|
| 5306 |
+
"http-errors": "^2.0.0",
|
| 5307 |
+
"iconv-lite": "^0.7.0",
|
| 5308 |
+
"on-finished": "^2.4.1",
|
| 5309 |
+
"qs": "^6.14.1",
|
| 5310 |
+
"raw-body": "^3.0.1",
|
| 5311 |
+
"type-is": "^2.0.1"
|
|
|
|
|
|
|
|
|
|
| 5312 |
},
|
| 5313 |
"engines": {
|
| 5314 |
+
"node": ">=18"
|
| 5315 |
+
},
|
| 5316 |
+
"funding": {
|
| 5317 |
+
"type": "opencollective",
|
| 5318 |
+
"url": "https://opencollective.com/express"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5319 |
}
|
| 5320 |
},
|
| 5321 |
"node_modules/body-parser/node_modules/iconv-lite": {
|
| 5322 |
+
"version": "0.7.2",
|
| 5323 |
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
| 5324 |
+
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
|
| 5325 |
"license": "MIT",
|
| 5326 |
"dependencies": {
|
| 5327 |
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
| 5328 |
},
|
| 5329 |
"engines": {
|
| 5330 |
"node": ">=0.10.0"
|
| 5331 |
+
},
|
| 5332 |
+
"funding": {
|
| 5333 |
+
"type": "opencollective",
|
| 5334 |
+
"url": "https://opencollective.com/express"
|
| 5335 |
}
|
| 5336 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5337 |
"node_modules/bonjour-service": {
|
| 5338 |
"version": "1.3.0",
|
| 5339 |
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz",
|
|
|
|
| 5708 |
"node": ">=0.10.0"
|
| 5709 |
}
|
| 5710 |
},
|
| 5711 |
+
"node_modules/cli-progress": {
|
| 5712 |
+
"version": "3.12.0",
|
| 5713 |
+
"resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz",
|
| 5714 |
+
"integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==",
|
| 5715 |
+
"license": "MIT",
|
| 5716 |
+
"optional": true,
|
| 5717 |
+
"dependencies": {
|
| 5718 |
+
"string-width": "^4.2.3"
|
| 5719 |
+
},
|
| 5720 |
+
"engines": {
|
| 5721 |
+
"node": ">=4"
|
| 5722 |
+
}
|
| 5723 |
+
},
|
| 5724 |
"node_modules/cliui": {
|
| 5725 |
"version": "7.0.4",
|
| 5726 |
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
|
|
|
| 5959 |
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
| 5960 |
"license": "MIT"
|
| 5961 |
},
|
| 5962 |
+
"node_modules/concurrently": {
|
| 5963 |
+
"version": "9.2.1",
|
| 5964 |
+
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
|
| 5965 |
+
"integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
|
| 5966 |
+
"license": "MIT",
|
| 5967 |
+
"dependencies": {
|
| 5968 |
+
"chalk": "4.1.2",
|
| 5969 |
+
"rxjs": "7.8.2",
|
| 5970 |
+
"shell-quote": "1.8.3",
|
| 5971 |
+
"supports-color": "8.1.1",
|
| 5972 |
+
"tree-kill": "1.2.2",
|
| 5973 |
+
"yargs": "17.7.2"
|
| 5974 |
+
},
|
| 5975 |
+
"bin": {
|
| 5976 |
+
"conc": "dist/bin/concurrently.js",
|
| 5977 |
+
"concurrently": "dist/bin/concurrently.js"
|
| 5978 |
+
},
|
| 5979 |
+
"engines": {
|
| 5980 |
+
"node": ">=18"
|
| 5981 |
+
},
|
| 5982 |
+
"funding": {
|
| 5983 |
+
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
| 5984 |
+
}
|
| 5985 |
+
},
|
| 5986 |
+
"node_modules/concurrently/node_modules/cliui": {
|
| 5987 |
+
"version": "8.0.1",
|
| 5988 |
+
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
| 5989 |
+
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
| 5990 |
+
"license": "ISC",
|
| 5991 |
+
"dependencies": {
|
| 5992 |
+
"string-width": "^4.2.0",
|
| 5993 |
+
"strip-ansi": "^6.0.1",
|
| 5994 |
+
"wrap-ansi": "^7.0.0"
|
| 5995 |
+
},
|
| 5996 |
+
"engines": {
|
| 5997 |
+
"node": ">=12"
|
| 5998 |
+
}
|
| 5999 |
+
},
|
| 6000 |
+
"node_modules/concurrently/node_modules/supports-color": {
|
| 6001 |
+
"version": "8.1.1",
|
| 6002 |
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
| 6003 |
+
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
| 6004 |
+
"license": "MIT",
|
| 6005 |
+
"dependencies": {
|
| 6006 |
+
"has-flag": "^4.0.0"
|
| 6007 |
+
},
|
| 6008 |
+
"engines": {
|
| 6009 |
+
"node": ">=10"
|
| 6010 |
+
},
|
| 6011 |
+
"funding": {
|
| 6012 |
+
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
| 6013 |
+
}
|
| 6014 |
+
},
|
| 6015 |
+
"node_modules/concurrently/node_modules/yargs": {
|
| 6016 |
+
"version": "17.7.2",
|
| 6017 |
+
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
| 6018 |
+
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
| 6019 |
+
"license": "MIT",
|
| 6020 |
+
"dependencies": {
|
| 6021 |
+
"cliui": "^8.0.1",
|
| 6022 |
+
"escalade": "^3.1.1",
|
| 6023 |
+
"get-caller-file": "^2.0.5",
|
| 6024 |
+
"require-directory": "^2.1.1",
|
| 6025 |
+
"string-width": "^4.2.3",
|
| 6026 |
+
"y18n": "^5.0.5",
|
| 6027 |
+
"yargs-parser": "^21.1.1"
|
| 6028 |
+
},
|
| 6029 |
+
"engines": {
|
| 6030 |
+
"node": ">=12"
|
| 6031 |
+
}
|
| 6032 |
+
},
|
| 6033 |
+
"node_modules/concurrently/node_modules/yargs-parser": {
|
| 6034 |
+
"version": "21.1.1",
|
| 6035 |
+
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
| 6036 |
+
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
| 6037 |
+
"license": "ISC",
|
| 6038 |
+
"engines": {
|
| 6039 |
+
"node": ">=12"
|
| 6040 |
+
}
|
| 6041 |
+
},
|
| 6042 |
"node_modules/confusing-browser-globals": {
|
| 6043 |
"version": "1.0.11",
|
| 6044 |
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
|
|
|
|
| 6055 |
}
|
| 6056 |
},
|
| 6057 |
"node_modules/content-disposition": {
|
| 6058 |
+
"version": "1.0.1",
|
| 6059 |
+
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
|
| 6060 |
+
"integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
|
| 6061 |
"license": "MIT",
|
|
|
|
|
|
|
|
|
|
| 6062 |
"engines": {
|
| 6063 |
+
"node": ">=18"
|
| 6064 |
+
},
|
| 6065 |
+
"funding": {
|
| 6066 |
+
"type": "opencollective",
|
| 6067 |
+
"url": "https://opencollective.com/express"
|
| 6068 |
}
|
| 6069 |
},
|
| 6070 |
"node_modules/content-type": {
|
|
|
|
| 6092 |
}
|
| 6093 |
},
|
| 6094 |
"node_modules/cookie-signature": {
|
| 6095 |
+
"version": "1.2.2",
|
| 6096 |
+
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
|
| 6097 |
+
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
|
| 6098 |
+
"license": "MIT",
|
| 6099 |
+
"engines": {
|
| 6100 |
+
"node": ">=6.6.0"
|
| 6101 |
+
}
|
| 6102 |
},
|
| 6103 |
"node_modules/core-js": {
|
| 6104 |
"version": "3.48.0",
|
|
|
|
| 8168 |
}
|
| 8169 |
},
|
| 8170 |
"node_modules/express": {
|
| 8171 |
+
"version": "5.2.1",
|
| 8172 |
+
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
| 8173 |
+
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
| 8174 |
+
"license": "MIT",
|
| 8175 |
+
"dependencies": {
|
| 8176 |
+
"accepts": "^2.0.0",
|
| 8177 |
+
"body-parser": "^2.2.1",
|
| 8178 |
+
"content-disposition": "^1.0.0",
|
| 8179 |
+
"content-type": "^1.0.5",
|
| 8180 |
+
"cookie": "^0.7.1",
|
| 8181 |
+
"cookie-signature": "^1.2.1",
|
| 8182 |
+
"debug": "^4.4.0",
|
| 8183 |
+
"depd": "^2.0.0",
|
| 8184 |
+
"encodeurl": "^2.0.0",
|
| 8185 |
+
"escape-html": "^1.0.3",
|
| 8186 |
+
"etag": "^1.8.1",
|
| 8187 |
+
"finalhandler": "^2.1.0",
|
| 8188 |
+
"fresh": "^2.0.0",
|
| 8189 |
+
"http-errors": "^2.0.0",
|
| 8190 |
+
"merge-descriptors": "^2.0.0",
|
| 8191 |
+
"mime-types": "^3.0.0",
|
| 8192 |
+
"on-finished": "^2.4.1",
|
| 8193 |
+
"once": "^1.4.0",
|
| 8194 |
+
"parseurl": "^1.3.3",
|
| 8195 |
+
"proxy-addr": "^2.0.7",
|
| 8196 |
+
"qs": "^6.14.0",
|
| 8197 |
+
"range-parser": "^1.2.1",
|
| 8198 |
+
"router": "^2.2.0",
|
| 8199 |
+
"send": "^1.1.0",
|
| 8200 |
+
"serve-static": "^2.2.0",
|
| 8201 |
+
"statuses": "^2.0.1",
|
| 8202 |
+
"type-is": "^2.0.1",
|
| 8203 |
+
"vary": "^1.1.2"
|
|
|
|
|
|
|
|
|
|
| 8204 |
},
|
| 8205 |
"engines": {
|
| 8206 |
+
"node": ">= 18"
|
| 8207 |
},
|
| 8208 |
"funding": {
|
| 8209 |
"type": "opencollective",
|
| 8210 |
"url": "https://opencollective.com/express"
|
| 8211 |
}
|
| 8212 |
},
|
| 8213 |
+
"node_modules/express/node_modules/accepts": {
|
| 8214 |
+
"version": "2.0.0",
|
| 8215 |
+
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
| 8216 |
+
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
|
| 8217 |
"license": "MIT",
|
| 8218 |
"dependencies": {
|
| 8219 |
+
"mime-types": "^3.0.0",
|
| 8220 |
+
"negotiator": "^1.0.0"
|
| 8221 |
+
},
|
| 8222 |
+
"engines": {
|
| 8223 |
+
"node": ">= 0.6"
|
| 8224 |
}
|
| 8225 |
},
|
| 8226 |
+
"node_modules/express/node_modules/mime-db": {
|
| 8227 |
+
"version": "1.54.0",
|
| 8228 |
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
| 8229 |
+
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
| 8230 |
+
"license": "MIT",
|
| 8231 |
+
"engines": {
|
| 8232 |
+
"node": ">= 0.6"
|
| 8233 |
+
}
|
| 8234 |
+
},
|
| 8235 |
+
"node_modules/express/node_modules/mime-types": {
|
| 8236 |
+
"version": "3.0.2",
|
| 8237 |
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
| 8238 |
+
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
| 8239 |
+
"license": "MIT",
|
| 8240 |
+
"dependencies": {
|
| 8241 |
+
"mime-db": "^1.54.0"
|
| 8242 |
+
},
|
| 8243 |
+
"engines": {
|
| 8244 |
+
"node": ">=18"
|
| 8245 |
+
},
|
| 8246 |
+
"funding": {
|
| 8247 |
+
"type": "opencollective",
|
| 8248 |
+
"url": "https://opencollective.com/express"
|
| 8249 |
+
}
|
| 8250 |
+
},
|
| 8251 |
+
"node_modules/express/node_modules/negotiator": {
|
| 8252 |
+
"version": "1.0.0",
|
| 8253 |
+
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
| 8254 |
+
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
|
| 8255 |
+
"license": "MIT",
|
| 8256 |
+
"engines": {
|
| 8257 |
+
"node": ">= 0.6"
|
| 8258 |
+
}
|
| 8259 |
},
|
| 8260 |
"node_modules/fast-deep-equal": {
|
| 8261 |
"version": "3.1.3",
|
|
|
|
| 8451 |
}
|
| 8452 |
},
|
| 8453 |
"node_modules/finalhandler": {
|
| 8454 |
+
"version": "2.1.1",
|
| 8455 |
+
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
|
| 8456 |
+
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
|
| 8457 |
"license": "MIT",
|
| 8458 |
"dependencies": {
|
| 8459 |
+
"debug": "^4.4.0",
|
| 8460 |
+
"encodeurl": "^2.0.0",
|
| 8461 |
+
"escape-html": "^1.0.3",
|
| 8462 |
+
"on-finished": "^2.4.1",
|
| 8463 |
+
"parseurl": "^1.3.3",
|
| 8464 |
+
"statuses": "^2.0.1"
|
|
|
|
| 8465 |
},
|
| 8466 |
"engines": {
|
| 8467 |
+
"node": ">= 18.0.0"
|
| 8468 |
+
},
|
| 8469 |
+
"funding": {
|
| 8470 |
+
"type": "opencollective",
|
| 8471 |
+
"url": "https://opencollective.com/express"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8472 |
}
|
| 8473 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8474 |
"node_modules/find-cache-dir": {
|
| 8475 |
"version": "3.3.2",
|
| 8476 |
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
|
|
|
|
| 8692 |
}
|
| 8693 |
},
|
| 8694 |
"node_modules/fresh": {
|
| 8695 |
+
"version": "2.0.0",
|
| 8696 |
+
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
| 8697 |
+
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
| 8698 |
"license": "MIT",
|
| 8699 |
"engines": {
|
| 8700 |
+
"node": ">= 0.8"
|
| 8701 |
}
|
| 8702 |
},
|
| 8703 |
"node_modules/fs-extra": {
|
|
|
|
| 9932 |
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
|
| 9933 |
"license": "MIT"
|
| 9934 |
},
|
| 9935 |
+
"node_modules/is-promise": {
|
| 9936 |
+
"version": "4.0.0",
|
| 9937 |
+
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
| 9938 |
+
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
| 9939 |
+
"license": "MIT"
|
| 9940 |
+
},
|
| 9941 |
"node_modules/is-regex": {
|
| 9942 |
"version": "1.2.1",
|
| 9943 |
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
|
|
|
| 11612 |
"license": "CC0-1.0"
|
| 11613 |
},
|
| 11614 |
"node_modules/media-typer": {
|
| 11615 |
+
"version": "1.1.0",
|
| 11616 |
+
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
| 11617 |
+
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
|
| 11618 |
"license": "MIT",
|
| 11619 |
"engines": {
|
| 11620 |
+
"node": ">= 0.8"
|
| 11621 |
}
|
| 11622 |
},
|
| 11623 |
"node_modules/memfs": {
|
|
|
|
| 11633 |
}
|
| 11634 |
},
|
| 11635 |
"node_modules/merge-descriptors": {
|
| 11636 |
+
"version": "2.0.0",
|
| 11637 |
+
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
| 11638 |
+
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
|
| 11639 |
"license": "MIT",
|
| 11640 |
+
"engines": {
|
| 11641 |
+
"node": ">=18"
|
| 11642 |
+
},
|
| 11643 |
"funding": {
|
| 11644 |
"url": "https://github.com/sponsors/sindresorhus"
|
| 11645 |
}
|
|
|
|
| 12370 |
"license": "MIT"
|
| 12371 |
},
|
| 12372 |
"node_modules/path-to-regexp": {
|
| 12373 |
+
"version": "8.3.0",
|
| 12374 |
+
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
| 12375 |
+
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
| 12376 |
+
"license": "MIT",
|
| 12377 |
+
"funding": {
|
| 12378 |
+
"type": "opencollective",
|
| 12379 |
+
"url": "https://opencollective.com/express"
|
| 12380 |
+
}
|
| 12381 |
},
|
| 12382 |
"node_modules/path-type": {
|
| 12383 |
"version": "4.0.0",
|
|
|
|
| 12500 |
"node": ">=4"
|
| 12501 |
}
|
| 12502 |
},
|
| 12503 |
+
"node_modules/playwright": {
|
| 12504 |
+
"version": "1.58.2",
|
| 12505 |
+
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
|
| 12506 |
+
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
|
| 12507 |
+
"dev": true,
|
| 12508 |
+
"license": "Apache-2.0",
|
| 12509 |
+
"dependencies": {
|
| 12510 |
+
"playwright-core": "1.58.2"
|
| 12511 |
+
},
|
| 12512 |
+
"bin": {
|
| 12513 |
+
"playwright": "cli.js"
|
| 12514 |
+
},
|
| 12515 |
+
"engines": {
|
| 12516 |
+
"node": ">=18"
|
| 12517 |
+
},
|
| 12518 |
+
"optionalDependencies": {
|
| 12519 |
+
"fsevents": "2.3.2"
|
| 12520 |
+
}
|
| 12521 |
+
},
|
| 12522 |
+
"node_modules/playwright-core": {
|
| 12523 |
+
"version": "1.58.2",
|
| 12524 |
+
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
|
| 12525 |
+
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
|
| 12526 |
+
"dev": true,
|
| 12527 |
+
"license": "Apache-2.0",
|
| 12528 |
+
"bin": {
|
| 12529 |
+
"playwright-core": "cli.js"
|
| 12530 |
+
},
|
| 12531 |
+
"engines": {
|
| 12532 |
+
"node": ">=18"
|
| 12533 |
+
}
|
| 12534 |
+
},
|
| 12535 |
+
"node_modules/playwright/node_modules/fsevents": {
|
| 12536 |
+
"version": "2.3.2",
|
| 12537 |
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
| 12538 |
+
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
| 12539 |
+
"dev": true,
|
| 12540 |
+
"hasInstallScript": true,
|
| 12541 |
+
"license": "MIT",
|
| 12542 |
+
"optional": true,
|
| 12543 |
+
"os": [
|
| 12544 |
+
"darwin"
|
| 12545 |
+
],
|
| 12546 |
+
"engines": {
|
| 12547 |
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
| 12548 |
+
}
|
| 12549 |
+
},
|
| 12550 |
"node_modules/possible-typed-array-names": {
|
| 12551 |
"version": "1.1.0",
|
| 12552 |
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
|
|
|
| 13957 |
}
|
| 13958 |
},
|
| 13959 |
"node_modules/qs": {
|
| 13960 |
+
"version": "6.15.0",
|
| 13961 |
+
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
|
| 13962 |
+
"integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
|
| 13963 |
"license": "BSD-3-Clause",
|
| 13964 |
"dependencies": {
|
| 13965 |
"side-channel": "^1.1.0"
|
|
|
|
| 14025 |
}
|
| 14026 |
},
|
| 14027 |
"node_modules/raw-body": {
|
| 14028 |
+
"version": "3.0.2",
|
| 14029 |
+
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
|
| 14030 |
+
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
|
| 14031 |
"license": "MIT",
|
| 14032 |
"dependencies": {
|
| 14033 |
"bytes": "~3.1.2",
|
| 14034 |
"http-errors": "~2.0.1",
|
| 14035 |
+
"iconv-lite": "~0.7.0",
|
| 14036 |
"unpipe": "~1.0.0"
|
| 14037 |
},
|
| 14038 |
"engines": {
|
| 14039 |
+
"node": ">= 0.10"
|
| 14040 |
}
|
| 14041 |
},
|
| 14042 |
"node_modules/raw-body/node_modules/iconv-lite": {
|
| 14043 |
+
"version": "0.7.2",
|
| 14044 |
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
| 14045 |
+
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
|
| 14046 |
"license": "MIT",
|
| 14047 |
"dependencies": {
|
| 14048 |
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
| 14049 |
},
|
| 14050 |
"engines": {
|
| 14051 |
"node": ">=0.10.0"
|
| 14052 |
+
},
|
| 14053 |
+
"funding": {
|
| 14054 |
+
"type": "opencollective",
|
| 14055 |
+
"url": "https://opencollective.com/express"
|
| 14056 |
}
|
| 14057 |
},
|
| 14058 |
"node_modules/react": {
|
|
|
|
| 14800 |
"randombytes": "^2.1.0"
|
| 14801 |
}
|
| 14802 |
},
|
| 14803 |
+
"node_modules/router": {
|
| 14804 |
+
"version": "2.2.0",
|
| 14805 |
+
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
|
| 14806 |
+
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
|
| 14807 |
+
"license": "MIT",
|
| 14808 |
+
"dependencies": {
|
| 14809 |
+
"debug": "^4.4.0",
|
| 14810 |
+
"depd": "^2.0.0",
|
| 14811 |
+
"is-promise": "^4.0.0",
|
| 14812 |
+
"parseurl": "^1.3.3",
|
| 14813 |
+
"path-to-regexp": "^8.0.0"
|
| 14814 |
+
},
|
| 14815 |
+
"engines": {
|
| 14816 |
+
"node": ">= 18"
|
| 14817 |
+
}
|
| 14818 |
+
},
|
| 14819 |
"node_modules/run-parallel": {
|
| 14820 |
"version": "1.2.0",
|
| 14821 |
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
|
|
|
| 14839 |
"queue-microtask": "^1.2.2"
|
| 14840 |
}
|
| 14841 |
},
|
| 14842 |
+
"node_modules/rxjs": {
|
| 14843 |
+
"version": "7.8.2",
|
| 14844 |
+
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
| 14845 |
+
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
| 14846 |
+
"license": "Apache-2.0",
|
| 14847 |
+
"dependencies": {
|
| 14848 |
+
"tslib": "^2.1.0"
|
| 14849 |
+
}
|
| 14850 |
+
},
|
| 14851 |
"node_modules/safe-array-concat": {
|
| 14852 |
"version": "1.1.3",
|
| 14853 |
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
|
|
|
|
| 15079 |
}
|
| 15080 |
},
|
| 15081 |
"node_modules/send": {
|
| 15082 |
+
"version": "1.2.1",
|
| 15083 |
+
"resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
|
| 15084 |
+
"integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
|
| 15085 |
"license": "MIT",
|
| 15086 |
"dependencies": {
|
| 15087 |
+
"debug": "^4.4.3",
|
| 15088 |
+
"encodeurl": "^2.0.0",
|
| 15089 |
+
"escape-html": "^1.0.3",
|
| 15090 |
+
"etag": "^1.8.1",
|
| 15091 |
+
"fresh": "^2.0.0",
|
| 15092 |
+
"http-errors": "^2.0.1",
|
| 15093 |
+
"mime-types": "^3.0.2",
|
| 15094 |
+
"ms": "^2.1.3",
|
| 15095 |
+
"on-finished": "^2.4.1",
|
| 15096 |
+
"range-parser": "^1.2.1",
|
| 15097 |
+
"statuses": "^2.0.2"
|
|
|
|
|
|
|
| 15098 |
},
|
| 15099 |
"engines": {
|
| 15100 |
+
"node": ">= 18"
|
| 15101 |
+
},
|
| 15102 |
+
"funding": {
|
| 15103 |
+
"type": "opencollective",
|
| 15104 |
+
"url": "https://opencollective.com/express"
|
| 15105 |
}
|
| 15106 |
},
|
| 15107 |
+
"node_modules/send/node_modules/mime-db": {
|
| 15108 |
+
"version": "1.54.0",
|
| 15109 |
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
| 15110 |
+
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
| 15111 |
"license": "MIT",
|
| 15112 |
+
"engines": {
|
| 15113 |
+
"node": ">= 0.6"
|
| 15114 |
}
|
| 15115 |
},
|
| 15116 |
+
"node_modules/send/node_modules/mime-types": {
|
| 15117 |
+
"version": "3.0.2",
|
| 15118 |
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
| 15119 |
+
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
| 15120 |
+
"license": "MIT",
|
| 15121 |
+
"dependencies": {
|
| 15122 |
+
"mime-db": "^1.54.0"
|
| 15123 |
+
},
|
| 15124 |
+
"engines": {
|
| 15125 |
+
"node": ">=18"
|
| 15126 |
+
},
|
| 15127 |
+
"funding": {
|
| 15128 |
+
"type": "opencollective",
|
| 15129 |
+
"url": "https://opencollective.com/express"
|
| 15130 |
+
}
|
| 15131 |
},
|
| 15132 |
"node_modules/serialize-javascript": {
|
| 15133 |
"version": "6.0.2",
|
|
|
|
| 15210 |
}
|
| 15211 |
},
|
| 15212 |
"node_modules/serve-static": {
|
| 15213 |
+
"version": "2.2.1",
|
| 15214 |
+
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
|
| 15215 |
+
"integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
|
| 15216 |
"license": "MIT",
|
| 15217 |
"dependencies": {
|
| 15218 |
+
"encodeurl": "^2.0.0",
|
| 15219 |
+
"escape-html": "^1.0.3",
|
| 15220 |
+
"parseurl": "^1.3.3",
|
| 15221 |
+
"send": "^1.2.0"
|
| 15222 |
},
|
| 15223 |
"engines": {
|
| 15224 |
+
"node": ">= 18"
|
| 15225 |
+
},
|
| 15226 |
+
"funding": {
|
| 15227 |
+
"type": "opencollective",
|
| 15228 |
+
"url": "https://opencollective.com/express"
|
| 15229 |
}
|
| 15230 |
},
|
| 15231 |
"node_modules/set-function-length": {
|
|
|
|
| 16474 |
"node": ">=8"
|
| 16475 |
}
|
| 16476 |
},
|
| 16477 |
+
"node_modules/tree-kill": {
|
| 16478 |
+
"version": "1.2.2",
|
| 16479 |
+
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
| 16480 |
+
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
| 16481 |
+
"license": "MIT",
|
| 16482 |
+
"bin": {
|
| 16483 |
+
"tree-kill": "cli.js"
|
| 16484 |
+
}
|
| 16485 |
+
},
|
| 16486 |
"node_modules/tryer": {
|
| 16487 |
"version": "1.0.1",
|
| 16488 |
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
|
|
|
|
| 16589 |
}
|
| 16590 |
},
|
| 16591 |
"node_modules/type-is": {
|
| 16592 |
+
"version": "2.0.1",
|
| 16593 |
+
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
| 16594 |
+
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
|
| 16595 |
"license": "MIT",
|
| 16596 |
"dependencies": {
|
| 16597 |
+
"content-type": "^1.0.5",
|
| 16598 |
+
"media-typer": "^1.1.0",
|
| 16599 |
+
"mime-types": "^3.0.0"
|
| 16600 |
},
|
| 16601 |
"engines": {
|
| 16602 |
"node": ">= 0.6"
|
| 16603 |
}
|
| 16604 |
},
|
| 16605 |
+
"node_modules/type-is/node_modules/mime-db": {
|
| 16606 |
+
"version": "1.54.0",
|
| 16607 |
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
| 16608 |
+
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
| 16609 |
+
"license": "MIT",
|
| 16610 |
+
"engines": {
|
| 16611 |
+
"node": ">= 0.6"
|
| 16612 |
+
}
|
| 16613 |
+
},
|
| 16614 |
+
"node_modules/type-is/node_modules/mime-types": {
|
| 16615 |
+
"version": "3.0.2",
|
| 16616 |
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
| 16617 |
+
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
| 16618 |
+
"license": "MIT",
|
| 16619 |
+
"dependencies": {
|
| 16620 |
+
"mime-db": "^1.54.0"
|
| 16621 |
+
},
|
| 16622 |
+
"engines": {
|
| 16623 |
+
"node": ">=18"
|
| 16624 |
+
},
|
| 16625 |
+
"funding": {
|
| 16626 |
+
"type": "opencollective",
|
| 16627 |
+
"url": "https://opencollective.com/express"
|
| 16628 |
+
}
|
| 16629 |
+
},
|
| 16630 |
"node_modules/typed-array-buffer": {
|
| 16631 |
"version": "1.0.3",
|
| 16632 |
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
|
|
|
|
| 17192 |
}
|
| 17193 |
}
|
| 17194 |
},
|
| 17195 |
+
"node_modules/webpack-dev-server/node_modules/body-parser": {
|
| 17196 |
+
"version": "1.20.4",
|
| 17197 |
+
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
|
| 17198 |
+
"integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==",
|
| 17199 |
+
"license": "MIT",
|
| 17200 |
+
"dependencies": {
|
| 17201 |
+
"bytes": "~3.1.2",
|
| 17202 |
+
"content-type": "~1.0.5",
|
| 17203 |
+
"debug": "2.6.9",
|
| 17204 |
+
"depd": "2.0.0",
|
| 17205 |
+
"destroy": "~1.2.0",
|
| 17206 |
+
"http-errors": "~2.0.1",
|
| 17207 |
+
"iconv-lite": "~0.4.24",
|
| 17208 |
+
"on-finished": "~2.4.1",
|
| 17209 |
+
"qs": "~6.14.0",
|
| 17210 |
+
"raw-body": "~2.5.3",
|
| 17211 |
+
"type-is": "~1.6.18",
|
| 17212 |
+
"unpipe": "~1.0.0"
|
| 17213 |
+
},
|
| 17214 |
+
"engines": {
|
| 17215 |
+
"node": ">= 0.8",
|
| 17216 |
+
"npm": "1.2.8000 || >= 1.4.16"
|
| 17217 |
+
}
|
| 17218 |
+
},
|
| 17219 |
+
"node_modules/webpack-dev-server/node_modules/content-disposition": {
|
| 17220 |
+
"version": "0.5.4",
|
| 17221 |
+
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
| 17222 |
+
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
| 17223 |
+
"license": "MIT",
|
| 17224 |
+
"dependencies": {
|
| 17225 |
+
"safe-buffer": "5.2.1"
|
| 17226 |
+
},
|
| 17227 |
+
"engines": {
|
| 17228 |
+
"node": ">= 0.6"
|
| 17229 |
+
}
|
| 17230 |
+
},
|
| 17231 |
+
"node_modules/webpack-dev-server/node_modules/cookie-signature": {
|
| 17232 |
+
"version": "1.0.7",
|
| 17233 |
+
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
|
| 17234 |
+
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
|
| 17235 |
+
"license": "MIT"
|
| 17236 |
+
},
|
| 17237 |
+
"node_modules/webpack-dev-server/node_modules/debug": {
|
| 17238 |
+
"version": "2.6.9",
|
| 17239 |
+
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
| 17240 |
+
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
| 17241 |
+
"license": "MIT",
|
| 17242 |
+
"dependencies": {
|
| 17243 |
+
"ms": "2.0.0"
|
| 17244 |
+
}
|
| 17245 |
+
},
|
| 17246 |
+
"node_modules/webpack-dev-server/node_modules/debug/node_modules/ms": {
|
| 17247 |
+
"version": "2.0.0",
|
| 17248 |
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
| 17249 |
+
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
| 17250 |
+
"license": "MIT"
|
| 17251 |
+
},
|
| 17252 |
+
"node_modules/webpack-dev-server/node_modules/express": {
|
| 17253 |
+
"version": "4.22.1",
|
| 17254 |
+
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
|
| 17255 |
+
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
|
| 17256 |
+
"license": "MIT",
|
| 17257 |
+
"dependencies": {
|
| 17258 |
+
"accepts": "~1.3.8",
|
| 17259 |
+
"array-flatten": "1.1.1",
|
| 17260 |
+
"body-parser": "~1.20.3",
|
| 17261 |
+
"content-disposition": "~0.5.4",
|
| 17262 |
+
"content-type": "~1.0.4",
|
| 17263 |
+
"cookie": "~0.7.1",
|
| 17264 |
+
"cookie-signature": "~1.0.6",
|
| 17265 |
+
"debug": "2.6.9",
|
| 17266 |
+
"depd": "2.0.0",
|
| 17267 |
+
"encodeurl": "~2.0.0",
|
| 17268 |
+
"escape-html": "~1.0.3",
|
| 17269 |
+
"etag": "~1.8.1",
|
| 17270 |
+
"finalhandler": "~1.3.1",
|
| 17271 |
+
"fresh": "~0.5.2",
|
| 17272 |
+
"http-errors": "~2.0.0",
|
| 17273 |
+
"merge-descriptors": "1.0.3",
|
| 17274 |
+
"methods": "~1.1.2",
|
| 17275 |
+
"on-finished": "~2.4.1",
|
| 17276 |
+
"parseurl": "~1.3.3",
|
| 17277 |
+
"path-to-regexp": "~0.1.12",
|
| 17278 |
+
"proxy-addr": "~2.0.7",
|
| 17279 |
+
"qs": "~6.14.0",
|
| 17280 |
+
"range-parser": "~1.2.1",
|
| 17281 |
+
"safe-buffer": "5.2.1",
|
| 17282 |
+
"send": "~0.19.0",
|
| 17283 |
+
"serve-static": "~1.16.2",
|
| 17284 |
+
"setprototypeof": "1.2.0",
|
| 17285 |
+
"statuses": "~2.0.1",
|
| 17286 |
+
"type-is": "~1.6.18",
|
| 17287 |
+
"utils-merge": "1.0.1",
|
| 17288 |
+
"vary": "~1.1.2"
|
| 17289 |
+
},
|
| 17290 |
+
"engines": {
|
| 17291 |
+
"node": ">= 0.10.0"
|
| 17292 |
+
},
|
| 17293 |
+
"funding": {
|
| 17294 |
+
"type": "opencollective",
|
| 17295 |
+
"url": "https://opencollective.com/express"
|
| 17296 |
+
}
|
| 17297 |
+
},
|
| 17298 |
+
"node_modules/webpack-dev-server/node_modules/finalhandler": {
|
| 17299 |
+
"version": "1.3.2",
|
| 17300 |
+
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
| 17301 |
+
"integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
|
| 17302 |
+
"license": "MIT",
|
| 17303 |
+
"dependencies": {
|
| 17304 |
+
"debug": "2.6.9",
|
| 17305 |
+
"encodeurl": "~2.0.0",
|
| 17306 |
+
"escape-html": "~1.0.3",
|
| 17307 |
+
"on-finished": "~2.4.1",
|
| 17308 |
+
"parseurl": "~1.3.3",
|
| 17309 |
+
"statuses": "~2.0.2",
|
| 17310 |
+
"unpipe": "~1.0.0"
|
| 17311 |
+
},
|
| 17312 |
+
"engines": {
|
| 17313 |
+
"node": ">= 0.8"
|
| 17314 |
+
}
|
| 17315 |
+
},
|
| 17316 |
+
"node_modules/webpack-dev-server/node_modules/fresh": {
|
| 17317 |
+
"version": "0.5.2",
|
| 17318 |
+
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
| 17319 |
+
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
|
| 17320 |
+
"license": "MIT",
|
| 17321 |
+
"engines": {
|
| 17322 |
+
"node": ">= 0.6"
|
| 17323 |
+
}
|
| 17324 |
+
},
|
| 17325 |
+
"node_modules/webpack-dev-server/node_modules/iconv-lite": {
|
| 17326 |
+
"version": "0.4.24",
|
| 17327 |
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
| 17328 |
+
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
| 17329 |
+
"license": "MIT",
|
| 17330 |
+
"dependencies": {
|
| 17331 |
+
"safer-buffer": ">= 2.1.2 < 3"
|
| 17332 |
+
},
|
| 17333 |
+
"engines": {
|
| 17334 |
+
"node": ">=0.10.0"
|
| 17335 |
+
}
|
| 17336 |
+
},
|
| 17337 |
+
"node_modules/webpack-dev-server/node_modules/media-typer": {
|
| 17338 |
+
"version": "0.3.0",
|
| 17339 |
+
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
| 17340 |
+
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
| 17341 |
+
"license": "MIT",
|
| 17342 |
+
"engines": {
|
| 17343 |
+
"node": ">= 0.6"
|
| 17344 |
+
}
|
| 17345 |
+
},
|
| 17346 |
+
"node_modules/webpack-dev-server/node_modules/merge-descriptors": {
|
| 17347 |
+
"version": "1.0.3",
|
| 17348 |
+
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
| 17349 |
+
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
| 17350 |
+
"license": "MIT",
|
| 17351 |
+
"funding": {
|
| 17352 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 17353 |
+
}
|
| 17354 |
+
},
|
| 17355 |
+
"node_modules/webpack-dev-server/node_modules/path-to-regexp": {
|
| 17356 |
+
"version": "0.1.12",
|
| 17357 |
+
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
| 17358 |
+
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
| 17359 |
+
"license": "MIT"
|
| 17360 |
+
},
|
| 17361 |
+
"node_modules/webpack-dev-server/node_modules/qs": {
|
| 17362 |
+
"version": "6.14.2",
|
| 17363 |
+
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
| 17364 |
+
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
| 17365 |
+
"license": "BSD-3-Clause",
|
| 17366 |
+
"dependencies": {
|
| 17367 |
+
"side-channel": "^1.1.0"
|
| 17368 |
+
},
|
| 17369 |
+
"engines": {
|
| 17370 |
+
"node": ">=0.6"
|
| 17371 |
+
},
|
| 17372 |
+
"funding": {
|
| 17373 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 17374 |
+
}
|
| 17375 |
+
},
|
| 17376 |
+
"node_modules/webpack-dev-server/node_modules/raw-body": {
|
| 17377 |
+
"version": "2.5.3",
|
| 17378 |
+
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
|
| 17379 |
+
"integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
|
| 17380 |
+
"license": "MIT",
|
| 17381 |
+
"dependencies": {
|
| 17382 |
+
"bytes": "~3.1.2",
|
| 17383 |
+
"http-errors": "~2.0.1",
|
| 17384 |
+
"iconv-lite": "~0.4.24",
|
| 17385 |
+
"unpipe": "~1.0.0"
|
| 17386 |
+
},
|
| 17387 |
+
"engines": {
|
| 17388 |
+
"node": ">= 0.8"
|
| 17389 |
+
}
|
| 17390 |
+
},
|
| 17391 |
+
"node_modules/webpack-dev-server/node_modules/send": {
|
| 17392 |
+
"version": "0.19.2",
|
| 17393 |
+
"resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
|
| 17394 |
+
"integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
|
| 17395 |
+
"license": "MIT",
|
| 17396 |
+
"dependencies": {
|
| 17397 |
+
"debug": "2.6.9",
|
| 17398 |
+
"depd": "2.0.0",
|
| 17399 |
+
"destroy": "1.2.0",
|
| 17400 |
+
"encodeurl": "~2.0.0",
|
| 17401 |
+
"escape-html": "~1.0.3",
|
| 17402 |
+
"etag": "~1.8.1",
|
| 17403 |
+
"fresh": "~0.5.2",
|
| 17404 |
+
"http-errors": "~2.0.1",
|
| 17405 |
+
"mime": "1.6.0",
|
| 17406 |
+
"ms": "2.1.3",
|
| 17407 |
+
"on-finished": "~2.4.1",
|
| 17408 |
+
"range-parser": "~1.2.1",
|
| 17409 |
+
"statuses": "~2.0.2"
|
| 17410 |
+
},
|
| 17411 |
+
"engines": {
|
| 17412 |
+
"node": ">= 0.8.0"
|
| 17413 |
+
}
|
| 17414 |
+
},
|
| 17415 |
+
"node_modules/webpack-dev-server/node_modules/serve-static": {
|
| 17416 |
+
"version": "1.16.3",
|
| 17417 |
+
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
|
| 17418 |
+
"integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
|
| 17419 |
+
"license": "MIT",
|
| 17420 |
+
"dependencies": {
|
| 17421 |
+
"encodeurl": "~2.0.0",
|
| 17422 |
+
"escape-html": "~1.0.3",
|
| 17423 |
+
"parseurl": "~1.3.3",
|
| 17424 |
+
"send": "~0.19.1"
|
| 17425 |
+
},
|
| 17426 |
+
"engines": {
|
| 17427 |
+
"node": ">= 0.8.0"
|
| 17428 |
+
}
|
| 17429 |
+
},
|
| 17430 |
+
"node_modules/webpack-dev-server/node_modules/type-is": {
|
| 17431 |
+
"version": "1.6.18",
|
| 17432 |
+
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
| 17433 |
+
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
| 17434 |
+
"license": "MIT",
|
| 17435 |
+
"dependencies": {
|
| 17436 |
+
"media-typer": "0.3.0",
|
| 17437 |
+
"mime-types": "~2.1.24"
|
| 17438 |
+
},
|
| 17439 |
+
"engines": {
|
| 17440 |
+
"node": ">= 0.6"
|
| 17441 |
+
}
|
| 17442 |
+
},
|
| 17443 |
"node_modules/webpack-dev-server/node_modules/ws": {
|
| 17444 |
"version": "8.19.0",
|
| 17445 |
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
package.json
CHANGED
|
@@ -3,10 +3,13 @@
|
|
| 3 |
"version": "0.1.0",
|
| 4 |
"private": true,
|
| 5 |
"dependencies": {
|
|
|
|
| 6 |
"@testing-library/dom": "^10.4.0",
|
| 7 |
"@testing-library/jest-dom": "^6.6.3",
|
| 8 |
"@testing-library/react": "^16.3.0",
|
| 9 |
"@testing-library/user-event": "^13.5.0",
|
|
|
|
|
|
|
| 10 |
"react": "^19.1.0",
|
| 11 |
"react-dom": "^19.1.0",
|
| 12 |
"react-scripts": "5.0.1",
|
|
@@ -15,10 +18,13 @@
|
|
| 15 |
},
|
| 16 |
"scripts": {
|
| 17 |
"start": "react-scripts start",
|
|
|
|
|
|
|
| 18 |
"build": "react-scripts build",
|
| 19 |
"test": "react-scripts test",
|
| 20 |
"eject": "react-scripts eject"
|
| 21 |
},
|
|
|
|
| 22 |
"eslintConfig": {
|
| 23 |
"extends": [
|
| 24 |
"react-app",
|
|
@@ -36,5 +42,8 @@
|
|
| 36 |
"last 1 firefox version",
|
| 37 |
"last 1 safari version"
|
| 38 |
]
|
|
|
|
|
|
|
|
|
|
| 39 |
}
|
| 40 |
}
|
|
|
|
| 3 |
"version": "0.1.0",
|
| 4 |
"private": true,
|
| 5 |
"dependencies": {
|
| 6 |
+
"@huggingface/hub": "^2.6.4",
|
| 7 |
"@testing-library/dom": "^10.4.0",
|
| 8 |
"@testing-library/jest-dom": "^6.6.3",
|
| 9 |
"@testing-library/react": "^16.3.0",
|
| 10 |
"@testing-library/user-event": "^13.5.0",
|
| 11 |
+
"concurrently": "^9.2.1",
|
| 12 |
+
"express": "^5.1.0",
|
| 13 |
"react": "^19.1.0",
|
| 14 |
"react-dom": "^19.1.0",
|
| 15 |
"react-scripts": "5.0.1",
|
|
|
|
| 18 |
},
|
| 19 |
"scripts": {
|
| 20 |
"start": "react-scripts start",
|
| 21 |
+
"server": "node server/index.js",
|
| 22 |
+
"dev": "concurrently \"npm run server\" \"npm start\"",
|
| 23 |
"build": "react-scripts build",
|
| 24 |
"test": "react-scripts test",
|
| 25 |
"eject": "react-scripts eject"
|
| 26 |
},
|
| 27 |
+
"proxy": "http://localhost:4000",
|
| 28 |
"eslintConfig": {
|
| 29 |
"extends": [
|
| 30 |
"react-app",
|
|
|
|
| 42 |
"last 1 firefox version",
|
| 43 |
"last 1 safari version"
|
| 44 |
]
|
| 45 |
+
},
|
| 46 |
+
"devDependencies": {
|
| 47 |
+
"@playwright/test": "^1.58.2"
|
| 48 |
}
|
| 49 |
}
|
server/index.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const express = require('express');
|
| 2 |
+
const { randomUUID } = require('node:crypto');
|
| 3 |
+
const fs = require('node:fs/promises');
|
| 4 |
+
const path = require('node:path');
|
| 5 |
+
|
| 6 |
+
const app = express();
|
| 7 |
+
|
| 8 |
+
const PORT = Number(process.env.PORT || 4000);
|
| 9 |
+
const BUILD_DIR = path.join(__dirname, '..', 'build');
|
| 10 |
+
const LOCAL_DATA_DIR = path.join(__dirname, '..', 'data');
|
| 11 |
+
const LOCAL_DATA_FILE = process.env.SESSIONS_FILE || path.join(LOCAL_DATA_DIR, 'sessions.json');
|
| 12 |
+
const HUB_DATASET_REPO = process.env.HF_DATASET_REPO || '';
|
| 13 |
+
const HUB_TOKEN = process.env.HF_TOKEN || '';
|
| 14 |
+
const HUB_DATASET_FILE = process.env.HF_DATASET_FILE || 'sessions.json';
|
| 15 |
+
|
| 16 |
+
app.use(express.json({ limit: '1mb' }));
|
| 17 |
+
|
| 18 |
+
function sortSessionsByDateDesc(sessions) {
|
| 19 |
+
return [...sessions].sort((a, b) => {
|
| 20 |
+
const byDate = (b?.date || '').localeCompare(a?.date || '');
|
| 21 |
+
if (byDate !== 0) return byDate;
|
| 22 |
+
return (b?.id || '').localeCompare(a?.id || '');
|
| 23 |
+
});
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
function usingHubDataset() {
|
| 27 |
+
return Boolean(HUB_DATASET_REPO && HUB_TOKEN);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
async function ensureLocalDataFile() {
|
| 31 |
+
await fs.mkdir(path.dirname(LOCAL_DATA_FILE), { recursive: true });
|
| 32 |
+
try {
|
| 33 |
+
await fs.access(LOCAL_DATA_FILE);
|
| 34 |
+
} catch {
|
| 35 |
+
await fs.writeFile(LOCAL_DATA_FILE, '[]\n', 'utf8');
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
async function importHub() {
|
| 40 |
+
return import('@huggingface/hub');
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
async function readLocalSessions() {
|
| 44 |
+
await ensureLocalDataFile();
|
| 45 |
+
const raw = await fs.readFile(LOCAL_DATA_FILE, 'utf8');
|
| 46 |
+
const parsed = JSON.parse(raw);
|
| 47 |
+
return Array.isArray(parsed) ? parsed : [];
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
async function writeLocalSessions(sessions) {
|
| 51 |
+
await ensureLocalDataFile();
|
| 52 |
+
await fs.writeFile(LOCAL_DATA_FILE, `${JSON.stringify(sessions, null, 2)}\n`, 'utf8');
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
async function readDatasetSessions() {
|
| 56 |
+
const hub = await importHub();
|
| 57 |
+
try {
|
| 58 |
+
const response = await hub.downloadFile({
|
| 59 |
+
repo: { type: 'dataset', name: HUB_DATASET_REPO },
|
| 60 |
+
path: HUB_DATASET_FILE,
|
| 61 |
+
accessToken: HUB_TOKEN,
|
| 62 |
+
});
|
| 63 |
+
const raw = await response.text();
|
| 64 |
+
const parsed = JSON.parse(raw);
|
| 65 |
+
return Array.isArray(parsed) ? parsed : [];
|
| 66 |
+
} catch (error) {
|
| 67 |
+
if (error && typeof error === 'object' && 'statusCode' in error && error.statusCode === 404) {
|
| 68 |
+
return [];
|
| 69 |
+
}
|
| 70 |
+
throw error;
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
async function writeDatasetSessions(sessions) {
|
| 75 |
+
const hub = await importHub();
|
| 76 |
+
const payload = `${JSON.stringify(sessions, null, 2)}\n`;
|
| 77 |
+
await hub.uploadFiles({
|
| 78 |
+
repo: { type: 'dataset', name: HUB_DATASET_REPO },
|
| 79 |
+
accessToken: HUB_TOKEN,
|
| 80 |
+
files: [
|
| 81 |
+
{
|
| 82 |
+
path: HUB_DATASET_FILE,
|
| 83 |
+
content: new Blob([payload], { type: 'application/json' }),
|
| 84 |
+
},
|
| 85 |
+
],
|
| 86 |
+
commitTitle: 'Update climbing dashboard sessions',
|
| 87 |
+
});
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
async function readSessions() {
|
| 91 |
+
if (usingHubDataset()) {
|
| 92 |
+
return readDatasetSessions();
|
| 93 |
+
}
|
| 94 |
+
return readLocalSessions();
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
async function writeSessions(sessions) {
|
| 98 |
+
if (usingHubDataset()) {
|
| 99 |
+
return writeDatasetSessions(sessions);
|
| 100 |
+
}
|
| 101 |
+
return writeLocalSessions(sessions);
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
app.get('/api/health', (_req, res) => {
|
| 105 |
+
res.json({
|
| 106 |
+
ok: true,
|
| 107 |
+
storage: usingHubDataset() ? 'huggingface-dataset' : 'local-file',
|
| 108 |
+
datasetRepo: HUB_DATASET_REPO || null,
|
| 109 |
+
});
|
| 110 |
+
});
|
| 111 |
+
|
| 112 |
+
app.get('/api/sessions', async (_req, res, next) => {
|
| 113 |
+
try {
|
| 114 |
+
const sessions = await readSessions();
|
| 115 |
+
res.json(sortSessionsByDateDesc(sessions));
|
| 116 |
+
} catch (error) {
|
| 117 |
+
next(error);
|
| 118 |
+
}
|
| 119 |
+
});
|
| 120 |
+
|
| 121 |
+
app.post('/api/sessions', async (req, res, next) => {
|
| 122 |
+
try {
|
| 123 |
+
const incoming = req.body;
|
| 124 |
+
if (!incoming || typeof incoming !== 'object') {
|
| 125 |
+
return res.status(400).json({ error: 'Invalid session payload.' });
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
const sessions = await readSessions();
|
| 129 |
+
const session = {
|
| 130 |
+
...incoming,
|
| 131 |
+
id: incoming.id || randomUUID(),
|
| 132 |
+
};
|
| 133 |
+
|
| 134 |
+
const withoutSameId = sessions.filter((entry) => entry.id !== session.id);
|
| 135 |
+
const updated = sortSessionsByDateDesc([session, ...withoutSameId]);
|
| 136 |
+
|
| 137 |
+
await writeSessions(updated);
|
| 138 |
+
return res.status(201).json(session);
|
| 139 |
+
} catch (error) {
|
| 140 |
+
next(error);
|
| 141 |
+
}
|
| 142 |
+
});
|
| 143 |
+
|
| 144 |
+
app.put('/api/sessions/:id', async (req, res, next) => {
|
| 145 |
+
try {
|
| 146 |
+
const { id } = req.params;
|
| 147 |
+
const changes = req.body;
|
| 148 |
+
if (!changes || typeof changes !== 'object') {
|
| 149 |
+
return res.status(400).json({ error: 'Invalid update payload.' });
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
const sessions = await readSessions();
|
| 153 |
+
const index = sessions.findIndex((entry) => entry.id === id);
|
| 154 |
+
if (index === -1) {
|
| 155 |
+
return res.status(404).json({ error: 'Session not found.' });
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
const updatedSession = { ...sessions[index], ...changes, id };
|
| 159 |
+
const nextSessions = [...sessions];
|
| 160 |
+
nextSessions[index] = updatedSession;
|
| 161 |
+
|
| 162 |
+
await writeSessions(sortSessionsByDateDesc(nextSessions));
|
| 163 |
+
return res.json(updatedSession);
|
| 164 |
+
} catch (error) {
|
| 165 |
+
next(error);
|
| 166 |
+
}
|
| 167 |
+
});
|
| 168 |
+
|
| 169 |
+
app.delete('/api/sessions/:id', async (req, res, next) => {
|
| 170 |
+
try {
|
| 171 |
+
const { id } = req.params;
|
| 172 |
+
const sessions = await readSessions();
|
| 173 |
+
const nextSessions = sessions.filter((entry) => entry.id !== id);
|
| 174 |
+
|
| 175 |
+
if (nextSessions.length === sessions.length) {
|
| 176 |
+
return res.status(404).json({ error: 'Session not found.' });
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
await writeSessions(nextSessions);
|
| 180 |
+
return res.status(204).send();
|
| 181 |
+
} catch (error) {
|
| 182 |
+
next(error);
|
| 183 |
+
}
|
| 184 |
+
});
|
| 185 |
+
|
| 186 |
+
if (process.env.NODE_ENV === 'production') {
|
| 187 |
+
app.use(express.static(BUILD_DIR));
|
| 188 |
+
app.get('*', (_req, res) => {
|
| 189 |
+
res.sendFile(path.join(BUILD_DIR, 'index.html'));
|
| 190 |
+
});
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
app.use((error, _req, res, _next) => {
|
| 194 |
+
// eslint-disable-next-line no-console
|
| 195 |
+
console.error(error);
|
| 196 |
+
res.status(500).json({ error: 'Internal server error' });
|
| 197 |
+
});
|
| 198 |
+
|
| 199 |
+
app.listen(PORT, () => {
|
| 200 |
+
// eslint-disable-next-line no-console
|
| 201 |
+
console.log(`Session API listening on http://localhost:${PORT}`);
|
| 202 |
+
// eslint-disable-next-line no-console
|
| 203 |
+
console.log(`Storage backend: ${usingHubDataset() ? `dataset:${HUB_DATASET_REPO}/${HUB_DATASET_FILE}` : `local:${LOCAL_DATA_FILE}`}`);
|
| 204 |
+
});
|
src/App.css
CHANGED
|
@@ -19,6 +19,11 @@
|
|
| 19 |
color: var(--color-text-muted);
|
| 20 |
}
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
.dashboard-main {
|
| 23 |
display: flex;
|
| 24 |
flex-direction: column;
|
|
@@ -38,6 +43,11 @@
|
|
| 38 |
padding: 1.5rem;
|
| 39 |
}
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
@media (max-width: 768px) {
|
| 42 |
.dashboard {
|
| 43 |
padding: 1rem;
|
|
|
|
| 19 |
color: var(--color-text-muted);
|
| 20 |
}
|
| 21 |
|
| 22 |
+
.dashboard-header .sync-error {
|
| 23 |
+
color: var(--color-danger);
|
| 24 |
+
font-weight: 600;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
.dashboard-main {
|
| 28 |
display: flex;
|
| 29 |
flex-direction: column;
|
|
|
|
| 43 |
padding: 1.5rem;
|
| 44 |
}
|
| 45 |
|
| 46 |
+
.loading-message {
|
| 47 |
+
color: var(--color-text-muted);
|
| 48 |
+
font-weight: 600;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
@media (max-width: 768px) {
|
| 52 |
.dashboard {
|
| 53 |
padding: 1rem;
|
src/App.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
| 1 |
import { useEffect, useMemo, useState } from 'react';
|
| 2 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import {
|
| 4 |
buildChartData,
|
| 5 |
buildGradeProgressData,
|
|
@@ -17,11 +22,34 @@ import SessionLog from './components/SessionLog';
|
|
| 17 |
import './App.css';
|
| 18 |
|
| 19 |
function App() {
|
| 20 |
-
const [sessions, setSessions] = useState(
|
|
|
|
|
|
|
| 21 |
|
| 22 |
useEffect(() => {
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
const today = new Date().toISOString().split('T')[0];
|
| 27 |
const currentWeekKey = getWeekKey(today);
|
|
@@ -56,16 +84,36 @@ function App() {
|
|
| 56 |
const recommendation = computeRecommendation(recentSummaries);
|
| 57 |
const maxRoutes = computeMaxRoutesThreshold(sessions, today);
|
| 58 |
|
| 59 |
-
function handleAddSession(newSession) {
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
}
|
| 62 |
|
| 63 |
-
function handleEditSession(id, updatedFields) {
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
}
|
| 66 |
|
| 67 |
-
function handleDeleteSession(id) {
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
}
|
| 70 |
|
| 71 |
return (
|
|
@@ -73,32 +121,39 @@ function App() {
|
|
| 73 |
<header className="dashboard-header">
|
| 74 |
<h1>Climbing Dashboard</h1>
|
| 75 |
<p>Log each climbing session and track routes, load, and RPE over time.</p>
|
|
|
|
| 76 |
</header>
|
| 77 |
|
| 78 |
<main className="dashboard-main">
|
| 79 |
-
|
| 80 |
-
<
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
</main>
|
| 103 |
</div>
|
| 104 |
);
|
|
|
|
| 1 |
import { useEffect, useMemo, useState } from 'react';
|
| 2 |
+
import {
|
| 3 |
+
createSession,
|
| 4 |
+
deleteSession,
|
| 5 |
+
loadSessions,
|
| 6 |
+
updateSession,
|
| 7 |
+
} from './utils/storage';
|
| 8 |
import {
|
| 9 |
buildChartData,
|
| 10 |
buildGradeProgressData,
|
|
|
|
| 22 |
import './App.css';
|
| 23 |
|
| 24 |
function App() {
|
| 25 |
+
const [sessions, setSessions] = useState([]);
|
| 26 |
+
const [isLoading, setIsLoading] = useState(true);
|
| 27 |
+
const [syncError, setSyncError] = useState('');
|
| 28 |
|
| 29 |
useEffect(() => {
|
| 30 |
+
let active = true;
|
| 31 |
+
|
| 32 |
+
async function bootstrapSessions() {
|
| 33 |
+
try {
|
| 34 |
+
const loaded = await loadSessions();
|
| 35 |
+
if (active) {
|
| 36 |
+
setSessions(Array.isArray(loaded) ? loaded : []);
|
| 37 |
+
setSyncError('');
|
| 38 |
+
}
|
| 39 |
+
} catch {
|
| 40 |
+
if (active) {
|
| 41 |
+
setSyncError('Could not load shared session data.');
|
| 42 |
+
}
|
| 43 |
+
} finally {
|
| 44 |
+
if (active) setIsLoading(false);
|
| 45 |
+
}
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
bootstrapSessions();
|
| 49 |
+
return () => {
|
| 50 |
+
active = false;
|
| 51 |
+
};
|
| 52 |
+
}, []);
|
| 53 |
|
| 54 |
const today = new Date().toISOString().split('T')[0];
|
| 55 |
const currentWeekKey = getWeekKey(today);
|
|
|
|
| 84 |
const recommendation = computeRecommendation(recentSummaries);
|
| 85 |
const maxRoutes = computeMaxRoutesThreshold(sessions, today);
|
| 86 |
|
| 87 |
+
async function handleAddSession(newSession) {
|
| 88 |
+
const sessionWithId = { ...newSession, id: crypto.randomUUID() };
|
| 89 |
+
|
| 90 |
+
try {
|
| 91 |
+
const created = await createSession(sessionWithId);
|
| 92 |
+
setSessions((prev) => [created, ...prev.filter((session) => session.id !== created.id)]);
|
| 93 |
+
setSyncError('');
|
| 94 |
+
} catch {
|
| 95 |
+
setSyncError('Could not save session.');
|
| 96 |
+
}
|
| 97 |
}
|
| 98 |
|
| 99 |
+
async function handleEditSession(id, updatedFields) {
|
| 100 |
+
try {
|
| 101 |
+
const updated = await updateSession(id, updatedFields);
|
| 102 |
+
setSessions((prev) => prev.map((session) => (session.id === id ? updated : session)));
|
| 103 |
+
setSyncError('');
|
| 104 |
+
} catch {
|
| 105 |
+
setSyncError('Could not update session.');
|
| 106 |
+
}
|
| 107 |
}
|
| 108 |
|
| 109 |
+
async function handleDeleteSession(id) {
|
| 110 |
+
try {
|
| 111 |
+
await deleteSession(id);
|
| 112 |
+
setSessions((prev) => prev.filter((session) => session.id !== id));
|
| 113 |
+
setSyncError('');
|
| 114 |
+
} catch {
|
| 115 |
+
setSyncError('Could not delete session.');
|
| 116 |
+
}
|
| 117 |
}
|
| 118 |
|
| 119 |
return (
|
|
|
|
| 121 |
<header className="dashboard-header">
|
| 122 |
<h1>Climbing Dashboard</h1>
|
| 123 |
<p>Log each climbing session and track routes, load, and RPE over time.</p>
|
| 124 |
+
{syncError && <p className="sync-error">{syncError}</p>}
|
| 125 |
</header>
|
| 126 |
|
| 127 |
<main className="dashboard-main">
|
| 128 |
+
{isLoading ? (
|
| 129 |
+
<p className="loading-message">Loading shared sessions...</p>
|
| 130 |
+
) : (
|
| 131 |
+
<>
|
| 132 |
+
<div className="dashboard-top">
|
| 133 |
+
<ClimbForm onAddSession={handleAddSession} />
|
| 134 |
+
<WeeklySummary
|
| 135 |
+
summary={selectedWeekSummary}
|
| 136 |
+
recommendation={recommendation}
|
| 137 |
+
weekKey={selectedWeekKey}
|
| 138 |
+
isCurrentWeek={selectedWeekKey === currentWeekKey}
|
| 139 |
+
weeksOfData={weeksBeforeSelected.length}
|
| 140 |
+
maxRoutes={maxRoutes}
|
| 141 |
+
hasPrevWeek={hasPrevWeek}
|
| 142 |
+
hasNextWeek={hasNextWeek}
|
| 143 |
+
onPrevWeek={() => hasPrevWeek && setSelectedWeekKey(allWeekKeys[selectedIdx - 1])}
|
| 144 |
+
onNextWeek={() => hasNextWeek && setSelectedWeekKey(allWeekKeys[selectedIdx + 1])}
|
| 145 |
+
/>
|
| 146 |
+
</div>
|
| 147 |
+
|
| 148 |
+
<Charts data={chartData} gradeData={gradeProgressData} painData={painData} />
|
| 149 |
+
|
| 150 |
+
<SessionLog
|
| 151 |
+
sessions={sessions}
|
| 152 |
+
onEditSession={handleEditSession}
|
| 153 |
+
onDeleteSession={handleDeleteSession}
|
| 154 |
+
/>
|
| 155 |
+
</>
|
| 156 |
+
)}
|
| 157 |
</main>
|
| 158 |
</div>
|
| 159 |
);
|
src/App.test.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
| 1 |
-
import { render, screen } from '@testing-library/react';
|
| 2 |
import App from './App';
|
| 3 |
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
render(<App />);
|
| 6 |
const heading = screen.getByRole('heading', { name: /climbing dashboard/i });
|
| 7 |
expect(heading).toBeInTheDocument();
|
|
|
|
|
|
|
|
|
|
| 8 |
});
|
|
|
|
| 1 |
+
import { render, screen, waitFor } from '@testing-library/react';
|
| 2 |
import App from './App';
|
| 3 |
|
| 4 |
+
jest.mock('./utils/storage', () => ({
|
| 5 |
+
loadSessions: jest.fn().mockResolvedValue([]),
|
| 6 |
+
createSession: jest.fn(),
|
| 7 |
+
updateSession: jest.fn(),
|
| 8 |
+
deleteSession: jest.fn(),
|
| 9 |
+
}));
|
| 10 |
+
|
| 11 |
+
test('renders climbing dashboard heading', async () => {
|
| 12 |
render(<App />);
|
| 13 |
const heading = screen.getByRole('heading', { name: /climbing dashboard/i });
|
| 14 |
expect(heading).toBeInTheDocument();
|
| 15 |
+
await waitFor(() =>
|
| 16 |
+
expect(screen.queryByText(/loading shared sessions/i)).not.toBeInTheDocument()
|
| 17 |
+
);
|
| 18 |
});
|
src/utils/storage.js
CHANGED
|
@@ -1,14 +1,40 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
| 9 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
}
|
| 11 |
|
| 12 |
-
export function
|
| 13 |
-
|
|
|
|
|
|
|
| 14 |
}
|
|
|
|
| 1 |
+
async function request(path, options = {}) {
|
| 2 |
+
const response = await fetch(path, {
|
| 3 |
+
headers: {
|
| 4 |
+
'Content-Type': 'application/json',
|
| 5 |
+
...(options.headers || {}),
|
| 6 |
+
},
|
| 7 |
+
...options,
|
| 8 |
+
});
|
| 9 |
+
|
| 10 |
+
if (!response.ok) {
|
| 11 |
+
throw new Error(`API ${response.status}: ${response.statusText}`);
|
| 12 |
}
|
| 13 |
+
|
| 14 |
+
if (response.status === 204) return null;
|
| 15 |
+
return response.json();
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
export async function loadSessions() {
|
| 19 |
+
return request('/api/sessions');
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
export async function createSession(session) {
|
| 23 |
+
return request('/api/sessions', {
|
| 24 |
+
method: 'POST',
|
| 25 |
+
body: JSON.stringify(session),
|
| 26 |
+
});
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
export async function updateSession(id, changes) {
|
| 30 |
+
return request(`/api/sessions/${encodeURIComponent(id)}`, {
|
| 31 |
+
method: 'PUT',
|
| 32 |
+
body: JSON.stringify(changes),
|
| 33 |
+
});
|
| 34 |
}
|
| 35 |
|
| 36 |
+
export async function deleteSession(id) {
|
| 37 |
+
return request(`/api/sessions/${encodeURIComponent(id)}`, {
|
| 38 |
+
method: 'DELETE',
|
| 39 |
+
});
|
| 40 |
}
|