fix: adding new logger and docorator changes

This commit is contained in:
Sriram Veeraghanta
2025-08-29 01:23:36 +05:30
15 changed files with 122 additions and 149 deletions

View File

@@ -45,7 +45,7 @@
"@plane/eslint-config": "workspace:*",
"@plane/tailwind-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/lodash": "^4.17.6",
"@types/lodash": "4.17.20",
"@types/node": "18.16.1",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.2.18",

View File

@@ -58,7 +58,7 @@
"@plane/eslint-config": "workspace:*",
"@plane/tailwind-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/lodash": "^4.17.6",
"@types/lodash": "4.17.20",
"@types/node": "18.14.1",
"@types/nprogress": "^0.2.0",
"@types/react": "^18.3.11",

View File

@@ -72,7 +72,7 @@
"@plane/eslint-config": "workspace:*",
"@plane/tailwind-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/lodash": "^4.17.6",
"@types/lodash": "4.17.20",
"@types/node": "18.16.1",
"@types/react": "^18.3.11",
"@types/react-color": "^3.0.6",

View File

@@ -11,8 +11,8 @@
"dist/**"
],
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts --external express,ws",
"dev": "tsup src/index.ts --format esm,cjs --watch --dts --external express,ws",
"build": "tsc --noEmit && tsup --minify",
"dev": "tsup --watch",
"check:lint": "eslint . --max-warnings 0",
"check:types": "tsc --noEmit",
"check:format": "prettier --check \"**/*.{ts,tsx,md,json,css,scss}\"",
@@ -20,26 +20,14 @@
"fix:format": "prettier --write \"**/*.{ts,tsx,md,json,css,scss}\"",
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist"
},
"dependencies": {
"express": "^4.21.2",
"reflect-metadata": "^0.2.2"
},
"devDependencies": {
"@plane/eslint-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/express": "^4.17.21",
"@types/node": "^20.14.9",
"@types/ws": "^8.5.10",
"reflect-metadata": "^0.2.2",
"tsup": "8.4.0",
"typescript": "5.8.3"
},
"peerDependencies": {
"express": ">=4.21.2",
"ws": ">=8.0.0"
},
"peerDependenciesMeta": {
"ws": {
"optional": true
}
}
}

View File

@@ -1,4 +1,6 @@
import { RequestHandler, Router } from "express";
import type { RequestHandler, Router, Request } from "express";
import type { WebSocket } from "ws";
import "reflect-metadata";
type HttpMethod =
@@ -21,6 +23,35 @@ interface ControllerConstructor {
}
export function registerControllers(
router: Router,
controllers: ControllerConstructor[],
dependencies: any[] = []
): void {
controllers.forEach((Controller) => {
// Create the controller instance with dependencies
const instance = new Controller(...dependencies);
// Determine if it's a WebSocket controller or REST controller by checking
// if it has any methods with the "ws" method metadata
const isWebsocket = Object.getOwnPropertyNames(Controller.prototype).some(
(methodName) => {
if (methodName === "constructor") return false;
return Reflect.getMetadata("method", instance, methodName) === "ws";
}
);
if (isWebsocket) {
// Register as WebSocket controller
// Pass the existing instance with dependencies to avoid creating a new instance without them
registerWebSocketController(router, Controller, instance);
} else {
// Register as REST controller - doesn't accept an instance parameter
registerRestController(router, Controller);
}
});
}
function registerRestController(
router: Router,
Controller: ControllerConstructor
): void {
@@ -59,3 +90,48 @@ export function registerControllers(
}
});
}
function registerWebSocketController(
router: Router,
Controller: ControllerConstructor,
existingInstance?: ControllerInstance
): void {
const instance = existingInstance || new Controller();
const baseRoute = Reflect.getMetadata("baseRoute", Controller) as string;
Object.getOwnPropertyNames(Controller.prototype).forEach((methodName) => {
if (methodName === "constructor") return; // Skip the constructor
const method = Reflect.getMetadata(
"method",
instance,
methodName
) as string;
const route = Reflect.getMetadata("route", instance, methodName) as string;
if (method === "ws" && route) {
const handler = instance[methodName] as unknown;
if (
typeof handler === "function" &&
"ws" in router &&
typeof router.ws === "function"
) {
router.ws(`${baseRoute}${route}`, (ws: WebSocket, req: Request) => {
try {
handler.call(instance, ws, req);
} catch (error) {
console.error(
`WebSocket error in ${Controller.name}.${methodName}`,
error
);
ws.close(
1011,
error instanceof Error ? error.message : "Internal server error"
);
}
});
}
}
});
}

View File

@@ -3,7 +3,6 @@ export { Controller, Middleware } from "./rest";
export { Get, Post, Put, Patch, Delete } from "./rest";
export { WebSocket } from "./websocket";
export { registerControllers } from "./controller";
export { registerWebSocketControllers } from "./websocket-controller";
// Also provide namespaced exports for better organization
import * as RestDecorators from "./rest";

View File

@@ -1,81 +0,0 @@
import { Router, Request } from "express";
import type { WebSocket } from "ws";
import "reflect-metadata";
interface ControllerInstance {
[key: string]: unknown;
}
interface ControllerConstructor {
new (...args: unknown[]): ControllerInstance;
prototype: ControllerInstance;
}
export function registerWebSocketControllers(
router: Router,
Controller: ControllerConstructor,
existingInstance?: ControllerInstance
): void {
const instance = existingInstance || new Controller();
const baseRoute = Reflect.getMetadata("baseRoute", Controller) as string;
Object.getOwnPropertyNames(Controller.prototype).forEach((methodName) => {
if (methodName === "constructor") return; // Skip the constructor
const method = Reflect.getMetadata(
"method",
instance,
methodName
) as string;
const route = Reflect.getMetadata("route", instance, methodName) as string;
if (method === "ws" && route) {
const handler = instance[methodName] as unknown;
if (
typeof handler === "function" &&
"ws" in router &&
typeof router.ws === "function"
) {
router.ws(`${baseRoute}${route}`, (ws: WebSocket, req: Request) => {
try {
handler.call(instance, ws, req);
} catch (error) {
console.error(
`WebSocket error in ${Controller.name}.${methodName}`,
error
);
ws.close(
1011,
error instanceof Error ? error.message : "Internal server error"
);
}
});
}
}
});
}
/**
* Base controller class for WebSocket endpoints
*/
export abstract class BaseWebSocketController {
protected router: Router;
constructor() {
this.router = Router();
}
/**
* Get the base route for this controller
*/
protected getBaseRoute(): string {
return Reflect.getMetadata("baseRoute", this.constructor) || "";
}
/**
* Abstract method to handle WebSocket connections
* Implement this in your derived class
*/
abstract handleConnection(ws: WebSocket, req: Request): void;
}

View File

@@ -6,7 +6,6 @@
"lib": ["ES2020"],
"rootDir": ".",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}

View File

@@ -25,7 +25,7 @@
"@plane/eslint-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/node": "^22.5.4",
"@types/lodash": "^4.17.6",
"@types/lodash": "4.17.20",
"@types/react": "^18.3.11",
"typescript": "5.8.3"
}

View File

@@ -28,15 +28,14 @@
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist"
},
"dependencies": {
"express": "^4.21.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"
"express-winston": "^4.2.0",
"winston": "^3.17.0"
},
"devDependencies": {
"@plane/eslint-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/express": "^4.17.21",
"@types/node": "^22.5.4",
"@types/node": "^20.14.9",
"tsup": "8.4.0",
"typescript": "5.8.3"
}

View File

@@ -1,4 +1,4 @@
import { createLogger, format, transports, LoggerOptions } from "winston";
import { createLogger, format, LoggerOptions, transports } from "winston";
export const loggerConfig: LoggerOptions = {
level: process.env.LOG_LEVEL || "info",

View File

@@ -1,8 +1,9 @@
import type { RequestHandler } from "express";
import expressWinston from "express-winston";
import { transports } from "winston";
import { loggerConfig } from "./config";
export const loggerMiddleware = expressWinston.logger({
export const loggerMiddleware: RequestHandler = expressWinston.logger({
...loggerConfig,
transports: [new transports.Console()],
msg: "{{req.method}} {{req.url}} {{res.statusCode}} {{res.responseTime}}ms",

View File

@@ -66,7 +66,7 @@
"@storybook/react": "^8.1.1",
"@storybook/react-webpack5": "^8.1.1",
"@storybook/test": "^8.1.1",
"@types/lodash": "^4.17.6",
"@types/lodash": "4.17.20",
"@types/node": "^20.5.2",
"@types/react": "^18.3.11",
"@types/react-color": "^3.0.9",

View File

@@ -36,7 +36,7 @@
"devDependencies": {
"@plane/eslint-config": "workspace:*",
"@plane/typescript-config": "workspace:*",
"@types/lodash": "^4.17.6",
"@types/lodash": "4.17.20",
"@types/node": "^22.5.4",
"@types/react": "^18.3.11",
"@types/uuid": "^9.0.8",

68
pnpm-lock.yaml generated
View File

@@ -113,8 +113,8 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript-config
'@types/lodash':
specifier: ^4.17.6
version: 4.17.18
specifier: 4.17.20
version: 4.17.20
'@types/node':
specifier: 18.16.1
version: 18.16.1
@@ -385,8 +385,8 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript-config
'@types/lodash':
specifier: ^4.17.6
version: 4.17.18
specifier: 4.17.20
version: 4.17.20
'@types/node':
specifier: 18.14.1
version: 18.14.1
@@ -515,7 +515,7 @@ importers:
version: 0.2.1(next@14.2.30(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
posthog-js:
specifier: ^1.131.3
version: 1.258.5
version: 1.255.1
react:
specifier: ^18.3.1
version: 18.3.1
@@ -578,8 +578,8 @@ importers:
specifier: workspace:*
version: link:../../packages/typescript-config
'@types/lodash':
specifier: ^4.17.6
version: 4.17.18
specifier: 4.17.20
version: 4.17.20
'@types/node':
specifier: 18.16.1
version: 18.16.1
@@ -628,16 +628,6 @@ importers:
version: 5.8.3
packages/decorators:
dependencies:
express:
specifier: ^4.21.2
version: 4.21.2
reflect-metadata:
specifier: ^0.2.2
version: 0.2.2
ws:
specifier: '>=8.0.0'
version: 8.18.3
devDependencies:
'@plane/eslint-config':
specifier: workspace:*
@@ -654,6 +644,9 @@ importers:
'@types/ws':
specifier: ^8.5.10
version: 8.18.1
reflect-metadata:
specifier: ^0.2.2
version: 0.2.2
tsup:
specifier: 8.4.0
version: 8.4.0(@swc/core@1.13.3(@swc/helpers@0.5.17))(jiti@1.21.7)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1)
@@ -910,8 +903,8 @@ importers:
specifier: workspace:*
version: link:../typescript-config
'@types/lodash':
specifier: ^4.17.6
version: 4.17.18
specifier: 4.17.20
version: 4.17.20
'@types/node':
specifier: ^22.5.4
version: 22.17.2
@@ -937,6 +930,12 @@ importers:
'@plane/typescript-config':
specifier: workspace:*
version: link:../typescript-config
'@types/express':
specifier: 4.17.23
version: 4.17.23
'@types/node':
specifier: ^20.14.9
version: 20.19.11
tsup:
specifier: 8.4.0
version: 8.4.0(@swc/core@1.13.3(@swc/helpers@0.5.17))(jiti@1.21.7)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1)
@@ -1224,8 +1223,8 @@ importers:
specifier: ^8.1.1
version: 8.6.14(storybook@8.6.14(prettier@3.6.2))
'@types/lodash':
specifier: ^4.17.6
version: 4.17.18
specifier: 4.17.20
version: 4.17.20
'@types/node':
specifier: ^20.5.2
version: 20.19.11
@@ -1300,8 +1299,8 @@ importers:
specifier: workspace:*
version: link:../typescript-config
'@types/lodash':
specifier: ^4.17.6
version: 4.17.18
specifier: 4.17.20
version: 4.17.20
'@types/node':
specifier: ^22.5.4
version: 22.17.2
@@ -3261,8 +3260,8 @@ packages:
'@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/lodash@4.17.18':
resolution: {integrity: sha512-KJ65INaxqxmU6EoCiJmRPZC9H9RVWCRd349tXM2M3O5NA7cY6YL7c0bHAHQ93NOfTObEQ004kd2QVHs/r0+m4g==}
'@types/lodash@4.17.20':
resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==}
'@types/markdown-it@13.0.9':
resolution: {integrity: sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==}
@@ -3300,9 +3299,6 @@ packages:
'@types/node@20.19.11':
resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==}
'@types/node@20.19.4':
resolution: {integrity: sha512-OP+We5WV8Xnbuvw0zC2m4qfB/BJvjyCwtNjhHdJxV1639SGSKrLmJkc3fMnp2Qy8nJyHp8RO6umxELN/dS1/EA==}
'@types/node@22.17.2':
resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==}
@@ -6378,8 +6374,8 @@ packages:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
posthog-js@1.258.5:
resolution: {integrity: sha512-Tx6CzS8MsGAQGPrQth5TbkGxGQgAY01SktNW773/KDmVOWiRVZq/WQF/MRJRiuFxJ7qjethZQi3aBWfWKdr1RA==}
posthog-js@1.255.1:
resolution: {integrity: sha512-KMh0o9MhORhEZVjXpktXB5rJ8PfDk+poqBoTSoLzWgNjhJf6D8jcyB9jUMA6vVPfn4YeepVX5NuclDRqOwr5Mw==}
peerDependencies:
'@rrweb/types': 2.0.0-alpha.17
rrweb-snapshot: 2.0.0-alpha.17
@@ -10063,7 +10059,7 @@ snapshots:
'@types/linkify-it@5.0.0': {}
'@types/lodash@4.17.18': {}
'@types/lodash@4.17.20': {}
'@types/markdown-it@13.0.9':
dependencies:
@@ -10099,10 +10095,6 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/node@20.19.4':
dependencies:
undici-types: 6.21.0
'@types/node@22.17.2':
dependencies:
undici-types: 6.21.0
@@ -10125,7 +10117,7 @@ snapshots:
'@types/pino@6.3.12':
dependencies:
'@types/node': 20.19.4
'@types/node': 20.19.11
'@types/pino-pretty': 5.0.0
'@types/pino-std-serializers': 4.0.0
sonic-boom: 2.8.0
@@ -12591,7 +12583,7 @@ snapshots:
jest-worker@27.5.1:
dependencies:
'@types/node': 20.19.4
'@types/node': 20.19.11
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -13550,7 +13542,7 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
posthog-js@1.258.5:
posthog-js@1.255.1:
dependencies:
core-js: 3.45.0
fflate: 0.4.8