Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion apps/space/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 5 additions & 0 deletions packages/decorators/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "es5"
}
6 changes: 1 addition & 5 deletions packages/decorators/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ userController.registerRoutes(router);
### WebSocket Controller

```typescript
import {
Controller,
WebSocket,
BaseWebSocketController,
} from "@plane/decorators";
import { Controller, WebSocket, BaseWebSocketController } from "@plane/decorators";
import { Request } from "express";
import { WebSocket as WS } from "ws";

Expand Down
20 changes: 4 additions & 16 deletions packages/decorators/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,23 @@
"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",
"check:lint": "eslint . --max-warnings 0",
"build": "tsc --noEmit && tsup --minify",
"dev": "tsup --watch",
"check:lint": "eslint . --max-warnings 1",
"check:types": "tsc --noEmit",
"check:format": "prettier --check \"**/*.{ts,tsx,md,json,css,scss}\"",
"fix:lint": "eslint . --fix",
"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
}
}
}
95 changes: 67 additions & 28 deletions packages/decorators/src/controller.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { RequestHandler, Router } from "express";
import type { RequestHandler, Router, Request } from "express";
import type { WebSocket } from "ws";

import "reflect-metadata";

type HttpMethod =
| "get"
| "post"
| "put"
| "delete"
| "patch"
| "options"
| "head"
| "ws";
type HttpMethod = "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "ws";

interface ControllerInstance {
[key: string]: unknown;
Expand All @@ -22,40 +16,85 @@

export function registerControllers(
router: Router,
Controller: ControllerConstructor,
controllers: ControllerConstructor[],
dependencies: any[] = []

Check warning on line 20 in packages/decorators/src/controller.ts

View workflow job for this annotation

GitHub Actions / Build and lint web apps

Unexpected any. Specify a different type
): 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 {
const instance = 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 HttpMethod;
const method = Reflect.getMetadata("method", instance, methodName) as HttpMethod;
const route = Reflect.getMetadata("route", instance, methodName) as string;
const middlewares =
(Reflect.getMetadata(
"middlewares",
instance,
methodName,
) as RequestHandler[]) || [];
const middlewares = (Reflect.getMetadata("middlewares", instance, methodName) as RequestHandler[]) || [];

if (method && route) {
const handler = instance[methodName] as unknown;

if (typeof handler === "function") {
if (method !== "ws") {
(
router[method] as (
path: string,
...handlers: RequestHandler[]
) => void
)(`${baseRoute}${route}`, ...middlewares, handler.bind(instance));
(router[method] as (path: string, ...handlers: RequestHandler[]) => void)(
`${baseRoute}${route}`,
...middlewares,
handler.bind(instance)
);
}
}
}
});
}

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");
}
});
}
}
});
}
1 change: 0 additions & 1 deletion packages/decorators/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
7 changes: 2 additions & 5 deletions packages/decorators/src/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ export function Controller(baseRoute: string = ""): ClassDecorator {
* @param method HTTP method to handle
* @returns Method decorator
*/
function createHttpMethodDecorator(
method: RestMethod,
): (route: string) => MethodDecorator {
function createHttpMethodDecorator(method: RestMethod): (route: string) => MethodDecorator {
return function (route: string): MethodDecorator {
return function (target: object, propertyKey: string | symbol) {
Reflect.defineMetadata("method", method, target, propertyKey);
Expand All @@ -46,8 +44,7 @@ export const Delete = createHttpMethodDecorator("delete");
*/
export function Middleware(middleware: RequestHandler): MethodDecorator {
return function (target: object, propertyKey: string | symbol) {
const middlewares =
Reflect.getMetadata("middlewares", target, propertyKey) || [];
const middlewares = Reflect.getMetadata("middlewares", target, propertyKey) || [];
middlewares.push(middleware);
Reflect.defineMetadata("middlewares", middlewares, target, propertyKey);
};
Expand Down
81 changes: 0 additions & 81 deletions packages/decorators/src/websocket-controller.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/decorators/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"lib": ["ES2020"],
"rootDir": ".",
"baseUrl": ".",

"paths": {
"@/*": ["./src/*"]
}
Expand Down
2 changes: 1 addition & 1 deletion packages/i18n/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
7 changes: 3 additions & 4 deletions packages/logger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
Loading
Loading