feat(sql): full sql start stop and query with crash prevention
This commit is contained in:
@@ -1,13 +1,21 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
|
import morgan from "morgan";
|
||||||
import { createLogger } from "./src/logger/logger.controller.js";
|
import { createLogger } from "./src/logger/logger.controller.js";
|
||||||
import { connectProdSql } from "./src/prodSql/sqlConnection.controller.js";
|
import { connectProdSql } from "./src/prodSql/sqlConnection.controller.js";
|
||||||
import { setupRoutes } from "./src/routeHandler.route.js";
|
import { setupRoutes } from "./src/routeHandler.route.js";
|
||||||
|
|
||||||
const port = Number(process.env.PORT);
|
const port = Number(process.env.PORT);
|
||||||
export const baseUrl = "";
|
|
||||||
const startApp = async () => {
|
const startApp = async () => {
|
||||||
const log = createLogger({ module: "system", subModule: "main start" });
|
const log = createLogger({ module: "system", subModule: "main start" });
|
||||||
const app = express();
|
const app = express();
|
||||||
|
let baseUrl = "/";
|
||||||
|
|
||||||
|
// global env that run only in dev
|
||||||
|
if (process.env.NODE_ENV?.trim() !== "production") {
|
||||||
|
app.use(morgan("tiny"));
|
||||||
|
baseUrl = "/lst";
|
||||||
|
}
|
||||||
|
|
||||||
// start the connection to the prod sql server
|
// start the connection to the prod sql server
|
||||||
connectProdSql();
|
connectProdSql();
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import type { Express } from "express";
|
|||||||
import { apiReference } from "@scalar/express-api-reference";
|
import { apiReference } from "@scalar/express-api-reference";
|
||||||
// const port = 3000;
|
// const port = 3000;
|
||||||
import type { OpenAPIV3_1 } from "openapi-types";
|
import type { OpenAPIV3_1 } from "openapi-types";
|
||||||
|
import { prodRestartSpec } from "../scaler/prodSqlRestart.spec.js";
|
||||||
|
import { prodStartSpec } from "../scaler/prodSqlStart.spec.js";
|
||||||
|
import { prodStopSpec } from "../scaler/prodSqlStop.spec.js";
|
||||||
// all the specs
|
// all the specs
|
||||||
import { statusSpec } from "../scaler/stats.spec.js";
|
import { statusSpec } from "../scaler/stats.spec.js";
|
||||||
|
|
||||||
@@ -21,7 +23,7 @@ export const openApiBase: OpenAPIV3_1.Document = {
|
|||||||
},
|
},
|
||||||
servers: [
|
servers: [
|
||||||
{
|
{
|
||||||
url: "http://localhost:3000",
|
url: `http://localhost:3000${process.env.NODE_ENV?.trim() !== "production" ? "/lst" : "/"}`,
|
||||||
description: "Development server",
|
description: "Development server",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -33,15 +35,15 @@ export const openApiBase: OpenAPIV3_1.Document = {
|
|||||||
bearerFormat: "JWT",
|
bearerFormat: "JWT",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
schemas: {
|
// schemas: {
|
||||||
Error: {
|
// Error: {
|
||||||
type: "object",
|
// type: "object",
|
||||||
properties: {
|
// properties: {
|
||||||
error: { type: "string" },
|
// error: { type: "string" },
|
||||||
message: { type: "string" },
|
// message: { type: "string" },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
tags: [
|
tags: [
|
||||||
// { name: "Health", description: "Health check endpoints" },
|
// { name: "Health", description: "Health check endpoints" },
|
||||||
@@ -57,6 +59,9 @@ export const setupApiDocsRoutes = (baseUrl: string, app: Express) => {
|
|||||||
...openApiBase,
|
...openApiBase,
|
||||||
paths: {
|
paths: {
|
||||||
...statusSpec,
|
...statusSpec,
|
||||||
|
...prodStartSpec,
|
||||||
|
...prodStopSpec,
|
||||||
|
...prodRestartSpec,
|
||||||
|
|
||||||
// Add more specs here as you build features
|
// Add more specs here as you build features
|
||||||
},
|
},
|
||||||
|
|||||||
16
backend/src/prodSql/querys/prodSqlStats.ts
Normal file
16
backend/src/prodSql/querys/prodSqlStats.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export const prodSqlServerStats = `
|
||||||
|
DECLARE @UptimeSeconds INT;
|
||||||
|
DECLARE @StartTime DATETIME;
|
||||||
|
|
||||||
|
SELECT @StartTime = sqlserver_start_time FROM sys.dm_os_sys_info;
|
||||||
|
SET @UptimeSeconds = DATEDIFF(SECOND, @StartTime, GETDATE());
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
@StartTime AS [Server Start Time],
|
||||||
|
GETDATE() AS [Current Time],
|
||||||
|
@UptimeSeconds AS [UptimeSeconds],
|
||||||
|
@UptimeSeconds / 86400 AS [Days],
|
||||||
|
(@UptimeSeconds % 86400) / 3600 AS [Hours],
|
||||||
|
(@UptimeSeconds % 3600) / 60 AS [Minutes],
|
||||||
|
(@UptimeSeconds % 60) AS [Seconds];
|
||||||
|
`;
|
||||||
@@ -1,5 +1,47 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
import { closePool, connectProdSql } from "./sqlConnection.controller.js";
|
||||||
|
|
||||||
const r = Router();
|
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;
|
export default r;
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ export let reconnecting = false;
|
|||||||
|
|
||||||
export const connectProdSql = async () => {
|
export const connectProdSql = async () => {
|
||||||
const serverUp = await checkHostnamePort(`${process.env.PROD_SERVER}:1433`);
|
const serverUp = await checkHostnamePort(`${process.env.PROD_SERVER}:1433`);
|
||||||
const log = createLogger({
|
|
||||||
module: "system",
|
|
||||||
subModule: "db",
|
|
||||||
});
|
|
||||||
if (!serverUp) {
|
if (!serverUp) {
|
||||||
// we will try to reconnect
|
// we will try to reconnect
|
||||||
connected = false;
|
connected = false;
|
||||||
@@ -41,9 +37,15 @@ export const connectProdSql = async () => {
|
|||||||
try {
|
try {
|
||||||
pool = await sql.connect(prodSqlConfig);
|
pool = await sql.connect(prodSqlConfig);
|
||||||
connected = true;
|
connected = true;
|
||||||
log.info(
|
return returnFunc({
|
||||||
`${prodSqlConfig.server} is connected to ${prodSqlConfig.database}`,
|
success: true,
|
||||||
);
|
level: "info",
|
||||||
|
module: "system",
|
||||||
|
subModule: "db",
|
||||||
|
message: `${prodSqlConfig.server} is connected to ${prodSqlConfig.database}`,
|
||||||
|
data: [],
|
||||||
|
notify: false,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
@@ -58,10 +60,6 @@ export const connectProdSql = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const closePool = async () => {
|
export const closePool = async () => {
|
||||||
const log = createLogger({
|
|
||||||
module: "system",
|
|
||||||
subModule: "db",
|
|
||||||
});
|
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
@@ -74,15 +72,25 @@ export const closePool = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await pool.close();
|
await pool.close();
|
||||||
log.info("Connection pool closed");
|
|
||||||
connected = false;
|
connected = false;
|
||||||
return {
|
return returnFunc({
|
||||||
success: true,
|
success: true,
|
||||||
message: "The sql server connection has been closed",
|
level: "info",
|
||||||
};
|
module: "system",
|
||||||
|
subModule: "db",
|
||||||
|
message: "The sql connection has been closed.",
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
connected = false;
|
connected = false;
|
||||||
console.log("There was an error closing the sql connection", error);
|
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "system",
|
||||||
|
subModule: "db",
|
||||||
|
message: "There was an error closing the sql connection",
|
||||||
|
data: [error],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const reconnectToSql = async () => {
|
export const reconnectToSql = async () => {
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||||
|
import {
|
||||||
|
closePool,
|
||||||
|
connected,
|
||||||
|
pool,
|
||||||
|
reconnecting,
|
||||||
|
reconnectToSql,
|
||||||
|
} from "./sqlConnection.controller.js";
|
||||||
|
|
||||||
|
interface SqlError extends Error {
|
||||||
|
code?: string;
|
||||||
|
originalError?: {
|
||||||
|
info?: { message?: string };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a prod query
|
||||||
|
* just pass over the query as a string and the name of the query.
|
||||||
|
* Query should be like below.
|
||||||
|
* * select * from AlplaPROD_test1.dbo.table
|
||||||
|
* You must use test1 always as it will be changed via query
|
||||||
|
*/
|
||||||
|
export const prodQuery = async (queryToRun: string, name: string) => {
|
||||||
|
if (!connected) {
|
||||||
|
reconnectToSql();
|
||||||
|
|
||||||
|
if (reconnecting) {
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "system",
|
||||||
|
subModule: "prodSql",
|
||||||
|
message: `The sql ${process.env.PROD_PLANT_TOKEN} is trying to reconnect already`,
|
||||||
|
data: [],
|
||||||
|
notify: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "system",
|
||||||
|
subModule: "prodSql",
|
||||||
|
message: `${process.env.PROD_PLANT_TOKEN} is not connected, and failed to connect.`,
|
||||||
|
data: [],
|
||||||
|
notify: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//change to the correct server
|
||||||
|
const query = queryToRun.replaceAll(
|
||||||
|
"test1",
|
||||||
|
`${process.env.PROD_PLANT_TOKEN}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await pool.request().query(query);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `Query results for: ${name}`,
|
||||||
|
data: result.recordset,
|
||||||
|
};
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const err = error as SqlError;
|
||||||
|
if (err.code === "ETIMEOUT") {
|
||||||
|
closePool();
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
module: "system",
|
||||||
|
subModule: "prodSql",
|
||||||
|
level: "error",
|
||||||
|
message: `${name} did not run due to a timeout.`,
|
||||||
|
notify: false,
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.code === "EREQUEST") {
|
||||||
|
closePool();
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
module: "system",
|
||||||
|
subModule: "prodSql",
|
||||||
|
level: "error",
|
||||||
|
message: `${name} encountered an error ${err.originalError?.info?.message || "undefined error"}`,
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
module: "system",
|
||||||
|
subModule: "prodSql",
|
||||||
|
level: "error",
|
||||||
|
message: `${name} encountered an unknown error.`,
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import type { Express } from "express";
|
|||||||
|
|
||||||
// import the routes and route setups
|
// import the routes and route setups
|
||||||
import { setupApiDocsRoutes } from "./configs/scaler.config.js";
|
import { setupApiDocsRoutes } from "./configs/scaler.config.js";
|
||||||
|
import prodSql from "./prodSql/sql.route.js";
|
||||||
import stats from "./system/stats.route.js";
|
import stats from "./system/stats.route.js";
|
||||||
|
|
||||||
export const setupRoutes = (baseUrl: string, app: Express) => {
|
export const setupRoutes = (baseUrl: string, app: Express) => {
|
||||||
//setup all the routes
|
//setup all the routes
|
||||||
setupApiDocsRoutes(baseUrl, app);
|
setupApiDocsRoutes(baseUrl, app);
|
||||||
app.use(`${baseUrl}/api/stats`, stats);
|
app.use(`${baseUrl}/api/stats`, stats);
|
||||||
|
app.use(`${baseUrl}/api/system/prodSql`, prodSql);
|
||||||
};
|
};
|
||||||
|
|||||||
34
backend/src/scaler/prodSqlRestart.spec.ts
Normal file
34
backend/src/scaler/prodSqlRestart.spec.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import type { OpenAPIV3_1 } from "openapi-types";
|
||||||
|
|
||||||
|
export const prodRestartSpec: OpenAPIV3_1.PathsObject = {
|
||||||
|
"/api/system/prodSql/restart": {
|
||||||
|
post: {
|
||||||
|
summary: "Prod restart sql connection",
|
||||||
|
description: "Attempts to restart the sql connection.",
|
||||||
|
tags: ["System"],
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success from server restarting",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
format: "true",
|
||||||
|
example: true,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
format: "Sql Server has been restarted",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
55
backend/src/scaler/prodSqlStart.spec.ts
Normal file
55
backend/src/scaler/prodSqlStart.spec.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import type { OpenAPIV3_1 } from "openapi-types";
|
||||||
|
|
||||||
|
export const prodStartSpec: OpenAPIV3_1.PathsObject = {
|
||||||
|
"/api/system/prodSql/start": {
|
||||||
|
post: {
|
||||||
|
summary: "Prod start sql connection",
|
||||||
|
description: "Connects to the prod sql server.",
|
||||||
|
tags: ["System"],
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Data that is returned from the connection",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
format: "true",
|
||||||
|
example: true,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
format: "usmcd1vms036 is connected to AlplaPROD_test3_cus",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
description: "Data that is returned from the connection",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
format: "false",
|
||||||
|
example: false,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
format: "The Sql server is already connected.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
56
backend/src/scaler/prodSqlStop.spec.ts
Normal file
56
backend/src/scaler/prodSqlStop.spec.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import type { OpenAPIV3_1 } from "openapi-types";
|
||||||
|
|
||||||
|
export const prodStopSpec: OpenAPIV3_1.PathsObject = {
|
||||||
|
"/api/system/prodSql/stop": {
|
||||||
|
post: {
|
||||||
|
summary: "Prod stop sql connection",
|
||||||
|
description: "Closes the connection to the prod server.",
|
||||||
|
tags: ["System"],
|
||||||
|
responses: {
|
||||||
|
"200": {
|
||||||
|
description: "Success from server starting",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
format: "true",
|
||||||
|
example: true,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
format: "The sql connection has been closed.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
description: "Errors on why the server could not be stopped",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
format: "false",
|
||||||
|
example: false,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
format:
|
||||||
|
"There is no connection to the prod server currently.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -28,6 +28,10 @@ export const statusSpec: OpenAPIV3_1.PathsObject = {
|
|||||||
type: "string",
|
type: "string",
|
||||||
format: "Heap: 11.62 MB / RSS: 86.31 MB",
|
format: "Heap: 11.62 MB / RSS: 86.31 MB",
|
||||||
},
|
},
|
||||||
|
sqlServerStats: {
|
||||||
|
type: "number",
|
||||||
|
format: "442127",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
import { prodSqlServerStats } from "../prodSql/querys/prodSqlStats.js";
|
||||||
|
import { prodQuery } from "../prodSql/sqlQuery.controller.js";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get("/", async (_, res) => {
|
router.get("/", async (_, res) => {
|
||||||
const used = process.memoryUsage();
|
const used = process.memoryUsage();
|
||||||
|
|
||||||
|
const sqlServerStats = await prodQuery(prodSqlServerStats, "Sql Stats");
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
status: "ok",
|
status: "ok",
|
||||||
uptime: process.uptime(),
|
uptime: process.uptime(),
|
||||||
memoryUsage: `Heap: ${(used.heapUsed / 1024 / 1024).toFixed(2)} MB / RSS: ${(
|
memoryUsage: `Heap: ${(used.heapUsed / 1024 / 1024).toFixed(2)} MB / RSS: ${(
|
||||||
used.rss / 1024 / 1024
|
used.rss / 1024 / 1024
|
||||||
).toFixed(2)} MB`,
|
).toFixed(2)} MB`,
|
||||||
|
sqlServerStats: sqlServerStats?.success
|
||||||
|
? sqlServerStats?.data[0].UptimeSeconds
|
||||||
|
: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import type { Response } from "express";
|
||||||
import { createLogger } from "../logger/logger.controller.js";
|
import { createLogger } from "../logger/logger.controller.js";
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
module: "system" | "ocp";
|
module: "system" | "ocp" | "routes";
|
||||||
subModule: "db" | "labeling" | "printer";
|
subModule: "db" | "labeling" | "printer" | "prodSql";
|
||||||
level: "info" | "error" | "debug" | "fatal";
|
level: "info" | "error" | "debug" | "fatal";
|
||||||
message: string;
|
message: string;
|
||||||
data?: unknown[];
|
data?: unknown[];
|
||||||
@@ -49,3 +50,12 @@ export const returnFunc = (data: Data) => {
|
|||||||
data: data.data || [],
|
data: data.data || [],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function apiReturn(
|
||||||
|
res: Response,
|
||||||
|
opts: Data & { status?: number },
|
||||||
|
): Response {
|
||||||
|
const result = returnFunc(opts);
|
||||||
|
const code = opts.status ?? (opts.success ? 200 : 500);
|
||||||
|
return res.status(code ?? (opts.success ? 200 : 500)).json(result);
|
||||||
|
}
|
||||||
|
|||||||
89
package-lock.json
generated
89
package-lock.json
generated
@@ -18,6 +18,7 @@
|
|||||||
"@commitlint/config-conventional": "^18.4.0",
|
"@commitlint/config-conventional": "^18.4.0",
|
||||||
"@scalar/express-api-reference": "^0.8.28",
|
"@scalar/express-api-reference": "^0.8.28",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
|
"@types/morgan": "^1.9.10",
|
||||||
"@types/mssql": "^9.1.8",
|
"@types/mssql": "^9.1.8",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/swagger-jsdoc": "^6.0.4",
|
"@types/swagger-jsdoc": "^6.0.4",
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
|
"morgan": "^1.10.1",
|
||||||
"mssql": "^12.2.0",
|
"mssql": "^12.2.0",
|
||||||
"npm-check-updates": "^19.1.2",
|
"npm-check-updates": "^19.1.2",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
@@ -1992,6 +1994,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/morgan": {
|
||||||
|
"version": "1.9.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.10.tgz",
|
||||||
|
"integrity": "sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/mssql": {
|
"node_modules/@types/mssql": {
|
||||||
"version": "9.1.8",
|
"version": "9.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-9.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-9.1.8.tgz",
|
||||||
@@ -2390,6 +2402,26 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/basic-auth": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "5.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/basic-auth/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/better-auth": {
|
"node_modules/better-auth": {
|
||||||
"version": "1.4.6",
|
"version": "1.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.4.6.tgz",
|
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.4.6.tgz",
|
||||||
@@ -5669,6 +5701,53 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/morgan": {
|
||||||
|
"version": "1.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
|
||||||
|
"integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"basic-auth": "~2.0.1",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~2.0.0",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"on-headers": "~1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/morgan/node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/morgan/node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/morgan/node_modules/on-finished": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ee-first": "1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mri": {
|
"node_modules/mri": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||||
@@ -5863,6 +5942,16 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/on-headers": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/once": {
|
"node_modules/once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"@commitlint/config-conventional": "^18.4.0",
|
"@commitlint/config-conventional": "^18.4.0",
|
||||||
"@scalar/express-api-reference": "^0.8.28",
|
"@scalar/express-api-reference": "^0.8.28",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
|
"@types/morgan": "^1.9.10",
|
||||||
"@types/mssql": "^9.1.8",
|
"@types/mssql": "^9.1.8",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/swagger-jsdoc": "^6.0.4",
|
"@types/swagger-jsdoc": "^6.0.4",
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
|
"morgan": "^1.10.1",
|
||||||
"mssql": "^12.2.0",
|
"mssql": "^12.2.0",
|
||||||
"npm-check-updates": "^19.1.2",
|
"npm-check-updates": "^19.1.2",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
|
|||||||
Reference in New Issue
Block a user