From 36ec8da1a07f194ad014c5a134eaef9e701aa0f7 Mon Sep 17 00:00:00 2001 From: Theis Gaedigk Date: Wed, 8 Jul 2026 10:27:21 +0200 Subject: [PATCH] Fix: cast DB row to AuthTokenPayload in findUser\n\nCast database RowDataPacket to AuthTokenPayload so generateToken receives the correct type.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- backend/misc/types.ts | 0 ...ducts.database.js => products.database.ts} | 42 +- ...torage.database.js => storage.database.ts} | 18 +- backend/routes/app/database/users.database.js | 91 -- backend/routes/app/database/users.database.ts | 132 +++ .../{products.route.js => products.route.ts} | 132 +-- .../{storage.route.js => storage.route.ts} | 97 +- backend/routes/app/users.route.js | 135 --- backend/routes/app/users.route.ts | 129 +++ backend/services/helperFuncs.ts | 9 + .../{tokenService.js => tokenService.ts} | 0 backend/vite.config.ts | 0 eslint.config.mjs | 0 shared/package-lock.json | 948 ++++++++++++++++++ shared/package.json | 0 shared/src/error/errorcodes.enum.ts | 4 + shared/tsconfig.json | 44 + shared/vite.config.ts | 15 + 18 files changed, 1429 insertions(+), 367 deletions(-) create mode 100644 backend/misc/types.ts rename backend/routes/app/database/{products.database.js => products.database.ts} (80%) rename backend/routes/app/database/{storage.database.js => storage.database.ts} (77%) delete mode 100644 backend/routes/app/database/users.database.js create mode 100644 backend/routes/app/database/users.database.ts rename backend/routes/app/{products.route.js => products.route.ts} (63%) rename backend/routes/app/{storage.route.js => storage.route.ts} (61%) delete mode 100644 backend/routes/app/users.route.js create mode 100644 backend/routes/app/users.route.ts create mode 100644 backend/services/helperFuncs.ts rename backend/services/{tokenService.js => tokenService.ts} (100%) create mode 100644 backend/vite.config.ts create mode 100644 eslint.config.mjs create mode 100644 shared/package-lock.json create mode 100644 shared/package.json create mode 100644 shared/src/error/errorcodes.enum.ts create mode 100644 shared/tsconfig.json create mode 100644 shared/vite.config.ts diff --git a/backend/misc/types.ts b/backend/misc/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/backend/routes/app/database/products.database.js b/backend/routes/app/database/products.database.ts similarity index 80% rename from backend/routes/app/database/products.database.js rename to backend/routes/app/database/products.database.ts index f6cd75d..48be2db 100644 --- a/backend/routes/app/database/products.database.js +++ b/backend/routes/app/database/products.database.ts @@ -1,5 +1,8 @@ import mysql from "mysql2"; import dotenv from "dotenv"; +import {PRODUCT_ERROR_CODE} from "@stockhome/shared"; +import {returnErrorCode} from "../../../services/helperFuncs.js"; + dotenv.config(); const pool = mysql @@ -20,12 +23,7 @@ export const newProduct = async ( expiry_date, bottling_date, ) => { - let newPrice; - if (price == "") { - newPrice = null; - } else { - newPrice = price; - } + const newPrice = price !== "" ? price : null; const [result] = await pool.query( "INSERT INTO products (name, description, price, amount, storage_location, expiry_date, bottling_date) VALUES (?, ?, ?, ?, UUID_TO_BIN(?), ?, ?)", @@ -41,10 +39,10 @@ export const newProduct = async ( ); if (result.affectedRows > 0) { - return { code: "sp001" }; // success - } else { - return { code: "ep001" }; // error + return { code: "sp001" }; } + + return returnErrorCode(PRODUCT_ERROR_CODE.PRODUCT_NOT_CREATED); }; export const productDetails = async (uuid) => { @@ -68,9 +66,9 @@ export const productDetails = async (uuid) => { if (result.length > 0) { return { code: "sp003", data: result[0] }; - } else { - return { code: "ep003" }; } + + return returnErrorCode(PRODUCT_ERROR_CODE.PRODUCT_NOT_FOUND); }; export const allProducts = async () => { @@ -95,9 +93,9 @@ export const allProducts = async () => { if (result.length > 0) { return { code: "sp002", data: result }; - } else { - return { code: "ep002" }; } + + return returnErrorCode(PRODUCT_ERROR_CODE.NO_PRODUCTS_FOUND); }; export const setAmount = async (itemUUID, amount) => { @@ -109,10 +107,10 @@ export const setAmount = async (itemUUID, amount) => { ); if (result.affectedRows > 0) { - return { code: "sp004" }; // success - } else { - return { code: "ep004" }; // error + return { code: "sp004" }; } + + return returnErrorCode(PRODUCT_ERROR_CODE.PRODUCT_AMOUNT_NOT_UPDATED); }; export const updateItem = async (itemUUID, newValues) => { @@ -133,10 +131,10 @@ export const updateItem = async (itemUUID, newValues) => { ); if (result.affectedRows > 0) { - return { code: "sp005" }; // success - } else { - return { code: "ep005" }; // error + return { code: "sp005" }; } + + return returnErrorCode(PRODUCT_ERROR_CODE.PRODUCT_NOT_UPDATED); }; export const deleteProduct = async (uuid) => { @@ -146,8 +144,8 @@ export const deleteProduct = async (uuid) => { ); if (result.affectedRows > 0) { - return { code: "sp006" }; // success - } else { - return { code: "ep006" }; // error + return { code: "sp006" }; } + + return returnErrorCode(PRODUCT_ERROR_CODE.PRODUCT_NOT_DELETED); }; diff --git a/backend/routes/app/database/storage.database.js b/backend/routes/app/database/storage.database.ts similarity index 77% rename from backend/routes/app/database/storage.database.js rename to backend/routes/app/database/storage.database.ts index 035d191..72e0ab4 100644 --- a/backend/routes/app/database/storage.database.js +++ b/backend/routes/app/database/storage.database.ts @@ -1,5 +1,7 @@ import mysql from "mysql2"; import dotenv from "dotenv"; +import {STORAGE_ERROR_CODE} from "@stockhome/shared"; +import {returnErrorCode} from "../../../services/helperFuncs.js"; dotenv.config(); const pool = mysql @@ -18,9 +20,9 @@ export const allStorages = async () => { if (result.length > 0) { return { code: "ss001", data: result }; - } else { - return { code: "es001" }; } + + return returnErrorCode(STORAGE_ERROR_CODE.NO_STORAGE_LOCATIONS_FOUND); }; export const newStorage = async (name, description) => { @@ -31,9 +33,9 @@ export const newStorage = async (name, description) => { if (result.affectedRows > 0) { return { code: "ss002" }; - } else { - return { code: "es002" }; } + + return returnErrorCode(STORAGE_ERROR_CODE.STORAGE_NOT_CREATED); }; export const updateStorage = async (uuid, values) => { @@ -44,9 +46,9 @@ export const updateStorage = async (uuid, values) => { if (result.affectedRows > 0) { return { code: "ss003" }; - } else { - return { code: "es003" }; } + + return returnErrorCode(STORAGE_ERROR_CODE.STORAGE_NOT_UPDATED); }; export const deleteStorage = async (uuid) => { @@ -57,7 +59,7 @@ export const deleteStorage = async (uuid) => { if (result.affectedRows > 0) { return { code: "ss004" }; - } else { - return { code: "es004" }; } + + return returnErrorCode(STORAGE_ERROR_CODE.STORAGE_NOT_DELETED); }; diff --git a/backend/routes/app/database/users.database.js b/backend/routes/app/database/users.database.js deleted file mode 100644 index aec4ea4..0000000 --- a/backend/routes/app/database/users.database.js +++ /dev/null @@ -1,91 +0,0 @@ -import mysql from "mysql2"; -import dotenv from "dotenv"; -dotenv.config(); - -const pool = mysql - .createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_NAME, - }) - .promise(); - -export const findUser = async (username, password) => { - const [result] = await pool.query( - "SELECT BIN_TO_UUID(uuid) AS uuid, username, first_name, last_name, email, is_admin, is_active, last_login FROM users WHERE username = ? AND password = ?;", - [username, password], - ); - - if (result.length <= 0) { - return { code: "eu001" }; // username or password is wrong - } - - if (!result[0].is_active) { - return { code: "eu002" }; // user is deactivated - } - - return { code: "su001", data: result[0] }; // user found -}; - -export const loginUser = async (username) => { - const [result] = await pool.query( - "UPDATE users SET last_login = NOW() WHERE username = ?;", - [username], - ); - - if (result.affectedRows > 0) { - return { code: "su002" }; - } else { - return { code: "eu003" }; - } -}; - -export const updateSettings = async (payload) => { - const appName = payload["app-name"]; - const currency = payload.currency; - - const [result] = await pool.query( - `UPDATE app_settings - SET value = CASE name - WHEN "app-name" THEN ? - WHEN "currency" THEN ? - ELSE value - END - WHERE name IN ("app-name", "currency");`, - [appName, currency], - ); - - if (result.affectedRows > 0) { - return { code: "su003" }; - } else { - return { code: "eu004" }; - } -}; - -export const getSettings = async () => { - const [result] = await pool.query(`SELECT * FROM app_settings;`); - - if (result.length > 0) { - return { code: "su004", result }; - } else { - return { code: "eu005" }; - } -}; - -export const changePassword = async ( - username, - currentPasswordUser, - newPassword, -) => { - const [result] = await pool.query( - `UPDATE users SET password = ? WHERE username = ? AND password = ?;`, - [newPassword, username, currentPasswordUser], - ); - - if (result.affectedRows > 0) { - return { code: "su005" }; - } else { - return { code: "eu006" }; - } -}; diff --git a/backend/routes/app/database/users.database.ts b/backend/routes/app/database/users.database.ts new file mode 100644 index 0000000..abd1c77 --- /dev/null +++ b/backend/routes/app/database/users.database.ts @@ -0,0 +1,132 @@ +import mysql, {type ResultSetHeader, type RowDataPacket} from "mysql2/promise"; +import dotenv from "dotenv"; +import {GENERAL_ERROR_CODE, USER_ERROR_CODE} from "@stockhome/shared"; +import {returnErrorCode} from "../../../services/helperFuncs.js"; +import type { AuthTokenPayload } from "../../../services/tokenService"; + +dotenv.config(); + +const pool = mysql.createPool({ + host: process.env.DB_HOST!, + user: process.env.DB_USER!, + password: process.env.DB_PASSWORD!, + database: process.env.DB_NAME!, +}); + +export const findUser = async (username: string, password: string) => { + const [result] = await pool.query( + "SELECT BIN_TO_UUID(uuid) AS uuid, username, first_name, last_name, email, is_admin, is_active, last_login FROM users WHERE username = ? AND password = ?;", + [username, password], + ); + + const userRow = result[0]; + + if (!userRow) { + return returnErrorCode(USER_ERROR_CODE.WRONG_USERNAME_PASSWORD); + } + + // Cast DB row to AuthTokenPayload for token generation / typing + const user = userRow as unknown as AuthTokenPayload; + + if (!user.is_active) { + return returnErrorCode(USER_ERROR_CODE.USER_IS_DEACTIVATED); + } + + return { + success: true, + code: "SU001", + data: user, + message: "Successfully found user.", + }; +}; + +export const loginUser = async (username: string) => { + const [result] = await pool.query( + "UPDATE users SET last_login = NOW() WHERE username = ?;", + [username], + ); + + if (result.affectedRows > 0) { + return { + success: true, + code: "SU002", + data: null, + message: "Successfully logged in user.", + }; + } else { + return returnErrorCode(GENERAL_ERROR_CODE.UNEXPECTED_SERVER_ERROR); + } +}; + +export const updateSettings = async (payload: { + "app-name": string; + currency: string; +}) => { + const appName = payload["app-name"]; + const currency = payload.currency; + + const [result] = await pool.query( + `UPDATE app_settings + SET value = CASE name + WHEN "app-name" THEN ? + WHEN "currency" THEN ? + ELSE value + END + WHERE name IN ("app-name", "currency");`, + [appName, currency], + ); + + if (result.affectedRows > 0) { + return { + success: true, + code: "SU003", + data: null, + message: "Successfully updated settings.", + }; + } else { + return returnErrorCode(GENERAL_ERROR_CODE.UNEXPECTED_SERVER_ERROR); + } +}; + +export const getSettings = async () => { + const [result] = await pool.query( + `SELECT * + FROM app_settings;`, + ); + + if (result.length > 0) { + return { + success: true, + code: "SU004", + data: result, + message: "Successfully fetched settings.", + }; + } else { + return returnErrorCode(GENERAL_ERROR_CODE.UNEXPECTED_SERVER_ERROR); + } +}; + +export const changePassword = async ( + username: string, + currentPasswordUser: string, + newPassword: string, +) => { + const [result] = await pool.query( + `UPDATE users + SET password = ? + WHERE username = ? + AND password = ?;`, + [newPassword, username, currentPasswordUser], + ); + + if (result.affectedRows > 0) { + return { + success: true, + code: "SU005", + data: null, + message: "Successfully fetched settings.", + }; + } else { + return returnErrorCode(GENERAL_ERROR_CODE.UNEXPECTED_SERVER_ERROR); + } +}; \ No newline at end of file diff --git a/backend/routes/app/products.route.js b/backend/routes/app/products.route.ts similarity index 63% rename from backend/routes/app/products.route.js rename to backend/routes/app/products.route.ts index fbe2eb1..4034865 100644 --- a/backend/routes/app/products.route.js +++ b/backend/routes/app/products.route.ts @@ -1,6 +1,6 @@ import express from "express"; import dotenv from "dotenv"; -import { authenticate } from "../../services/tokenService.js"; +import {authenticate} from "../../services/tokenService.js"; import { allProducts, deleteProduct, @@ -8,7 +8,9 @@ import { productDetails, setAmount, updateItem, -} from "./database/products.database.js"; +} from "./database/products.database.ts"; +import {PRODUCT_ERROR_CODE} from "@stockhome/shared"; + dotenv.config(); const router = express.Router(); @@ -33,45 +35,50 @@ router.post("/new-product", authenticate, async (req, res) => { bottling_date, ); - if (result.code === "ep001") { - res.status(406).json({ - success: false, - code: "ep001", - data: null, - message: "Error while creating product", - }); - } - if (result.code === "sp001") { - res.status(201).json({ + return res.status(201).json({ success: true, code: "sp001", data: null, message: "", }); } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.get("/all-products", authenticate, async (req, res) => { const result = await allProducts(); - if (result.code === "ep002") { - res.status(406).json({ - success: false, - code: "ep002", - data: null, - message: "Error while fetching products", - }); - } - if (result.code === "sp002") { - res.status(200).json({ + return res.status(200).json({ success: true, code: "sp002", data: result.data, message: "", }); } + + if (result.code === PRODUCT_ERROR_CODE.NO_PRODUCTS_FOUND[0]) { + return res.status(404).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); + } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.get("/view", async (req, res) => { @@ -79,23 +86,30 @@ router.get("/view", async (req, res) => { const result = await productDetails(uuid); - if (result.code === "ep003") { - res.status(406).json({ - success: false, - code: "ep003", - data: null, - message: "Error while fetching product", - }); - } - if (result.code === "sp003") { - res.status(200).json({ + return res.status(200).json({ success: true, code: "sp003", data: result.data, message: "", }); } + + if (result.code === PRODUCT_ERROR_CODE.PRODUCT_NOT_FOUND[0]) { + return res.status(404).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); + } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.put("/mutate/set-amount", authenticate, async (req, res) => { @@ -104,23 +118,21 @@ router.put("/mutate/set-amount", authenticate, async (req, res) => { const result = await setAmount(itemUUID, amount); - if (result.code === "ep004") { - res.status(406).json({ - success: false, - code: "ep004", - data: null, - message: "Error while updating product amount", - }); - } - if (result.code === "sp004") { - res.status(200).json({ + return res.status(200).json({ success: true, code: "sp004", data: null, message: "", }); } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.post("/mutate/update-item", async (req, res) => { @@ -129,23 +141,21 @@ router.post("/mutate/update-item", async (req, res) => { const result = await updateItem(itemUUID, newValues); - if (result.code === "ep005") { - res.status(406).json({ - success: false, - code: "ep005", - data: null, - message: "Error while updating product", - }); - } - if (result.code === "sp005") { - res.status(200).json({ + return res.status(200).json({ success: true, code: "sp005", data: null, message: "", }); } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.post("/delete-selection", authenticate, async (req, res) => { @@ -154,27 +164,27 @@ router.post("/delete-selection", authenticate, async (req, res) => { for (const uuid of uuidArray) { const response = await deleteProduct(uuid); - if (response.code === "ep006" || !response) { + if (!response || response.code !== "sp006") { isError = true; break; } } if (isError === false) { - res.status(202).json({ + return res.status(202).json({ success: true, code: "sp006", data: null, message: "", }); - } else { - res.status(500).json({ - success: false, - code: "ep006", - data: null, - message: "", - }); } + + return res.status(500).json({ + success: false, + code: PRODUCT_ERROR_CODE.PRODUCT_NOT_DELETED[0], + data: null, + message: PRODUCT_ERROR_CODE.PRODUCT_NOT_DELETED[1], + }); }); export default router; diff --git a/backend/routes/app/storage.route.js b/backend/routes/app/storage.route.ts similarity index 61% rename from backend/routes/app/storage.route.js rename to backend/routes/app/storage.route.ts index d2fb690..7fbe54b 100644 --- a/backend/routes/app/storage.route.js +++ b/backend/routes/app/storage.route.ts @@ -1,35 +1,39 @@ import express from "express"; import dotenv from "dotenv"; -import { authenticate } from "../../services/tokenService.js"; -import { - allStorages, - newStorage, - updateStorage, - deleteStorage, -} from "./database/storage.database.js"; +import {authenticate} from "../../services/tokenService.js"; +import {allStorages, deleteStorage, newStorage, updateStorage,} from "./database/storage.database.ts"; +import {STORAGE_ERROR_CODE} from "@stockhome/shared"; + dotenv.config(); const router = express.Router(); router.get("/all-storages", authenticate, async (req, res) => { const result = await allStorages(); - if (result.code === "es001") { - res.status(500).json({ - success: false, - code: "es001", - data: null, - message: "unexpected server error", - }); - } - if (result.code === "ss001") { - res.status(200).json({ + return res.status(200).json({ success: true, code: "ss001", data: result.data, message: "", }); } + + if (result.code === STORAGE_ERROR_CODE.NO_STORAGE_LOCATIONS_FOUND[0]) { + return res.status(404).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); + } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.post("/new-storage", authenticate, async (req, res) => { @@ -38,13 +42,12 @@ router.post("/new-storage", authenticate, async (req, res) => { let desc = description; if (!name) { - res.status(400).json({ + return res.status(400).json({ success: false, - code: "es000", + code: STORAGE_ERROR_CODE.INVALID_REQUEST_BODY[0], data: null, message: "invalid request body", }); - return; } if (description == "") { @@ -53,23 +56,21 @@ router.post("/new-storage", authenticate, async (req, res) => { const result = await newStorage(name, desc); - if (result.code === "es002") { - res.status(500).json({ - success: false, - code: "es002", - data: null, - message: "unexpected server error", - }); - } - if (result.code === "ss002") { - res.status(201).json({ + return res.status(201).json({ success: true, code: "ss002", data: null, message: "", }); } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.post("/update-storage", authenticate, async (req, res) => { @@ -78,23 +79,21 @@ router.post("/update-storage", authenticate, async (req, res) => { const result = await updateStorage(storageUUID, values); - if (result.code === "es003") { - res.status(500).json({ - success: false, - code: "es003", - data: null, - message: "unexpected server error", - }); - } - if (result.code === "ss003") { - res.status(201).json({ + return res.status(201).json({ success: true, code: "ss003", data: null, message: "", }); } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); router.delete("/delete", authenticate, async (req, res) => { @@ -102,23 +101,21 @@ router.delete("/delete", authenticate, async (req, res) => { const result = await deleteStorage(uuid); - if (result.code === "es004") { - res.status(500).json({ - success: false, - code: "es004", - data: null, - message: "unexpected server error", - }); - } - if (result.code === "ss004") { - res.status(201).json({ + return res.status(201).json({ success: true, code: "ss004", data: null, message: "", }); } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); }); export default router; diff --git a/backend/routes/app/users.route.js b/backend/routes/app/users.route.js deleted file mode 100644 index 94cec80..0000000 --- a/backend/routes/app/users.route.js +++ /dev/null @@ -1,135 +0,0 @@ -import express from "express"; -import dotenv from "dotenv"; -import { authenticate, generateToken } from "../../services/tokenService.js"; -import { - findUser, - loginUser, - updateSettings, - getSettings, - changePassword, -} from "./database/users.database.js"; -dotenv.config(); -const router = express.Router(); - -router.post("/verify-token", authenticate, async (req, res) => { - res.sendStatus(200); -}); - -router.post("/update-app-settings", authenticate, async (req, res) => { - const appName = req.body.appName; - const currency = req.body.currency; - - const result = await updateSettings(req.body); - - if (result.code === "su003") { - res.status(201).json({ - success: true, - code: "su003", - data: result.data, - message: null, - }); - } - - if (result.code === "eu004") { - res.status(500).json({ - success: false, - code: "eu004", - data: null, - message: "Unexpected server error", - }); - } -}); - -router.get("/settings", authenticate, async (req, res) => { - const result = await getSettings(); - - if (result.code === "su004") { - res.status(201).json({ - success: true, - code: "su004", - data: result.result, - message: null, - }); - } - - if (result.code === "eu005") { - res.status(500).json({ - success: false, - code: "eu005", - data: null, - message: "Unexpected server error", - }); - } -}); - -router.post("/login", async (req, res) => { - const username = req.body.username; - const password = req.body.password; - - const result = await findUser(username, password); - - if (result.code === "eu001") { - res.status(404).json({ - success: false, - code: "eu001", - data: null, - message: "username oder password is wrong", - }); - } - - if (result.code === "eu002") { - res.status(403).json({ - success: false, - code: "eu002", - data: null, - message: "user is deactivated", - }); - } - - if (result.code === "su001") { - const token = await generateToken(result.data); - const login = await loginUser(result.data.username); - - if (login.code === "eu003") { - res.status(500).json({ - success: false, - code: "eu003", - data: null, - message: "Unexpected server error. Please contact system admin.", - }); - } - - res.status(202).json({ - success: true, - code: "su001", - data: { - token, - }, - message: "User token generated successfully", - }); - } -}); - -router.post("/change-password", authenticate, async (req, res) => { - const currentPassword = req.body.currentPassword; - const newPassword = req.body.newPassword; - const username = req.user.username; - - const result = await changePassword(username, currentPassword, newPassword); - - if (result.code === "su005") { - res.status(202).json({ - success: true, - code: result.code, - }); - } - - if (result.code === "eu006") { - res.status(406).json({ - success: false, - code: result.code, - }); - } -}); - -export default router; diff --git a/backend/routes/app/users.route.ts b/backend/routes/app/users.route.ts new file mode 100644 index 0000000..274c0a8 --- /dev/null +++ b/backend/routes/app/users.route.ts @@ -0,0 +1,129 @@ +import express from "express"; +import dotenv from "dotenv"; +import {authenticate, generateToken} from "../../services/tokenService.js"; +import {changePassword, findUser, getSettings, loginUser, updateSettings,} from "./database/users.database.ts"; + +dotenv.config(); +const router = express.Router(); + +router.post("/verify-token", authenticate, async (req, res) => { + res.sendStatus(200); +}); + +router.post("/update-app-settings", authenticate, async (req, res) => { + const result = await updateSettings(req.body); + + if (result.code === "su003") { + return res.status(201).json({ + success: true, + code: "su003", + data: result.data, + message: null, + }); + } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); +}); + +router.get("/settings", authenticate, async (req, res) => { + const result = await getSettings(); + + if (result.code === "su004") { + return res.status(200).json({ + success: true, + code: "su004", + data: result.data, + message: null, + }); + } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); +}); + +router.post("/login", async (req, res) => { + const username = req.body.username; + const password = req.body.password; + + const result = await findUser(username, password); + + if (result.code === "EU001") { + return res.status(404).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); + } + + if (result.code === "EU002") { + return res.status(403).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); + } + + if (result.code === "su001") { + const token = await generateToken(result.data); + const login = await loginUser(result.data.username); + + if (login.code !== "su002") { + return res.status(500).json({ + success: false, + code: login.code, + data: null, + message: login.message, + }); + } + + return res.status(202).json({ + success: true, + code: "su001", + data: { + token, + }, + message: "User token generated successfully", + }); + } + + return res.status(500).json({ + success: false, + code: result.code, + data: null, + message: result.message, + }); +}); + +router.post("/change-password", authenticate, async (req, res) => { + const currentPassword = req.body.currentPassword; + const newPassword = req.body.newPassword; + const username = req.user.username; + + const result = await changePassword(username, currentPassword, newPassword); + + if (result.code === "su005") { + return res.status(202).json({ + success: true, + code: result.code, + }); + } + + return res.status(500).json({ + success: false, + code: result.code, + message: result.message, + }); +}); + +export default router; diff --git a/backend/services/helperFuncs.ts b/backend/services/helperFuncs.ts new file mode 100644 index 0000000..7ae1f96 --- /dev/null +++ b/backend/services/helperFuncs.ts @@ -0,0 +1,9 @@ +export const returnErrorCode = (errorKey) => { + if (!Array.isArray(errorKey) || errorKey.length < 2) { + return false; + } + + return {code: errorKey[0], message: errorKey[1], data: null}; +}; + +export default returnErrorCode; \ No newline at end of file diff --git a/backend/services/tokenService.js b/backend/services/tokenService.ts similarity index 100% rename from backend/services/tokenService.js rename to backend/services/tokenService.ts diff --git a/backend/vite.config.ts b/backend/vite.config.ts new file mode 100644 index 0000000..e69de29 diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..e69de29 diff --git a/shared/package-lock.json b/shared/package-lock.json new file mode 100644 index 0000000..2942109 --- /dev/null +++ b/shared/package-lock.json @@ -0,0 +1,948 @@ +{ + "name": "shared", + "version": "0.0.0-dev", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "shared", + "version": "0.0.0-dev", + "devDependencies": { + "barrelsby": "^2.8.1", + "vite-plugin-dts": "^5.0.3" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/barrelsby": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/barrelsby/-/barrelsby-2.8.1.tgz", + "integrity": "sha512-barN2MVKqUVwmjRy3JLSMYufrBDcdWUc2pjlR0V9P8S3aMvvJ4StFz1GJMzEi5GBoQlnBIWOcCxBDzI2xfaaGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs": "^17.0.10", + "signale": "^1.4.0", + "yargs": "^17.4.1" + }, + "bin": { + "barrelsby": "bin/cli.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.0.tgz", + "integrity": "sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==", + "dev": true, + "license": "MIT" + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/local-pkg": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", + "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-dts": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/unplugin-dts/-/unplugin-dts-1.0.3.tgz", + "integrity": "sha512-/GR887wfG4r1cWyt1UZsLRuMIjsmEbGkS9yJrz+0dsToHAYUD5CTyP3JMGVLv25j9K0mJcwAVvZno/aTuSUvNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.4", + "@volar/typescript": "^2.4.26", + "compare-versions": "^6.1.1", + "debug": "^4.4.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.1.1", + "magic-string": "^0.30.17", + "unplugin": "^2.3.2" + }, + "peerDependencies": { + "@microsoft/api-extractor": ">=7", + "@rspack/core": "^1", + "@vue/language-core": "^3.1.5", + "esbuild": "*", + "rolldown": "*", + "rollup": ">=3", + "typescript": ">=4", + "vite": ">=3", + "webpack": "^4 || ^5" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@rspack/core": { + "optional": true + }, + "@vue/language-core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + }, + "vite": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/vite-plugin-dts": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-5.0.3.tgz", + "integrity": "sha512-gIth6NdCEHWPiiRMCK3N6C8WjvdsrtEQrmsiG8h6Ov+lFP+b07Y+wcs9H0H7n146l0PDTYK4cQN1vgeG1pMdRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unplugin-dts": "1.0.3" + }, + "peerDependencies": { + "@microsoft/api-extractor": ">=7", + "rollup": ">=3", + "vite": ">=3" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "rollup": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/shared/package.json b/shared/package.json new file mode 100644 index 0000000..e69de29 diff --git a/shared/src/error/errorcodes.enum.ts b/shared/src/error/errorcodes.enum.ts new file mode 100644 index 0000000..dcb6f89 --- /dev/null +++ b/shared/src/error/errorcodes.enum.ts @@ -0,0 +1,4 @@ +export enum ERROR_CODE { + WRONG_USER_NAME_PASSWORD = 'EU001', + UNEXPECTED_FORMAT = 'ES001', +} \ No newline at end of file diff --git a/shared/tsconfig.json b/shared/tsconfig.json new file mode 100644 index 0000000..85a84bc --- /dev/null +++ b/shared/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + // "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "esnext", + "target": "esnext", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + } +} diff --git a/shared/vite.config.ts b/shared/vite.config.ts new file mode 100644 index 0000000..b87fac5 --- /dev/null +++ b/shared/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from "vite"; +import react, { reactCompilerPreset } from "@vitejs/plugin-react"; +import babel from "@rolldown/plugin-babel"; +import tailwindcss from "@tailwindcss/vite"; +import { TanStackRouterVite } from "@tanstack/router-vite-plugin"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react(), + tailwindcss(), + TanStackRouterVite(), + babel({ presets: [reactCompilerPreset()] }), + ], +});