Enhance API routing and health check functionality
- Added ApiRouteTemplate as a base class for defining API routes - Implemented HealthCheckApi for health check endpoint management - Introduced IApiRoute interface for consistent route handling - Updated UserApiRoute to align with new routing structure - Added HealthCheck class for health status retrieval - Improved dependency management with new types and interfaces
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'bun:test';
|
import {describe, it, expect, beforeEach} from 'bun:test';
|
||||||
import { DependencyManager } from '../../src/di/DependencyManager';
|
import {DependencyManager} from '../../src/di/DependencyManager';
|
||||||
import { Logger, Database, UserService } from '../mocks';
|
import {Logger, Database, UserService} from '../mocks';
|
||||||
|
|
||||||
describe('When Managing Dependencies', () => {
|
describe('When Managing Dependencies', () => {
|
||||||
let dependencyManager: DependencyManager;
|
let dependencyManager: DependencyManager;
|
||||||
|
|||||||
45
bun.lock
45
bun.lock
@@ -3,16 +3,21 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "myoopapp",
|
"name": "myoopapp",
|
||||||
|
"dependencies": {
|
||||||
|
"@techniker-me/tools": "2025.0.16",
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.38.0",
|
"@eslint/js": "9.38.0",
|
||||||
"@eslint/json": "^0.13.2",
|
"@eslint/json": "0.13.2",
|
||||||
"@eslint/markdown": "^7.5.0",
|
"@eslint/markdown": "7.5.0",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"eslint": "^9.38.0",
|
"@types/express": "5.0.5",
|
||||||
"globals": "^16.4.0",
|
"@types/morgan": "1.9.10",
|
||||||
"jiti": "^2.6.1",
|
"eslint": "9.38.0",
|
||||||
|
"globals": "16.4.0",
|
||||||
|
"jiti": "2.6.1",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"typescript-eslint": "^8.46.2",
|
"typescript-eslint": "8.46.2",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
@@ -58,22 +63,46 @@
|
|||||||
|
|
||||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||||
|
|
||||||
|
"@techniker-me/tools": ["@techniker-me/tools@2025.0.16", "https://npm.techniker.me/@techniker-me/tools/-/tools-2025.0.16.tgz", {}, "sha512-Ul2yj1vd4lCO8g7IW2pHkAsdeRVEUMqGpiIvSedCc1joVXEWPbh4GESW83kMHtisjFjjlZIzb3EVlCE0BCiBWQ=="],
|
||||||
|
|
||||||
|
"@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="],
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="],
|
"@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="],
|
||||||
|
|
||||||
|
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
||||||
|
|
||||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
|
|
||||||
|
"@types/express": ["@types/express@5.0.5", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "^1" } }, "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ=="],
|
||||||
|
|
||||||
|
"@types/express-serve-static-core": ["@types/express-serve-static-core@5.1.0", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA=="],
|
||||||
|
|
||||||
|
"@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="],
|
||||||
|
|
||||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||||
|
|
||||||
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
|
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
|
||||||
|
|
||||||
|
"@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="],
|
||||||
|
|
||||||
|
"@types/morgan": ["@types/morgan@1.9.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA=="],
|
||||||
|
|
||||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@24.9.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA=="],
|
"@types/node": ["@types/node@24.9.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA=="],
|
||||||
|
|
||||||
|
"@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
|
||||||
|
|
||||||
|
"@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
|
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
|
||||||
|
|
||||||
|
"@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="],
|
||||||
|
|
||||||
|
"@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="],
|
||||||
|
|
||||||
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.2", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/type-utils": "8.46.2", "@typescript-eslint/utils": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.2", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w=="],
|
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.2", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/type-utils": "8.46.2", "@typescript-eslint/utils": "8.46.2", "@typescript-eslint/visitor-keys": "8.46.2", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.2", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w=="],
|
||||||
@@ -400,6 +429,8 @@
|
|||||||
|
|
||||||
"@eslint/markdown/@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.0", "", { "dependencies": { "@eslint/core": "^0.16.0", "levn": "^0.4.1" } }, "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A=="],
|
"@eslint/markdown/@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.0", "", { "dependencies": { "@eslint/core": "^0.16.0", "levn": "^0.4.1" } }, "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A=="],
|
||||||
|
|
||||||
|
"@types/serve-static/@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
"lint": "eslint --max-warnings 0 .",
|
"lint": "eslint --max-warnings 0 .",
|
||||||
"prelint:fix": "bun run format",
|
"prelint:fix": "bun run format",
|
||||||
"lint:fix": "eslint --fix .",
|
"lint:fix": "eslint --fix .",
|
||||||
|
"typecheck": "tsc --noEmit",
|
||||||
"test": "bun test",
|
"test": "bun test",
|
||||||
"test:watch": "bun test --watch"
|
"test:watch": "bun test --watch"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { LoggingLevel } from './logger/LoggingLevel';
|
import {LoggingLevel} from './logger/LoggingLevel';
|
||||||
|
|
||||||
export default class Defaults {
|
export default class Defaults {
|
||||||
static get loggingLevel(): LoggingLevel {
|
static get loggingLevel(): LoggingLevel {
|
||||||
|
|||||||
25
src/api/ApiRouteTemplate.ts
Normal file
25
src/api/ApiRouteTemplate.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import type {RoutePath, RouteHandler} from '../net/http/HttpRouteManger.js';
|
||||||
|
import type {IApiRoute} from './IApiRoute';
|
||||||
|
|
||||||
|
export abstract class ApiRouteTemplate implements IApiRoute {
|
||||||
|
private readonly _getRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _postRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _putRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _deleteRoutes: Record<string, RouteHandler> = {};
|
||||||
|
|
||||||
|
public getGETRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._getRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPOSTRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._postRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPUTRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._putRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDELETERoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._deleteRoutes;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/api/HealthCheckApi.ts
Normal file
43
src/api/HealthCheckApi.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import type {HealthCheck} from '../health/HealthCheck.js';
|
||||||
|
import type {RoutePath, RouteHandler} from '../net/http/HttpRouteManger.js';
|
||||||
|
import type {IApiRoute} from './IApiRoute';
|
||||||
|
import type express from 'express';
|
||||||
|
|
||||||
|
export class HealthCheckApi implements IApiRoute {
|
||||||
|
private readonly _getRoutes: Record<string, RouteHandler>;
|
||||||
|
private readonly _postRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _putRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _deleteRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _healthCheck: HealthCheck;
|
||||||
|
|
||||||
|
constructor(healthCheck: HealthCheck) {
|
||||||
|
this._healthCheck = healthCheck;
|
||||||
|
this._getRoutes = this.setupGETRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getGETRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._getRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPOSTRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._postRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPUTRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._putRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDELETERoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return this._deleteRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupGETRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
|
return {
|
||||||
|
'/_health': (req: express.Request, res: express.Response) => {
|
||||||
|
const health = this._healthCheck.getHealth();
|
||||||
|
|
||||||
|
res.send(health);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/api/IApiRoute.ts
Normal file
8
src/api/IApiRoute.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type {RouteHandler, RoutePath} from '../net/http/HttpRouteManger';
|
||||||
|
|
||||||
|
export interface IApiRoute {
|
||||||
|
getGETRoutes(): Record<RoutePath, RouteHandler>;
|
||||||
|
getPOSTRoutes(): Record<RoutePath, RouteHandler>;
|
||||||
|
getPUTRoutes(): Record<RoutePath, RouteHandler>;
|
||||||
|
getDELETERoutes(): Record<RoutePath, RouteHandler>;
|
||||||
|
}
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
import type { RouteHandler } from "../net/http/HttpRouteManger";
|
import type {RoutePath, RouteHandler} from '../net/http/HttpRouteManger';
|
||||||
|
import type {IApiRoute} from './IApiRoute';
|
||||||
|
|
||||||
|
export class UserApiRoute implements IApiRoute {
|
||||||
|
private readonly _getRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _postRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _putRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _deleteRoutes: Record<string, RouteHandler> = {};
|
||||||
|
|
||||||
export class UserApiRoute {
|
public getGETRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
private readonly _getRoutes: Record<string, RouteHandler> = {};
|
return this._getRoutes;
|
||||||
private readonly _postRoutes: Record<string, RouteHandler> = {};
|
}
|
||||||
private readonly _putRoutes: Record<string, RouteHandler> = {};
|
|
||||||
private readonly _deleteRoutes: Record<string, RouteHandler> = {};
|
|
||||||
|
|
||||||
public getGETRoutes(): Record<string, RouteHandler> {
|
public getPOSTRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
return this._getRoutes;
|
return this._postRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPOSTRoutes(): Record<string, RouteHandler> {
|
public getPUTRoutes(): Record<RoutePath, RouteHandler> {
|
||||||
return this._postRoutes;
|
return this._putRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPUTRoutes(): Record<string, RouteHandler> {
|
public getDELETERoutes(): Record<RoutePath, RouteHandler> {
|
||||||
return this._putRoutes;
|
return this._deleteRoutes;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public getDELETERoutes(): Record<string, RouteHandler> {
|
|
||||||
return this._deleteRoutes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ type Registration = {
|
|||||||
/**
|
/**
|
||||||
* Lifecycle types:
|
* Lifecycle types:
|
||||||
* - 'singleton': A single shared instance cached for the lifetime of the manager
|
* - 'singleton': A single shared instance cached for the lifetime of the manager
|
||||||
* - 'sergice': A single shared instance cached for the lifetime of the manager
|
* - 'service': A single shared instance cached for the lifetime of the manager
|
||||||
* - 'transient': A new instance created on each resolve (transient)
|
* - 'transient': A new instance created on each resolve (transient)
|
||||||
*/
|
*/
|
||||||
type Lifecycle = 'transient' | 'singleton';
|
type Lifecycle = 'transient' | 'singleton';
|
||||||
@@ -62,7 +62,7 @@ export class DependencyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const registration = this._registrations.get(name);
|
const registration = this._registrations.get(name);
|
||||||
const { Class, dependencies, lifecycle } = registration!;
|
const {Class, dependencies, lifecycle} = registration!;
|
||||||
|
|
||||||
if (lifecycle === 'singleton' && this._singletons.has(name)) {
|
if (lifecycle === 'singleton' && this._singletons.has(name)) {
|
||||||
console.debug(`↻ Using cached singleton [${name}]`);
|
console.debug(`↻ Using cached singleton [${name}]`);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Type } from "./Type";
|
import {Type} from './Type';
|
||||||
|
|
||||||
export class NamedType extends Type {
|
export class NamedType extends Type {
|
||||||
private readonly _name: string;
|
private readonly _name: string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Type } from "../Type";
|
import type {Type} from '../Type';
|
||||||
import type { NamedType } from "../NamedType";
|
import type {NamedType} from '../NamedType';
|
||||||
|
|
||||||
export interface IDependencyProvider {
|
export interface IDependencyProvider {
|
||||||
canProvide(type: Type | NamedType): boolean;
|
canProvide(type: Type | NamedType): boolean;
|
||||||
|
|||||||
13
src/health/HealthCheck.ts
Normal file
13
src/health/HealthCheck.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import type {ILogger} from '../logger/ILogger';
|
||||||
|
import LoggerFactory from '../logger/LoggerFactory';
|
||||||
|
|
||||||
|
export class HealthCheck {
|
||||||
|
private readonly _logger: ILogger = LoggerFactory.getLogger('HealthCheck');
|
||||||
|
|
||||||
|
public getHealth() {
|
||||||
|
return {
|
||||||
|
status: 'ok',
|
||||||
|
cpu: process.cpuUsage()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
export interface ILogger {
|
export interface ILogger {
|
||||||
info(message: string, ...optionalParams: unknown[]): void;
|
info(message: string, ...optionalParams: unknown[]): void;
|
||||||
debug(message: string, ...optionalParams: unknown[]): void;
|
debug(message: string, ...optionalParams: unknown[]): void;
|
||||||
warn(message: string, ...optionalParams: unknown[]): void;
|
warn(message: string, ...optionalParams: unknown[]): void;
|
||||||
error(message: string, ...optionalParams: unknown[]): void;
|
error(message: string, ...optionalParams: unknown[]): void;
|
||||||
trace(message: string, ...optionalParams: unknown[]): void;
|
trace(message: string, ...optionalParams: unknown[]): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { ILogger } from './ILogger';
|
import type {ILogger} from './ILogger';
|
||||||
import { LoggingLevel } from './LoggingLevel';
|
import {LoggingLevel} from './LoggingLevel';
|
||||||
import type { Threshold } from './Threshold';
|
import type {Threshold} from './Threshold';
|
||||||
import type { IAppender } from './appenders/IAppender';
|
import type {IAppender} from './appenders/IAppender';
|
||||||
import LoggingLevelMapping from './LoggingLevelMapping';
|
import LoggingLevelMapping from './LoggingLevelMapping';
|
||||||
|
|
||||||
export default class Logger implements ILogger {
|
export default class Logger implements ILogger {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { IAppender } from "./appenders/IAppender";
|
import type {IAppender} from './appenders/IAppender';
|
||||||
import Logger from './Logger';
|
import Logger from './Logger';
|
||||||
import type { LoggingLevelType } from "./LoggingLevel";
|
import type {LoggingLevelType} from './LoggingLevel';
|
||||||
import LoggingLevelMapping from "./LoggingLevelMapping";
|
import LoggingLevelMapping from './LoggingLevelMapping';
|
||||||
import { Threshold } from "./Threshold";
|
import {Threshold} from './Threshold';
|
||||||
import ConsoleAppender from "./appenders/ConsoleAppender";
|
import ConsoleAppender from './appenders/ConsoleAppender';
|
||||||
import Disposable from "../lang/disposables/Disposable";
|
import Disposable from '../lang/disposables/Disposable';
|
||||||
|
|
||||||
type Category = string;
|
type Category = string;
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ export enum LoggingLevel {
|
|||||||
All = 70
|
All = 70
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoggingLevelType = 'Off' | 'Debug' | 'Trace' | 'Info' | 'Silly' | 'Warn' | 'Error' | 'All';
|
export type LoggingLevelType = 'Off' | 'Debug' | 'Trace' | 'Info' | 'Silly' | 'Warn' | 'Error' | 'All';
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import {assertUnreachable} from '@techniker-me/tools';
|
import {assertUnreachable} from '@techniker-me/tools';
|
||||||
import {LoggingLevel, type LoggingLevelType} from './LoggingLevel';
|
import {LoggingLevel, type LoggingLevelType} from './LoggingLevel';
|
||||||
|
|
||||||
@@ -49,4 +48,4 @@ export default class LoggingLevelMapping {
|
|||||||
assertUnreachable(loggingLevelType);
|
assertUnreachable(loggingLevelType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Defaults from '../Defaults';
|
import Defaults from '../Defaults';
|
||||||
import { Subject } from '../lang/observables';
|
import {Subject} from '../lang/observables';
|
||||||
import { LoggingLevel } from './LoggingLevel';
|
import {LoggingLevel} from './LoggingLevel';
|
||||||
|
|
||||||
export class Threshold {
|
export class Threshold {
|
||||||
private _threshold: Subject<LoggingLevel>;
|
private _threshold: Subject<LoggingLevel>;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {LoggingLevel, type LoggingLevelType} from '../LoggingLevel';
|
import {type LoggingLevelType} from '../LoggingLevel';
|
||||||
import type ILogMessage from './LogMessage';
|
import type ILogMessage from './LogMessage';
|
||||||
|
|
||||||
export type AppenderOptions = {
|
export type AppenderOptions = {
|
||||||
@@ -7,7 +7,7 @@ export type AppenderOptions = {
|
|||||||
|
|
||||||
export default class Appender {
|
export default class Appender {
|
||||||
private readonly _logRecorderUrl: string = 'https://logserver.techniker.me/api/logs';
|
private readonly _logRecorderUrl: string = 'https://logserver.techniker.me/api/logs';
|
||||||
// @ts-ignore
|
// @ts-expect-error browser vs node
|
||||||
private readonly _domain: string = typeof globalThis !== 'undefined' ? (globalThis.location?.hostname ?? '') : '';
|
private readonly _domain: string = typeof globalThis !== 'undefined' ? (globalThis.location?.hostname ?? '') : '';
|
||||||
private readonly _logMessageQueue: ILogMessage[] = [];
|
private readonly _logMessageQueue: ILogMessage[] = [];
|
||||||
private _pendingPostLogMessagePromise: Promise<Response | undefined> | undefined = undefined;
|
private _pendingPostLogMessagePromise: Promise<Response | undefined> | undefined = undefined;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Appender from './Appender';
|
import Appender from './Appender';
|
||||||
import type { AppenderOptions } from './Appender';
|
import type {AppenderOptions} from './Appender';
|
||||||
|
|
||||||
export default class AppnederFactory {
|
export default class AppnederFactory {
|
||||||
public static createRemoteAppender(remoteAppenderUrl: string, {domain}: AppenderOptions): Appender {
|
public static createRemoteAppender(remoteAppenderUrl: string, {domain}: AppenderOptions): Appender {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { LoggingLevelType } from '../LoggingLevel';
|
import type {LoggingLevelType} from '../LoggingLevel';
|
||||||
|
|
||||||
export interface IAppender {
|
export interface IAppender {
|
||||||
log(timestamp: string, level: LoggingLevelType, category: string, message: string): void;
|
log(timestamp: string, level: LoggingLevelType, category: string, message: string): void;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type {LoggingLevel, LoggingLevelType} from '../LoggingLevel';
|
import type {LoggingLevelType} from '../LoggingLevel';
|
||||||
import type {IAppender} from './IAppender';
|
import type {IAppender} from './IAppender';
|
||||||
import type ILogMessage from './LogMessage';
|
import type ILogMessage from './LogMessage';
|
||||||
|
|
||||||
export default class TechnikerMeAppender implements IAppender {
|
export default class TechnikerMeAppender implements IAppender {
|
||||||
private readonly _logRecorderUrl: string = 'https://logserver.techniker.me/api/logs';
|
private readonly _logRecorderUrl: string = 'https://logserver.techniker.me/api/logs';
|
||||||
// @ts-ignore
|
// @ts-expect-error browser vs node
|
||||||
private readonly _domain: string = typeof globalThis !== 'undefined' ? (globalThis.location?.hostname ?? '') : '';
|
private readonly _domain: string = typeof globalThis !== 'undefined' ? (globalThis.location?.hostname ?? '') : '';
|
||||||
private readonly _logMessageQueue: ILogMessage[] = [];
|
private readonly _logMessageQueue: ILogMessage[] = [];
|
||||||
private _pendingPostLogMessagePromise: Promise<Response | undefined> | undefined = undefined;
|
private _pendingPostLogMessagePromise: Promise<Response | undefined> | undefined = undefined;
|
||||||
|
|||||||
Reference in New Issue
Block a user