diff --git a/backend/app.ts b/backend/app.ts index 5bb829e..44b67e0 100644 --- a/backend/app.ts +++ b/backend/app.ts @@ -1,8 +1,8 @@ import express from "express"; import morgan from "morgan"; import { createLogger } from "./src/logger/logger.controller.js"; -import { connectProdSql } from "./src/prodSql/sqlConnection.controller.js"; -import { setupRoutes } from "./src/routeHandler.route.js"; +import { connectProdSql } from "./src/prodSql/prodSqlConnection.controller.js"; +import { setupRoutes } from "./src/routeHandler.routes.js"; const port = Number(process.env.PORT); diff --git a/backend/src/prodSql/prodSql.routes.ts b/backend/src/prodSql/prodSql.routes.ts new file mode 100644 index 0000000..cb7e554 --- /dev/null +++ b/backend/src/prodSql/prodSql.routes.ts @@ -0,0 +1,10 @@ +import type { Express } from "express"; +import restart from "./prodSqlRestart.route.js"; +import start from "./prodSqlStart.route.js"; +import stop from "./prodSqlStop.route.js"; +export const setupProdSqlRoutes = (baseUrl: string, app: Express) => { + //setup all the routes + app.use(`${baseUrl}/api/system/prodSql`, start); + app.use(`${baseUrl}/api/system/prodSql`, stop); + app.use(`${baseUrl}/api/system/prodSql`, restart); +}; diff --git a/backend/src/prodSql/sqlConnection.controller.ts b/backend/src/prodSql/prodSqlConnection.controller.ts similarity index 100% rename from backend/src/prodSql/sqlConnection.controller.ts rename to backend/src/prodSql/prodSqlConnection.controller.ts diff --git a/backend/src/prodSql/sqlQuery.controller.ts b/backend/src/prodSql/prodSqlQuery.controller.ts similarity index 98% rename from backend/src/prodSql/sqlQuery.controller.ts rename to backend/src/prodSql/prodSqlQuery.controller.ts index f04677c..06c7dcc 100644 --- a/backend/src/prodSql/sqlQuery.controller.ts +++ b/backend/src/prodSql/prodSqlQuery.controller.ts @@ -5,7 +5,7 @@ import { pool, reconnecting, reconnectToSql, -} from "./sqlConnection.controller.js"; +} from "./prodSqlConnection.controller.js"; interface SqlError extends Error { code?: string; diff --git a/backend/src/prodSql/prodSqlRestart.route.ts b/backend/src/prodSql/prodSqlRestart.route.ts new file mode 100644 index 0000000..105812d --- /dev/null +++ b/backend/src/prodSql/prodSqlRestart.route.ts @@ -0,0 +1,23 @@ +import { Router } from "express"; +import { apiReturn } from "../utils/returnHelper.utils.js"; +import { closePool, connectProdSql } from "./prodSqlConnection.controller.js"; + +const r = Router(); + +r.post("/restart", async (_, res) => { + await closePool(); + + await new Promise((r) => setTimeout(r, 2000)); + + const connect = await connectProdSql(); + apiReturn(res, { + success: connect.success, + level: connect.success ? "info" : "error", + module: "routes", + subModule: "prodSql", + message: "Sql Server has been restarted", + data: connect.data, + status: connect.success ? 200 : 400, + }); +}); +export default r; diff --git a/backend/src/prodSql/prodSqlStart.route.ts b/backend/src/prodSql/prodSqlStart.route.ts new file mode 100644 index 0000000..f35ec75 --- /dev/null +++ b/backend/src/prodSql/prodSqlStart.route.ts @@ -0,0 +1,20 @@ +import { Router } from "express"; +import { apiReturn } from "../utils/returnHelper.utils.js"; +import { connectProdSql } from "./prodSqlConnection.controller.js"; + +const r = Router(); + +r.post("/start", async (_, res) => { + const connect = await connectProdSql(); + apiReturn(res, { + success: connect.success, + level: connect.success ? "info" : "error", + module: "routes", + subModule: "prodSql", + message: connect.message, + data: connect.data, + status: connect.success ? 200 : 400, + }); +}); + +export default r; diff --git a/backend/src/prodSql/prodSqlStop.route.ts b/backend/src/prodSql/prodSqlStop.route.ts new file mode 100644 index 0000000..c1f27b4 --- /dev/null +++ b/backend/src/prodSql/prodSqlStop.route.ts @@ -0,0 +1,20 @@ +import { Router } from "express"; +import { apiReturn } from "../utils/returnHelper.utils.js"; +import { closePool } from "./prodSqlConnection.controller.js"; + +const r = Router(); + +r.post("/stop", async (_, res) => { + const connect = await closePool(); + apiReturn(res, { + success: connect.success, + level: connect.success ? "info" : "error", + module: "routes", + subModule: "prodSql", + message: connect.message, + data: connect.data, + status: connect.success ? 200 : 400, + }); +}); + +export default r; diff --git a/backend/src/prodSql/sql.route.ts b/backend/src/prodSql/sql.route.ts deleted file mode 100644 index 6577221..0000000 --- a/backend/src/prodSql/sql.route.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Router } from "express"; -import { apiReturn } from "../utils/returnHelper.utils.js"; -import { closePool, connectProdSql } from "./sqlConnection.controller.js"; - -const r = Router(); - -r.post("/start", async (_, res) => { - const connect = await connectProdSql(); - apiReturn(res, { - success: connect.success, - level: connect.success ? "info" : "error", - module: "routes", - subModule: "prodSql", - message: connect.message, - data: connect.data, - status: connect.success ? 200 : 400, - }); -}); -r.post("/stop", async (_, res) => { - const connect = await closePool(); - apiReturn(res, { - success: connect.success, - level: connect.success ? "info" : "error", - module: "routes", - subModule: "prodSql", - message: connect.message, - data: connect.data, - status: connect.success ? 200 : 400, - }); -}); -r.post("/restart", async (_, res) => { - await closePool(); - - await new Promise((r) => setTimeout(r, 2000)); - - const connect = await connectProdSql(); - apiReturn(res, { - success: connect.success, - level: connect.success ? "info" : "error", - module: "routes", - subModule: "prodSql", - message: "Sql Server has been restarted", - data: connect.data, - status: connect.success ? 200 : 400, - }); -}); -export default r; diff --git a/backend/src/routeHandler.route.ts b/backend/src/routeHandler.routes.ts similarity index 77% rename from backend/src/routeHandler.route.ts rename to backend/src/routeHandler.routes.ts index d19c297..e7d8f80 100644 --- a/backend/src/routeHandler.route.ts +++ b/backend/src/routeHandler.routes.ts @@ -2,12 +2,13 @@ import type { Express } from "express"; // import the routes and route setups import { setupApiDocsRoutes } from "./configs/scaler.config.js"; -import prodSql from "./prodSql/sql.route.js"; +import { setupProdSqlRoutes } from "./prodSql/prodSql.routes.js"; import stats from "./system/stats.route.js"; export const setupRoutes = (baseUrl: string, app: Express) => { //setup all the routes setupApiDocsRoutes(baseUrl, app); + setupProdSqlRoutes(baseUrl, app); + app.use(`${baseUrl}/api/stats`, stats); - app.use(`${baseUrl}/api/system/prodSql`, prodSql); }; diff --git a/backend/src/system/stats.route.ts b/backend/src/system/stats.route.ts index 93707da..b8b63a0 100644 --- a/backend/src/system/stats.route.ts +++ b/backend/src/system/stats.route.ts @@ -1,6 +1,6 @@ import { Router } from "express"; +import { prodQuery } from "../prodSql/prodSqlQuery.controller.js"; import { prodSqlServerStats } from "../prodSql/querys/prodSqlStats.js"; -import { prodQuery } from "../prodSql/sqlQuery.controller.js"; const router = Router(); diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..9e4dcdf --- /dev/null +++ b/biome.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true, + "defaultBranch": "main" + }, + "files": { + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "linter": { + "enabled": true, + "rules": { + "suspicious": { + "noConsole": { + "level":"on", + "options": { + "allow": ["error", "info", "warn"] + } + } + }, + "correctness": { + "useJsxKeyInIterable": "error" + } + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "recommended": true, + "organizeImports": "on" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "json": { + "formatter": { + "enabled": false + } + } +} diff --git a/package.json b/package.json index 04397b6..2bedd74 100644 --- a/package.json +++ b/package.json @@ -7,15 +7,16 @@ "test": "echo \"Error: no test specified\" && exit 1", "dev": "dotenvx run -f .env -- npm run dev:app", "dev:app": "cd backend && tsx watch app.ts", - "prebuild": "tsx backend/src/scaler/generateSpec.ts", - "build": "esbuild backend/app.ts --bundle --platform=node --minify --outfile=dist/index.js --format=esm --packages=external", + "build": "npm run specCheck && npm run lint && npm run build:app", "build:app": "ncc build backend/app.ts -o dist -m -s", - "lint": "tsc", + "lint": "tsc && biome lint", "start": "dotenvx run -f .env -- node dist/index.js", "commit": "cz", "changeset": "changeset", "version": "changeset version", - "release": "dotenvx run -f .env -- npm run version && git push --follow-tags && node scripts/create-release.js" + "release": "dotenvx run -f .env -- npm run version && git push --follow-tags && node scripts/create-release.js", + "specCheck": "node scripts/check-route-specs.mjs" + }, "repository": { "type": "git", diff --git a/scripts/check-route-specs.mjs b/scripts/check-route-specs.mjs new file mode 100644 index 0000000..8c31ed4 --- /dev/null +++ b/scripts/check-route-specs.mjs @@ -0,0 +1,50 @@ +import { readdirSync, statSync } from "node:fs"; +import { basename, join } from "node:path"; + +/** + * Recursively get all files from a directory + */ +function getAllFiles(dir) { + let results = []; + for (const file of readdirSync(dir)) { + const filePath = join(dir, file); + const stat = statSync(filePath); + if (stat.isDirectory()) { + results = results.concat(getAllFiles(filePath)); + } else { + results.push(filePath); + } + } + return results; +} + +/** + * Main check function + */ +function checkRouteSpecs(baseDir) { + const allFiles = getAllFiles(baseDir); + + // Collect base filenames (without extensions) + const routeFiles = allFiles.filter((f) => f.endsWith(".route.ts")); + const specFiles = allFiles.filter((f) => f.endsWith(".spec.ts")); + + const specNames = new Set(specFiles.map((f) => basename(f, ".spec.ts"))); + + const missingSpecs = routeFiles.filter((routePath) => { + const baseName = basename(routePath, ".route.ts"); + return !specNames.has(baseName); + }); + + if (missingSpecs.length > 0) { + console.error("❌ Missing spec files for these routes:\n"); + for (const missing of missingSpecs) { + console.error(`··-·${missing}`); + } + process.exit(1); + } else { + console.info("✅ All route files have corresponding spec files."); + } +} + +// Adjust paths based on your structure +checkRouteSpecs("backend/src"); diff --git a/scripts/create-release.js b/scripts/create-release.js index bdef648..600995f 100644 --- a/scripts/create-release.js +++ b/scripts/create-release.js @@ -1,7 +1,7 @@ +import { readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; import axios from "axios"; -import { readFileSync } from "fs"; -import { dirname, join } from "path"; -import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -36,8 +36,8 @@ try { }, ); - console.log(`✅ Release ${version} created!`); - console.log(`🔗 ${response.data.html_url}`); + console.info(`✅ Release ${version} created!`); + console.info(`🔗 ${response.data.html_url}`); } catch (error) { console.error(`❌ Error: ${error.response?.data?.message || error.message}`); process.exit(1);