mielk-api 1.0.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db/pg/connection/pool.d.ts +4 -0
- package/dist/db/pg/connection/pool.js +37 -0
- package/dist/db/pg/connection/tunnel.d.ts +2 -0
- package/dist/db/pg/connection/tunnel.js +30 -0
- package/dist/db/pg/index.d.ts +6 -0
- package/dist/db/pg/index.js +4 -0
- package/dist/{back/enums → db/pg/static}/PostgreErrorCodes.d.ts +1 -1
- package/dist/{back/enums → db/pg/static}/PostgreErrorCodes.js +1 -1
- package/dist/db/pg/types/DbConfig.d.ts +13 -0
- package/dist/express.d.ts +4 -0
- package/dist/express.js +16 -0
- package/dist/http/apiResponse/apiResponse.d.ts +6 -0
- package/dist/http/apiResponse/apiResponse.js +28 -0
- package/dist/http/httpResponseStatus/HttpResponseStatus.d.ts +10 -0
- package/dist/{back/enums/ApiStatus.js → http/httpResponseStatus/HttpResponseStatus.js} +2 -2
- package/dist/http/index.d.ts +9 -0
- package/dist/http/index.js +4 -0
- package/dist/{front/types.d.ts → http/types/ApiResponse.d.ts} +3 -3
- package/dist/http/types/ApiResponse.js +1 -0
- package/dist/{back/types/types.d.ts → http/types/HttpStatus.d.ts} +2 -2
- package/dist/http/types/HttpStatus.js +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/internal/messaging/messageTags.d.ts +9 -1
- package/dist/internal/messaging/messageTags.js +18 -9
- package/dist/middlewares/cors/cors.d.ts +7 -0
- package/dist/middlewares/cors/cors.js +31 -0
- package/dist/middlewares/cors/privateCors.d.ts +6 -0
- package/dist/middlewares/cors/privateCors.js +18 -0
- package/dist/middlewares/cors/publicCors.d.ts +6 -0
- package/dist/middlewares/cors/publicCors.js +10 -0
- package/dist/middlewares/index.d.ts +10 -0
- package/dist/middlewares/index.js +10 -0
- package/dist/middlewares/rateLimit/rateLimit.d.ts +6 -0
- package/dist/middlewares/rateLimit/rateLimit.js +10 -0
- package/dist/middlewares/requestAuth/auth.middleware.d.ts +2 -0
- package/dist/middlewares/requestAuth/auth.middleware.js +13 -0
- package/dist/middlewares/zod/validate.d.ts +4 -0
- package/dist/middlewares/zod/validate.js +34 -0
- package/dist/routing/controllers/db.controller.d.ts +3 -0
- package/dist/routing/controllers/db.controller.js +31 -0
- package/dist/routing/controllers/health.controller.d.ts +3 -0
- package/dist/routing/controllers/health.controller.js +11 -0
- package/dist/routing/repositories/db.repository.d.ts +2 -0
- package/dist/routing/repositories/db.repository.js +24 -0
- package/dist/routing/routes/db.route.d.ts +4 -0
- package/dist/routing/routes/db.route.js +7 -0
- package/dist/routing/routes/health.route.d.ts +4 -0
- package/dist/routing/routes/health.route.js +7 -0
- package/dist/routing/services/db.service.d.ts +2 -0
- package/dist/routing/services/db.service.js +20 -0
- package/package.json +33 -11
- package/dist/back/enums/ApiStatus.d.ts +0 -10
- package/dist/back/index.d.ts +0 -6
- package/dist/back/index.js +0 -4
- package/dist/front/index.d.ts +0 -4
- /package/dist/{back/types/types.js → db/mssql/index.d.ts} +0 -0
- /package/dist/{front → db/mssql}/index.js +0 -0
- /package/dist/{front/types.js → db/pg/types/DbConfig.js} +0 -0
- /package/dist/{utils → http/client}/Post.d.ts +0 -0
- /package/dist/{utils → http/client}/Post.js +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { Msg } from '../../../internal/messaging/messageTags.js';
|
|
11
|
+
import { Pool } from 'pg';
|
|
12
|
+
import { openSshTunnel } from './tunnel.js';
|
|
13
|
+
import { isProd } from '../../../express.js';
|
|
14
|
+
let pool = null;
|
|
15
|
+
let config = null;
|
|
16
|
+
export const initDb = (dbConfig) => {
|
|
17
|
+
config = Object.assign({ max: 10, min: 0, idleTimeoutMillis: 30000, connectionTimeoutMillis: 10000 }, dbConfig);
|
|
18
|
+
};
|
|
19
|
+
export function getPool() {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
if (pool)
|
|
22
|
+
return pool;
|
|
23
|
+
if (config === null)
|
|
24
|
+
throw new Error(Msg.connection.notInitialized);
|
|
25
|
+
if (!isProd) {
|
|
26
|
+
if (!config.ssh)
|
|
27
|
+
throw new Error(Msg.connection.sshOptionsNotSpecified);
|
|
28
|
+
const port = yield openSshTunnel(config.ssh, config.port);
|
|
29
|
+
config.port = port;
|
|
30
|
+
}
|
|
31
|
+
pool = new Pool(config);
|
|
32
|
+
pool.on('error', (err) => {
|
|
33
|
+
console.error(Msg.connection.postgreConnectionError, err);
|
|
34
|
+
});
|
|
35
|
+
return pool;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { createTunnel } from 'tunnel-ssh';
|
|
11
|
+
import { Msg } from '../../../internal/messaging/messageTags.js';
|
|
12
|
+
const tunnelOptions = {
|
|
13
|
+
autoClose: true,
|
|
14
|
+
reconnectOnError: true,
|
|
15
|
+
};
|
|
16
|
+
const serverOptions = {};
|
|
17
|
+
export function openSshTunnel(sshOptions, dstPort) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
try {
|
|
20
|
+
const forwardOptions = { dstPort };
|
|
21
|
+
const [server] = yield createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions);
|
|
22
|
+
const port = server.address().port;
|
|
23
|
+
return port;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.error(Msg.connection.sshTunnelFailed, err);
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SshOptions } from "tunnel-ssh";
|
|
2
|
+
export interface DbConfig {
|
|
3
|
+
host: string;
|
|
4
|
+
port: number;
|
|
5
|
+
user: string;
|
|
6
|
+
password: string;
|
|
7
|
+
database: string;
|
|
8
|
+
ssh?: SshOptions;
|
|
9
|
+
max?: number;
|
|
10
|
+
min?: number;
|
|
11
|
+
idleTimeoutMillis?: number;
|
|
12
|
+
connectionTimeoutMillis?: number;
|
|
13
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { DbConfig } from './db/pg/index.js';
|
|
2
|
+
import { CorsConfig, RateLimitConfig } from './middlewares/index.js';
|
|
3
|
+
export declare const createExpressApp: (isProd: boolean, dbConfig: DbConfig, corsConfig: CorsConfig, rateLimitConfig?: RateLimitConfig) => import("express-serve-static-core").Express;
|
|
4
|
+
export declare const isProd: boolean;
|
package/dist/express.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { initDb } from './db/pg/index.js';
|
|
3
|
+
import { initCors, setRateLimit } from './middlewares/index.js';
|
|
4
|
+
const env = {
|
|
5
|
+
isProd: true
|
|
6
|
+
};
|
|
7
|
+
export const createExpressApp = (isProd, dbConfig, corsConfig, rateLimitConfig) => {
|
|
8
|
+
const app = express();
|
|
9
|
+
env.isProd = isProd;
|
|
10
|
+
initDb(dbConfig);
|
|
11
|
+
initCors(corsConfig);
|
|
12
|
+
setRateLimit(app, rateLimitConfig);
|
|
13
|
+
app.use(express.json());
|
|
14
|
+
return app;
|
|
15
|
+
};
|
|
16
|
+
export const isProd = env.isProd;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
import { HttpStatus } from '../types/HttpStatus.js';
|
|
3
|
+
import { ApiErrorDetails } from '../types/ApiResponse.js';
|
|
4
|
+
export declare function success<T>(res: Response, status: HttpStatus, data: T): void;
|
|
5
|
+
export declare function failure(res: Response, status: HttpStatus, details: string | ApiErrorDetails): void;
|
|
6
|
+
export declare function serverError(res: Response, err: Error): void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isObject, isPrimitive } from 'mielk-fn/variables';
|
|
2
|
+
import { HttpResponseStatus } from '../httpResponseStatus/HttpResponseStatus.js';
|
|
3
|
+
import { isProd } from '../../express.js';
|
|
4
|
+
export function success(res, status, data) {
|
|
5
|
+
const apiResponse = {
|
|
6
|
+
success: true,
|
|
7
|
+
data,
|
|
8
|
+
};
|
|
9
|
+
res.status(status.code).json(apiResponse);
|
|
10
|
+
}
|
|
11
|
+
export function failure(res, status, details) {
|
|
12
|
+
const message = isPrimitive(details) ? details : (details === null || details === void 0 ? void 0 : details.message) || status.defaultMessageTag;
|
|
13
|
+
const apiError = {
|
|
14
|
+
success: false,
|
|
15
|
+
message,
|
|
16
|
+
params: isObject(details) ? details.params : undefined
|
|
17
|
+
};
|
|
18
|
+
res.status(status.code).json(apiError);
|
|
19
|
+
}
|
|
20
|
+
export function serverError(res, err) {
|
|
21
|
+
var _a;
|
|
22
|
+
const status = HttpResponseStatus.SERVER_ERROR;
|
|
23
|
+
const apiError = {
|
|
24
|
+
success: false,
|
|
25
|
+
message: isProd ? status.defaultMessageTag : `message: ${err.message} | stack: ${(_a = err.stack) === null || _a === void 0 ? void 0 : _a.toString()}`,
|
|
26
|
+
};
|
|
27
|
+
res.status(status.code).json(apiError);
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HttpStatus } from "../types/HttpStatus.js";
|
|
2
|
+
export declare const HttpResponseStatus: {
|
|
3
|
+
OK: HttpStatus;
|
|
4
|
+
CREATED: HttpStatus;
|
|
5
|
+
BAD_REQUEST: HttpStatus;
|
|
6
|
+
UNAUTHORIZED: HttpStatus;
|
|
7
|
+
NOT_FOUND: HttpStatus;
|
|
8
|
+
CONFLICT: HttpStatus;
|
|
9
|
+
SERVER_ERROR: HttpStatus;
|
|
10
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Msg } from "../../internal/messaging/messageTags.js";
|
|
2
2
|
const createApiStatus = (success, code, defaultMessageTag) => ({ success, code, defaultMessageTag });
|
|
3
|
-
const msg = Msg.
|
|
4
|
-
export const
|
|
3
|
+
const msg = Msg.apiStatus;
|
|
4
|
+
export const HttpResponseStatus = {
|
|
5
5
|
OK: createApiStatus(true, 200, msg.ok),
|
|
6
6
|
CREATED: createApiStatus(true, 201, msg.created),
|
|
7
7
|
BAD_REQUEST: createApiStatus(false, 400, msg.badRequest),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ApiSuccess, ApiError, ApiErrorDetails } from '../http/types/ApiResponse.js';
|
|
2
|
+
import type { ApiResponse } from '../http/types/ApiResponse.js';
|
|
3
|
+
import { HttpStatus } from './types/HttpStatus.js';
|
|
4
|
+
import { HttpResponseStatus } from './httpResponseStatus/HttpResponseStatus.js';
|
|
5
|
+
import { success, failure, serverError } from './apiResponse/apiResponse.js';
|
|
6
|
+
export type { ApiResponse };
|
|
7
|
+
export { HttpStatus as ApiStatus, ApiError, ApiSuccess, ApiErrorDetails };
|
|
8
|
+
export { HttpResponseStatus };
|
|
9
|
+
export { success, failure, serverError };
|
|
@@ -7,8 +7,8 @@ export interface ApiError {
|
|
|
7
7
|
message: string;
|
|
8
8
|
params?: Record<string, string | number | Date | unknown | boolean>;
|
|
9
9
|
}
|
|
10
|
-
export
|
|
11
|
-
export type ApiErrorDetails = {
|
|
10
|
+
export interface ApiErrorDetails {
|
|
12
11
|
message: string;
|
|
13
12
|
params?: Record<string, string | number | Date | unknown | boolean>;
|
|
14
|
-
}
|
|
13
|
+
}
|
|
14
|
+
export type ApiResponse<T> = ApiSuccess<T> | ApiError;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
export * as
|
|
2
|
-
export * as
|
|
1
|
+
export * as pg from './db/pg/index.js';
|
|
2
|
+
export * as mssql from './db/mssql/index.js';
|
|
3
|
+
export * as http from './http/index.js';
|
|
4
|
+
export { dbRouter } from './routing/routes/db.route.js';
|
|
5
|
+
export { healthRouter } from './routing/routes/health.route.js';
|
|
6
|
+
export { createExpressApp } from './express.js';
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
export * as
|
|
2
|
-
export * as
|
|
1
|
+
export * as pg from './db/pg/index.js';
|
|
2
|
+
export * as mssql from './db/mssql/index.js';
|
|
3
|
+
export * as http from './http/index.js';
|
|
4
|
+
export { dbRouter } from './routing/routes/db.route.js';
|
|
5
|
+
export { healthRouter } from './routing/routes/health.route.js';
|
|
6
|
+
export { createExpressApp } from './express.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const Msg: {
|
|
2
|
-
|
|
2
|
+
apiStatus: {
|
|
3
3
|
ok: string;
|
|
4
4
|
created: string;
|
|
5
5
|
unauthorized: string;
|
|
@@ -8,4 +8,12 @@ export declare const Msg: {
|
|
|
8
8
|
conflict: string;
|
|
9
9
|
serverError: string;
|
|
10
10
|
};
|
|
11
|
+
connection: {
|
|
12
|
+
corsBlocked: string;
|
|
13
|
+
notInitialized: string;
|
|
14
|
+
sshOptionsNotSpecified: string;
|
|
15
|
+
sshTunnelFailed: string;
|
|
16
|
+
postgreConnectionError: string;
|
|
17
|
+
unauthorizedRequest: string;
|
|
18
|
+
};
|
|
11
19
|
};
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
const PARENT_FOLDER = 'api/';
|
|
2
|
-
const
|
|
2
|
+
const ___API_STATUS___ = `${PARENT_FOLDER}/ApiStatus`;
|
|
3
|
+
const ___CONNECTION___ = `${PARENT_FOLDER}/Connection`;
|
|
3
4
|
export const Msg = {
|
|
4
|
-
|
|
5
|
-
ok: `${
|
|
6
|
-
created: `${
|
|
7
|
-
unauthorized: `${
|
|
8
|
-
badRequest: `${
|
|
9
|
-
notFound: `${
|
|
10
|
-
conflict: `${
|
|
11
|
-
serverError: `${
|
|
5
|
+
apiStatus: {
|
|
6
|
+
ok: `${___API_STATUS___}:ok`,
|
|
7
|
+
created: `${___API_STATUS___}:created`,
|
|
8
|
+
unauthorized: `${___API_STATUS___}:unauthorized`,
|
|
9
|
+
badRequest: `${___API_STATUS___}:badRequest`,
|
|
10
|
+
notFound: `${___API_STATUS___}:notFound`,
|
|
11
|
+
conflict: `${___API_STATUS___}:conflict`,
|
|
12
|
+
serverError: `${___API_STATUS___}:serverError`,
|
|
13
|
+
},
|
|
14
|
+
connection: {
|
|
15
|
+
corsBlocked: `${___CONNECTION___}:corsBlocked`,
|
|
16
|
+
notInitialized: `${___CONNECTION___}:notInitialized`,
|
|
17
|
+
sshOptionsNotSpecified: `${___CONNECTION___}:sshOptionsNotSpecified`,
|
|
18
|
+
sshTunnelFailed: `${___CONNECTION___}:sshTunnelFailed`, // ❌ SSH tunnel failed
|
|
19
|
+
postgreConnectionError: `${___CONNECTION___}:postgreConnectionError`, // Unexpected PostgreSQL error
|
|
20
|
+
unauthorizedRequest: `${___CONNECTION___}:unauthorizedRequest`
|
|
12
21
|
}
|
|
13
22
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type CorsConfig = {
|
|
2
|
+
allowedOrigins: string | undefined;
|
|
3
|
+
apiKey: string | undefined;
|
|
4
|
+
};
|
|
5
|
+
export declare const initCors: (config: CorsConfig) => void;
|
|
6
|
+
export declare function checkCors(origin?: string): boolean;
|
|
7
|
+
export declare const apiKey: () => string | undefined;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { isProd } from "../../express.js";
|
|
2
|
+
const corsConfig = {
|
|
3
|
+
allowedOrigins: '',
|
|
4
|
+
apiKey: ''
|
|
5
|
+
};
|
|
6
|
+
export const initCors = (config) => {
|
|
7
|
+
const { allowedOrigins, apiKey } = config;
|
|
8
|
+
corsConfig.allowedOrigins = allowedOrigins;
|
|
9
|
+
corsConfig.apiKey = apiKey;
|
|
10
|
+
};
|
|
11
|
+
function getAllowedOrigins() {
|
|
12
|
+
const { allowedOrigins } = corsConfig;
|
|
13
|
+
if (!allowedOrigins)
|
|
14
|
+
return [];
|
|
15
|
+
return allowedOrigins
|
|
16
|
+
.split(',')
|
|
17
|
+
.map((o) => o.trim())
|
|
18
|
+
.filter(Boolean);
|
|
19
|
+
}
|
|
20
|
+
export function checkCors(origin) {
|
|
21
|
+
if (!origin)
|
|
22
|
+
return false;
|
|
23
|
+
if (!isProd) {
|
|
24
|
+
return origin.startsWith('http://localhost');
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const allowedOrigins = getAllowedOrigins();
|
|
28
|
+
return allowedOrigins.includes(origin);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export const apiKey = () => corsConfig.apiKey;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import cors from 'cors';
|
|
2
|
+
import { checkCors } from './cors.js';
|
|
3
|
+
export const privateCors = cors({
|
|
4
|
+
origin: (origin, callback) => {
|
|
5
|
+
if (!origin) {
|
|
6
|
+
// i.e. Postman or curl
|
|
7
|
+
return callback(null, true);
|
|
8
|
+
}
|
|
9
|
+
if (checkCors(origin)) {
|
|
10
|
+
return callback(null, true);
|
|
11
|
+
}
|
|
12
|
+
const message = `CORS blocked: ${origin}`;
|
|
13
|
+
console.warn(`❌ ${message}`);
|
|
14
|
+
return callback(new Error(message), false);
|
|
15
|
+
},
|
|
16
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
17
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
18
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CorsConfig, initCors } from './cors/cors.js';
|
|
2
|
+
import { privateCors } from './cors/privateCors.js';
|
|
3
|
+
import { publicCors } from './cors/publicCors.js';
|
|
4
|
+
import { RateLimitConfig, setRateLimit } from './rateLimit/rateLimit.js';
|
|
5
|
+
import { apiKeyAuthorization } from './requestAuth/auth.middleware.js';
|
|
6
|
+
import { validateQueryParams, validateBodyJson } from './zod/validate.js';
|
|
7
|
+
export { CorsConfig, initCors, privateCors, publicCors };
|
|
8
|
+
export { RateLimitConfig, setRateLimit };
|
|
9
|
+
export { apiKeyAuthorization };
|
|
10
|
+
export { validateQueryParams, validateBodyJson };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { initCors } from './cors/cors.js';
|
|
2
|
+
import { privateCors } from './cors/privateCors.js';
|
|
3
|
+
import { publicCors } from './cors/publicCors.js';
|
|
4
|
+
import { setRateLimit } from './rateLimit/rateLimit.js';
|
|
5
|
+
import { apiKeyAuthorization } from './requestAuth/auth.middleware.js';
|
|
6
|
+
import { validateQueryParams, validateBodyJson } from './zod/validate.js';
|
|
7
|
+
export { initCors, privateCors, publicCors };
|
|
8
|
+
export { setRateLimit };
|
|
9
|
+
export { apiKeyAuthorization };
|
|
10
|
+
export { validateQueryParams, validateBodyJson };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import rateLimit from 'express-rate-limit';
|
|
2
|
+
const rateLimitConfig = {
|
|
3
|
+
windowMs: 60 * 1000,
|
|
4
|
+
max: 100,
|
|
5
|
+
};
|
|
6
|
+
export const setRateLimit = (app, customConfig) => {
|
|
7
|
+
const config = Object.assign(Object.assign({}, rateLimitConfig), customConfig);
|
|
8
|
+
const limiter = rateLimit(config);
|
|
9
|
+
app.use(limiter);
|
|
10
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isProd } from '../../express.js';
|
|
2
|
+
import { apiKey } from '../cors/cors.js';
|
|
3
|
+
export function apiKeyAuthorization(req, res, next) {
|
|
4
|
+
var _a;
|
|
5
|
+
if (!isProd) {
|
|
6
|
+
return next();
|
|
7
|
+
}
|
|
8
|
+
const key = (_a = req.headers['authorization']) === null || _a === void 0 ? void 0 : _a.split(' ')[1]; // Bearer <key>
|
|
9
|
+
if (!apiKey && (!key || key !== apiKey)) {
|
|
10
|
+
// failure(res, API_STATUS.UNAUTHORIZED, { message: Msg.connection.unauthorizedRequest} )
|
|
11
|
+
}
|
|
12
|
+
next();
|
|
13
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { ZodType } from 'zod';
|
|
3
|
+
export declare const validateQueryParams: (schema: ZodType) => (req: Request, res: Response, next: NextFunction) => void;
|
|
4
|
+
export declare const validateBodyJson: (schema: ZodType) => (req: Request, res: Response, next: NextFunction) => void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { failure, HttpResponseStatus } from '../../http/index.js';
|
|
2
|
+
export const validateQueryParams = (schema) => (req, res, next) => {
|
|
3
|
+
const result = schema.safeParse({
|
|
4
|
+
params: req.params,
|
|
5
|
+
query: req.query,
|
|
6
|
+
body: req.body,
|
|
7
|
+
});
|
|
8
|
+
if (!result.success) {
|
|
9
|
+
const issue = result.error.issues[0];
|
|
10
|
+
const { message } = issue;
|
|
11
|
+
failure(res, HttpResponseStatus.BAD_REQUEST, { message });
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
const data = result.data;
|
|
15
|
+
if (data.params)
|
|
16
|
+
req.params = data.params;
|
|
17
|
+
if (data.query)
|
|
18
|
+
req.query = data.query;
|
|
19
|
+
if (data.body)
|
|
20
|
+
req.body = data.body;
|
|
21
|
+
}
|
|
22
|
+
next();
|
|
23
|
+
};
|
|
24
|
+
export const validateBodyJson = (schema) => (req, res, next) => {
|
|
25
|
+
const result = schema.safeParse(req.body);
|
|
26
|
+
if (!result.success) {
|
|
27
|
+
const message = result.error.issues.map(i => i.message).join('; ');
|
|
28
|
+
failure(res, HttpResponseStatus.BAD_REQUEST, { message });
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
req.body = result.data;
|
|
32
|
+
}
|
|
33
|
+
next();
|
|
34
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import * as DbService from '../services/db.service.js';
|
|
11
|
+
import { HttpResponseStatus, serverError, success } from '../../http/index.js';
|
|
12
|
+
export const getDbTest = (_req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13
|
+
try {
|
|
14
|
+
const dbTime = yield DbService.getDatabaseTime();
|
|
15
|
+
return success(res, HttpResponseStatus.OK, dbTime);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
return serverError(res, err);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
export function getDbVersion(_req, res) {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
try {
|
|
24
|
+
const version = yield DbService.getDatabaseVersion();
|
|
25
|
+
return success(res, HttpResponseStatus.OK, version);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
return serverError(res, err);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { HttpResponseStatus, success } from '../../http/index.js';
|
|
2
|
+
import { isProd } from '../../express.js';
|
|
3
|
+
export const getHealth = (_req, res) => {
|
|
4
|
+
return success(res, HttpResponseStatus.OK, new Date().toISOString());
|
|
5
|
+
};
|
|
6
|
+
export const getEnv = (_req, res) => {
|
|
7
|
+
const data = {
|
|
8
|
+
isProduction: isProd,
|
|
9
|
+
};
|
|
10
|
+
return success(res, HttpResponseStatus.OK, data);
|
|
11
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { getPool } from '../../db/pg/connection/pool.js';
|
|
11
|
+
export function selectDatabaseTime() {
|
|
12
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
13
|
+
const pool = yield getPool();
|
|
14
|
+
const result = yield pool.query('SELECT NOW()');
|
|
15
|
+
return result.rows[0].now;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export function selectDatabaseVersion() {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
const pool = yield getPool();
|
|
21
|
+
const result = yield pool.query('SELECT version()');
|
|
22
|
+
return result.rows[0].version;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { getDbTest, getDbVersion } from '../controllers/db.controller.js';
|
|
3
|
+
const dbRouter = Router();
|
|
4
|
+
dbRouter.get('/test/', getDbTest);
|
|
5
|
+
dbRouter.get('/version/', getDbVersion);
|
|
6
|
+
export { dbRouter };
|
|
7
|
+
export default dbRouter;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { getHealth, getEnv } from '../controllers/health.controller.js';
|
|
3
|
+
const healthRouter = Router();
|
|
4
|
+
healthRouter.get('/', getHealth);
|
|
5
|
+
healthRouter.get('/environment', getEnv);
|
|
6
|
+
export { healthRouter };
|
|
7
|
+
export default healthRouter;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import * as dbRepository from '../repositories/db.repository.js';
|
|
11
|
+
export function getDatabaseTime() {
|
|
12
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
13
|
+
return dbRepository.selectDatabaseTime();
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function getDatabaseVersion() {
|
|
17
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
return dbRepository.selectDatabaseVersion();
|
|
19
|
+
});
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mielk-api",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"author": "mielk",
|
|
6
6
|
"description": "Wrapper for API operations",
|
|
@@ -13,19 +13,29 @@
|
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
15
|
},
|
|
16
|
-
"./
|
|
17
|
-
"types": "./dist/
|
|
18
|
-
"import": "./dist/
|
|
19
|
-
"default": "./dist/
|
|
16
|
+
"./db-mssql": {
|
|
17
|
+
"types": "./dist/db/mssql/index.d.ts",
|
|
18
|
+
"import": "./dist/db/mssql/index.js",
|
|
19
|
+
"default": "./dist/db/mssql/index.js"
|
|
20
20
|
},
|
|
21
|
-
"./
|
|
22
|
-
"types": "./dist/
|
|
23
|
-
"import": "./dist/
|
|
24
|
-
"default": "./dist/
|
|
21
|
+
"./db-pg": {
|
|
22
|
+
"types": "./dist/db/pg/index.d.ts",
|
|
23
|
+
"import": "./dist/db/pg/index.js",
|
|
24
|
+
"default": "./dist/db/pg/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./http": {
|
|
27
|
+
"types": "./dist/http/index.d.ts",
|
|
28
|
+
"import": "./dist/http/index.js",
|
|
29
|
+
"default": "./dist/http/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./middlewares": {
|
|
32
|
+
"types": "./dist/middlewares/index.d.ts",
|
|
33
|
+
"import": "./dist/middlewares/index.js",
|
|
34
|
+
"default": "./dist/middlewares/index.js"
|
|
25
35
|
}
|
|
26
36
|
},
|
|
27
37
|
"scripts": {
|
|
28
|
-
"test": "jest --detectOpenHandles",
|
|
38
|
+
"test": "jest --watchAll=false --detectOpenHandles",
|
|
29
39
|
"build": "tsc",
|
|
30
40
|
"prepublishOnly": "npm test && npm run build",
|
|
31
41
|
"dev": "tsc -w",
|
|
@@ -42,8 +52,12 @@
|
|
|
42
52
|
"@babel/core": "^7.25.8",
|
|
43
53
|
"@babel/node": "^7.25.7",
|
|
44
54
|
"@babel/preset-env": "^7.25.8",
|
|
55
|
+
"@types/cors": "^2.8.19",
|
|
56
|
+
"@types/express": "^5.0.6",
|
|
45
57
|
"@types/jest": "^30.0.0",
|
|
46
58
|
"@types/node": "^22.7.5",
|
|
59
|
+
"@types/pg": "^8.18.0",
|
|
60
|
+
"@types/tunnel-ssh": "^5.0.4",
|
|
47
61
|
"babel-jest": "^29.7.0",
|
|
48
62
|
"jest": "^30.3.0",
|
|
49
63
|
"jest-html-reporters": "^3.1.7",
|
|
@@ -55,7 +69,15 @@
|
|
|
55
69
|
"files": [
|
|
56
70
|
"dist"
|
|
57
71
|
],
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"express": "^5",
|
|
74
|
+
"express-rate-limit": "^8",
|
|
75
|
+
"zod": "^4"
|
|
76
|
+
},
|
|
58
77
|
"dependencies": {
|
|
59
|
-
"
|
|
78
|
+
"cors": "^2.8.6",
|
|
79
|
+
"mielk-fn": "^1.1.1",
|
|
80
|
+
"pg": "^8.20.0",
|
|
81
|
+
"tunnel-ssh": "^5.2.0"
|
|
60
82
|
}
|
|
61
83
|
}
|
package/dist/back/index.d.ts
DELETED
package/dist/back/index.js
DELETED
package/dist/front/index.d.ts
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|