diff --git a/codewit/api/src/main.ts b/codewit/api/src/main.ts index dab9305b..2e94f650 100644 --- a/codewit/api/src/main.ts +++ b/codewit/api/src/main.ts @@ -1,4 +1,4 @@ -import express from 'express'; +import express, { Router } from 'express'; import { sequelize } from './models'; import demoRouter from './routes/demo'; import exerciseRouter from './routes/exercise'; @@ -10,14 +10,28 @@ import userRouter from './routes/user'; import attemptRouter from './routes/attempt'; import passport from 'passport'; import session from 'express-session'; -import { COOKIE_KEY, HOST, PORT } from './secrets'; +import { ENABLE_ASSET_SERVING, COOKIE_KEY, HOST, PORT } from './secrets'; import './auth/passport'; import { checkAuth } from './middleware/auth'; import { catchError, asyncHandle } from "./middleware/catch"; +import { log_request } from "./middleware/logging"; +import { set_request_id } from "./middleware/id"; import { init } from "./utils/id_generator"; +import handler from "serve-handler"; +import { join } from "node:path"; + +const cwd = process.cwd(); + +// we need to serve data from "dist/apps/client" +const assets_dir = join(cwd, "dist/apps/client"); const app = express(); +// ensure that a request id and uuid have been assigned to each inbound http +// request +app.use(set_request_id); +app.use(log_request); + app.use( session({ secret: COOKIE_KEY, @@ -35,22 +49,65 @@ app.use(passport.session()); app.use(express.json()); +// there is a mix of no api prefix requests and api prefix requests that are +// being made when attempting to authorize a user with google. this is to help +// with this but it should be fixed so that the flow is more consistent app.use('/oauth2', authrouter); -app.use('/users', checkAuth, userRouter); -app.use('/demos', checkAuth, demoRouter); -app.use('/exercises', checkAuth, exerciseRouter); -app.use('/modules', checkAuth, moduleRouter); -app.use('/resources', checkAuth, resourceRouter); -app.use('/courses', (req, res, next) => { - if (req.path === '/landing' || req.path === '/landing/') { - return next(); - } +if (ENABLE_ASSET_SERVING) { + // start api configuration ----------------------------------------------------- + + const api_router = Router(); + + api_router.use('/oauth2', authrouter); + + api_router.use('/users', checkAuth, userRouter); + api_router.use('/demos', checkAuth, demoRouter); + api_router.use('/exercises', checkAuth, exerciseRouter); + api_router.use('/modules', checkAuth, moduleRouter); + api_router.use('/resources', checkAuth, resourceRouter); + api_router.use('/attempts', checkAuth, attemptRouter); + + api_router.use('/courses', (req, res, next) => { + if (req.path === '/landing' || req.path === '/landing/') { + return next(); + } + + return checkAuth(req, res, next); + }, courseRouter); + + app.use("/api", api_router); + + + // handle all requests as if they are trying to retrieve UI assets + app.get("/*", async (req, res) => { + await handler(req, res, { + public: assets_dir, + rewrites: [ + { "source": "/**", "destination": "/index.html" } + ] + }); + }); + + // end api configuration ------------------------------------------------------- +} else { + app.use('/users', checkAuth, userRouter); + app.use('/demos', checkAuth, demoRouter); + app.use('/exercises', checkAuth, exerciseRouter); + app.use('/modules', checkAuth, moduleRouter); + app.use('/resources', checkAuth, resourceRouter); + app.use('/attempts', checkAuth, attemptRouter); + + app.use('/courses', (req, res, next) => { + if (req.path === '/landing' || req.path === '/landing/') { + return next(); + } - return checkAuth(req, res, next); -}, courseRouter); -app.use('/attempts', checkAuth, attemptRouter); + return checkAuth(req, res, next); + }, courseRouter); +} +// catch all for dealing with errors app.use(catchError); init() diff --git a/codewit/api/src/middleware/id.ts b/codewit/api/src/middleware/id.ts new file mode 100644 index 00000000..34048848 --- /dev/null +++ b/codewit/api/src/middleware/id.ts @@ -0,0 +1,21 @@ +import { Request, Response, NextFunction } from "express"; +import { v4 as uuidv4 } from "uuid"; + +// a request counter to keep track of the total number of requests +let request_counter = 0; + +// assigns an id and uuid to the provided request, used for tracing a request +// through the server and to other services +export function set_request_id(req: Request, res: Response, next: NextFunction) { + // the current request id count to assign + let id = request_counter += 1; + // the uuid to assign to the request + let uuid = uuidv4(); + + // going to make them functions as to prevent overwriting the values, will + // not stop from overwriting the functions but still + req.id = () => id; + req.uuid = () => uuid; + + next(); +} diff --git a/codewit/api/src/middleware/logging.ts b/codewit/api/src/middleware/logging.ts new file mode 100644 index 00000000..1f80336e --- /dev/null +++ b/codewit/api/src/middleware/logging.ts @@ -0,0 +1,47 @@ +import { Request, Response, NextFunction } from "express"; + +// logs any incoming requests once the request has finished +export function log_request(req: Request, res: Response, next: NextFunction) { + let start = process.hrtime.bigint(); + + // pull the current request id and uuid + let id = req.id(); + let uuid = req.uuid(); + + let ip = req.socket.remoteAddress; + let port = req.socket.remotePort; + let version = req.httpVersion; + let method = req.method; + let path = req.path; + + // when the "finish" event is triggered we will then log the request and + // response because we will have the status code by that time + res.once("finish", () => { + let now = new Date(); + let finish = process.hrtime.bigint(); + let duration = finish - start; + let code = res.statusCode; + let message = res.statusMessage; + + console.log(`${now.toJSON()} ${id}:${uuid} ${ip}:${port} HTTP/${version} ${method} ${path} ${code} ${message} ${format_duration(duration)}`); + }); + + next(); +} + +const TIME_UNITS = ["ns", "μs", "ms", "s"]; + +// simple duration formatter that will convert nanoseconds to a larger unit +// for easier readability +function format_duration(duration: bigint): string { + let index = 0; + let while_check = BigInt(2000); + let div_assign = BigInt(1000); + + while (index < TIME_UNITS.length && duration > while_check) { + duration /= div_assign; + index += 1; + } + + return `${duration}${TIME_UNITS[index]}`; +} diff --git a/codewit/api/src/models/index.ts b/codewit/api/src/models/index.ts index e37affb7..c056ce85 100644 --- a/codewit/api/src/models/index.ts +++ b/codewit/api/src/models/index.ts @@ -17,16 +17,12 @@ import { ModuleDemos } from './moduleDemos'; require('dotenv').config(); -if ( - !process.env.DB_HOST || - !process.env.DB_NAME || - !process.env.DB_USER || - !process.env.DB_PASSWORD || - !process.env.DB_PORT -) { - throw new Error( - 'Please provide the DB_HOST, DB_NAME, DB_USER, DB_PASSWORD, and DB_PORT environment variables' - ); +const required_keys = ["DB_HOST", "DB_NAME", "DB_USER"]; + +for (let key of required_keys) { + if (!(key in process.env)) { + throw new Error(`Missing required database value: "${key}"`); + } } const sequelize = new Sequelize({ @@ -34,8 +30,9 @@ const sequelize = new Sequelize({ database: process.env.DB_NAME, username: process.env.DB_USER, password: process.env.DB_PASSWORD, - port: Number(process.env.DB_PORT), + port: Number(process.env.DB_PORT ?? 5432), dialect: 'postgres', + logging: false, pool: { max: 10, min: 0, diff --git a/codewit/api/src/secrets.ts b/codewit/api/src/secrets.ts index 5b6762bf..020e48b8 100644 --- a/codewit/api/src/secrets.ts +++ b/codewit/api/src/secrets.ts @@ -1,3 +1,11 @@ +function check_if_boolean(value: string): boolean { + switch (value.toLowerCase()) { + case "true": return true; + case "false": return false; + default: return false + } +} + const HOST = process.env.API_HOST ?? '0.0.0.0'; const PORT = process.env.PORT ? Number(process.env.PORT) : 3000; const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID; @@ -5,6 +13,7 @@ const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET; const GOOGLE_REDIRECT_URL = process.env.GOOGLE_REDIRECT_URL; const COOKIE_KEY = process.env.COOKIE_KEY as string; const FRONTEND_URL = process.env.FRONTEND_URL; +const ENABLE_ASSET_SERVING = check_if_boolean(process.env.ENABLE_ASSET_SERVING ?? ""); export { HOST, @@ -14,4 +23,5 @@ export { GOOGLE_REDIRECT_URL, COOKIE_KEY, FRONTEND_URL, + ENABLE_ASSET_SERVING, }; diff --git a/codewit/api/src/typings/index.d.ts b/codewit/api/src/typings/index.d.ts index e209dea0..3192761f 100644 --- a/codewit/api/src/typings/index.d.ts +++ b/codewit/api/src/typings/index.d.ts @@ -4,5 +4,17 @@ declare global { namespace Express { // eslint-disable-next-line @typescript-eslint/no-empty-interface interface User extends UserDocument {} + + export interface Request { + // retrieves the current request id + // + // represents the total number of requests handled + id: () => number, + + // retrieves the current request uuid + // + // used for tracing requests to other servers (eg codeval) + uuid: () => string, + } } } diff --git a/codewit/client/vite.config.ts b/codewit/client/vite.config.ts index a08b6d7b..2422ceb5 100644 --- a/codewit/client/vite.config.ts +++ b/codewit/client/vite.config.ts @@ -56,9 +56,6 @@ export default defineConfig(({ mode }) => ({ '/api': { target: API_TARGET, changeOrigin: true, - rewrite: usingGatewayProxy - ? undefined - : (path) => path.replace(/^\/api/, ''), }, '/codeeval': { target: CODEEVAL_TARGET, diff --git a/codewit/docker-compose.yml b/codewit/docker-compose.yml index 50f42611..c7065686 100644 --- a/codewit/docker-compose.yml +++ b/codewit/docker-compose.yml @@ -32,6 +32,7 @@ services: - PORT=3000 - FRONTEND_URL=http://localhost:3001 - NODE_ENV=dev + - ENABLE_ASSET_SERVING=true env_file: - .env restart: unless-stopped diff --git a/codewit/package-lock.json b/codewit/package-lock.json index 502ec6c7..74730d60 100644 --- a/codewit/package-lock.json +++ b/codewit/package-lock.json @@ -49,9 +49,11 @@ "remark-gfm": "^4.0.0", "sequelize": "^6.36.0", "sequelize-cli": "^6.6.1", + "serve-handler": "6.1.7", "tailwind-merge": "^2.6.0", "tslib": "^2.3.0", "unique-names-generator": "^4.7.1", + "uuid": "14.0.0", "zod": "^3.22.4", "zod-validation-error": "^3.0.3" }, @@ -228,7 +230,6 @@ "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", @@ -2460,7 +2461,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.24.1.tgz", "integrity": "sha512-sBfP4rniPBRQzNakwuQEqjEuiJDWJyF2kqLLqij4WXRoVwPPJfjx966Eq3F7+OPQxDtMt/Q9MWLoZLWjeveBlg==", - "peer": true, "dependencies": { "@codemirror/state": "^6.4.0", "style-mod": "^4.1.0", @@ -2535,6 +2535,16 @@ "node": ">=16" } }, + "node_modules/@cypress/request/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@cypress/xvfb": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", @@ -2569,7 +2579,6 @@ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "license": "MIT", - "peer": true, "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -4849,7 +4858,6 @@ "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", "license": "MIT", - "peer": true, "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -4980,7 +4988,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -4993,7 +5000,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -5006,7 +5012,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -5019,7 +5024,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -5032,7 +5036,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5045,7 +5048,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5058,7 +5060,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5071,7 +5072,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5084,7 +5084,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5097,7 +5096,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5110,7 +5108,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -5123,7 +5120,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -5136,7 +5132,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -5567,7 +5562,6 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dev": true, - "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -5740,7 +5734,6 @@ "resolved": "https://registry.npmjs.org/@swc-node/register/-/register-1.6.8.tgz", "integrity": "sha512-74ijy7J9CWr1Z88yO+ykXphV29giCrSpANQPQRooE0bObpkTO1g4RzQovIfbIaniBiGDDVsYwDoQ3FIrCE8HcQ==", "devOptional": true, - "peer": true, "dependencies": { "@swc-node/core": "^1.10.6", "@swc-node/sourcemap-support": "^0.3.0", @@ -5834,7 +5827,6 @@ "integrity": "sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==", "devOptional": true, "hasInstallScript": true, - "peer": true, "dependencies": { "@swc/counter": "^0.1.1", "@swc/types": "^0.1.5" @@ -6036,8 +6028,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", - "devOptional": true, - "peer": true + "devOptional": true }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", @@ -6375,7 +6366,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.11.tgz", "integrity": "sha512-3uyzz01D1fkTLXuxF3JfoJoHQMU2fxsfJwE+6N5hHy0dVNoZOvwKP8Z2k7k1KDeD54N20apcJnG75TBAStIrBA==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/query-core": "5.90.11" }, @@ -6895,7 +6885,6 @@ "version": "18.2.33", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz", "integrity": "sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==", - "peer": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -6906,7 +6895,6 @@ "version": "18.2.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz", "integrity": "sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==", - "peer": true, "dependencies": { "@types/react": "*" } @@ -7080,7 +7068,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz", "integrity": "sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==", "dev": true, - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.20.0", "@typescript-eslint/types": "6.20.0", @@ -7650,7 +7637,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7711,7 +7697,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -8612,7 +8597,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -8978,7 +8962,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "peer": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -9546,8 +9529,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "peer": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/csv-parse": { "version": "6.1.0", @@ -10354,7 +10336,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "peer": true, "dependencies": { "ansi-colors": "^4.1.1" }, @@ -10527,7 +10508,6 @@ "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "dev": true, "hasInstallScript": true, - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -10585,7 +10565,6 @@ "version": "8.48.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -10640,7 +10619,6 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -11400,7 +11378,6 @@ "version": "1.18.0", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", - "peer": true, "dependencies": { "cookie": "0.6.0", "cookie-signature": "1.0.7", @@ -13701,7 +13678,6 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -14422,7 +14398,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "peer": true, "dependencies": { "argparse": "^2.0.1" }, @@ -14440,7 +14415,6 @@ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", "dev": true, - "peer": true, "dependencies": { "abab": "^2.0.6", "cssstyle": "^3.0.0", @@ -15981,8 +15955,7 @@ "node_modules/monaco-editor": { "version": "0.46.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.46.0.tgz", - "integrity": "sha512-ADwtLIIww+9FKybWscd7OCfm9odsFYHImBRI1v9AviGce55QY8raT+9ihH8jX/E/e6QVSGM+pKj4jSUSRmALNQ==", - "peer": true + "integrity": "sha512-ADwtLIIww+9FKybWscd7OCfm9odsFYHImBRI1v9AviGce55QY8raT+9ihH8jX/E/e6QVSGM+pKj4jSUSRmALNQ==" }, "node_modules/mrmime": { "version": "2.0.0", @@ -16178,7 +16151,6 @@ "integrity": "sha512-AtcM7JmBC82O17WMxuu9JJxEKTcsMII1AMgxCeiCWcW22wHd3EhIn5Hg1iSFv9ftkSSd8YgHeqTciRbdTqbxpA==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@nrwl/tao": "18.0.1", "@yarnpkg/lockfile": "^1.1.0", @@ -16736,6 +16708,12 @@ "node": ">=0.10.0" } }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -16829,7 +16807,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", - "peer": true, "dependencies": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", @@ -17078,7 +17055,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -17534,7 +17510,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -17546,7 +17521,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -18394,7 +18368,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==", "devOptional": true, - "peer": true, "dependencies": { "@types/estree": "1.0.5" }, @@ -18785,12 +18758,21 @@ "node": ">= 10.0.0" } }, + "node_modules/sequelize/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/seroval": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -18807,6 +18789,97 @@ "seroval": "^1.0" } }, + "node_modules/serve-handler": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.7.tgz", + "integrity": "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==", + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.5", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/serve-handler/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-handler/node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/serve-handler/node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -19010,7 +19083,6 @@ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz", "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -19600,7 +19672,6 @@ "version": "3.4.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -20230,7 +20301,6 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -20577,11 +20647,16 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/v8-compile-cache-lib": { @@ -20687,7 +20762,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz", "integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==", "dev": true, - "peer": true, "dependencies": { "esbuild": "^0.19.3", "postcss": "^8.4.32", @@ -20831,7 +20905,6 @@ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.2.2.tgz", "integrity": "sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==", "dev": true, - "peer": true, "dependencies": { "@vitest/expect": "1.2.2", "@vitest/runner": "1.2.2", @@ -21402,7 +21475,6 @@ "version": "3.22.4", "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/codewit/package.json b/codewit/package.json index 8b95443a..adebd01e 100644 --- a/codewit/package.json +++ b/codewit/package.json @@ -58,9 +58,11 @@ "remark-gfm": "^4.0.0", "sequelize": "^6.36.0", "sequelize-cli": "^6.6.1", + "serve-handler": "6.1.7", "tailwind-merge": "^2.6.0", "tslib": "^2.3.0", "unique-names-generator": "^4.7.1", + "uuid": "14.0.0", "zod": "^3.22.4", "zod-validation-error": "^3.0.3" },