bootifyjs 0.0.1 → 0.0.3
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/README.md +567 -0
- package/package.json +1 -1
- package/src/application/Application.ts +0 -355
- package/src/container/container.ts +0 -28
- package/src/decorators/cache/ICacheClient.ts +0 -5
- package/src/decorators/cache/cache.decorator.ts +0 -36
- package/src/decorators/controller.decorator.ts +0 -119
- package/src/decorators/http.decorator.ts +0 -25
- package/src/decorators/timing.decorator.ts +0 -23
- package/src/decorators/transaction/IDatabaseClient.ts +0 -9
- package/src/decorators/transaction/transactional.decorator.ts +0 -24
- package/src/index.ts +0 -10
- package/src/logger/Logger.ts +0 -179
- package/src/middleware/http.ts +0 -81
- package/src/middleware/requestcontext.ts +0 -12
@@ -1,355 +0,0 @@
|
|
1
|
-
import Fastify, {
|
2
|
-
FastifyInstance,
|
3
|
-
FastifyPluginAsync,
|
4
|
-
FastifyPluginCallback,
|
5
|
-
FastifyServerOptions,
|
6
|
-
} from 'fastify';
|
7
|
-
import { registerControllers } from '../decorators/controller.decorator';
|
8
|
-
import Logger from '../logger/Logger';
|
9
|
-
import { requestContext } from '../middleware/requestcontext';
|
10
|
-
import { httpLoggerMiddleware } from '../middleware/http';
|
11
|
-
|
12
|
-
interface FastifyServerConfig {
|
13
|
-
port?: number;
|
14
|
-
host?: string;
|
15
|
-
route?: FastifyPluginCallback | FastifyPluginAsync;
|
16
|
-
enableCors?: boolean;
|
17
|
-
enableSwagger?: boolean;
|
18
|
-
enableLogging?: boolean;
|
19
|
-
enableErrorHandling?: boolean;
|
20
|
-
enableDatabase?: boolean;
|
21
|
-
enableRedis?: boolean;
|
22
|
-
corsOptions?: {
|
23
|
-
origin?: string | string[];
|
24
|
-
methods?: string[];
|
25
|
-
credentials?: boolean;
|
26
|
-
};
|
27
|
-
swaggerOptions?: {
|
28
|
-
routePrefix?: string;
|
29
|
-
swaggerDoc?: any;
|
30
|
-
};
|
31
|
-
enableMetrics?: boolean;
|
32
|
-
enableCookie?: boolean;
|
33
|
-
enableAuth?: boolean;
|
34
|
-
}
|
35
|
-
|
36
|
-
export class Application {
|
37
|
-
private server: FastifyInstance;
|
38
|
-
private config: FastifyServerConfig;
|
39
|
-
|
40
|
-
constructor(config: FastifyServerConfig = {}) {
|
41
|
-
this.config = {
|
42
|
-
port: 3000,
|
43
|
-
host: '0.0.0.0',
|
44
|
-
enableCors: true,
|
45
|
-
enableSwagger: false,
|
46
|
-
enableLogging: true,
|
47
|
-
enableErrorHandling: true,
|
48
|
-
enableDatabase: false,
|
49
|
-
enableRedis: false,
|
50
|
-
enableCookie: false,
|
51
|
-
enableAuth: false,
|
52
|
-
enableMetrics: false,
|
53
|
-
corsOptions: {
|
54
|
-
origin: [
|
55
|
-
'http://localhost:4000',
|
56
|
-
'http://localhost:3000',
|
57
|
-
'http://localhost:5173',
|
58
|
-
],
|
59
|
-
methods: ['GET', 'PUT', 'PATCH', 'POST', 'DELETE'],
|
60
|
-
credentials: true,
|
61
|
-
},
|
62
|
-
swaggerOptions: {
|
63
|
-
routePrefix: '/docs',
|
64
|
-
swaggerDoc: {
|
65
|
-
info: {
|
66
|
-
title: 'API Documentation',
|
67
|
-
version: '1.0.0',
|
68
|
-
},
|
69
|
-
},
|
70
|
-
},
|
71
|
-
...config,
|
72
|
-
};
|
73
|
-
|
74
|
-
this.server = Fastify({
|
75
|
-
ajv: {
|
76
|
-
customOptions: {
|
77
|
-
strict: false,
|
78
|
-
},
|
79
|
-
},
|
80
|
-
genReqId: (req) => {
|
81
|
-
const requestId = req.headers['x-request-id'];
|
82
|
-
return Array.isArray(requestId) ? requestId[0] : requestId || crypto.randomUUID();
|
83
|
-
},
|
84
|
-
});
|
85
|
-
|
86
|
-
this.setupServer();
|
87
|
-
}
|
88
|
-
|
89
|
-
private async setupServer() {
|
90
|
-
try {
|
91
|
-
// Register CORS
|
92
|
-
// if (this.config.enableCors) {
|
93
|
-
// Logger.info('Registering CORS');
|
94
|
-
// await this.server.register(require('@fastify/cors'), this.config.corsOptions);
|
95
|
-
// }
|
96
|
-
|
97
|
-
// Register Swagger
|
98
|
-
// if (this.config.enableSwagger) {
|
99
|
-
// await this.server.register(require('@fastify/swagger'), this.config.swaggerOptions?.swaggerDoc);
|
100
|
-
// await this.server.register(require('@fastify/swagger-ui'), {
|
101
|
-
// routePrefix: this.config.swaggerOptions?.routePrefix,
|
102
|
-
// });
|
103
|
-
// }
|
104
|
-
|
105
|
-
// Register Cookie support
|
106
|
-
// if (this.config.enableCookie) {
|
107
|
-
// await this.server.register(require('@fastify/cookie'), {
|
108
|
-
// hook: 'onRequest',
|
109
|
-
// parseOptions: {},
|
110
|
-
// });
|
111
|
-
// }
|
112
|
-
|
113
|
-
// Register Metrics
|
114
|
-
// if (this.config.enableMetrics) {
|
115
|
-
// await this.server.register(require('fastify-metrics'), {
|
116
|
-
// endpoint: '/metrics',
|
117
|
-
// });
|
118
|
-
// }
|
119
|
-
|
120
|
-
// Register error handling
|
121
|
-
if (this.config.enableErrorHandling) {
|
122
|
-
this.server.setErrorHandler(this.globalErrorHandler);
|
123
|
-
}
|
124
|
-
|
125
|
-
// Add common schemas
|
126
|
-
this.addCommonSchemas();
|
127
|
-
|
128
|
-
// Add logging hooks
|
129
|
-
if (this.config.enableLogging) {
|
130
|
-
this.setupLogging();
|
131
|
-
}
|
132
|
-
|
133
|
-
// Setup route logging
|
134
|
-
this.setupRouteLogging();
|
135
|
-
|
136
|
-
// Register custom routes
|
137
|
-
if (this.config.route) {
|
138
|
-
await this.server.register(this.config.route);
|
139
|
-
}
|
140
|
-
|
141
|
-
} catch (error) {
|
142
|
-
Logger.error('Failed to setup server:', error as Error);
|
143
|
-
throw error;
|
144
|
-
}
|
145
|
-
}
|
146
|
-
|
147
|
-
private globalErrorHandler = (error: any, request: any, reply: any) => {
|
148
|
-
Logger.error('Global error handler:', error);
|
149
|
-
|
150
|
-
const statusCode = error.statusCode || 500;
|
151
|
-
const message = error.message || 'Internal Server Error';
|
152
|
-
|
153
|
-
reply.status(statusCode).send({
|
154
|
-
statusCode,
|
155
|
-
error: error.name || 'Error',
|
156
|
-
message,
|
157
|
-
});
|
158
|
-
};
|
159
|
-
|
160
|
-
private addCommonSchemas() {
|
161
|
-
this.server.addSchema({
|
162
|
-
$id: 'errorResponseSchema',
|
163
|
-
type: 'object',
|
164
|
-
description: 'Error Response',
|
165
|
-
properties: {
|
166
|
-
statusCode: { type: 'number' },
|
167
|
-
error: { type: 'string' },
|
168
|
-
message: { type: 'string' },
|
169
|
-
},
|
170
|
-
});
|
171
|
-
|
172
|
-
this.server.addSchema({
|
173
|
-
$id: 'messageResponseSchema',
|
174
|
-
type: 'object',
|
175
|
-
description: 'Message Response',
|
176
|
-
properties: {
|
177
|
-
message: { type: 'string' },
|
178
|
-
},
|
179
|
-
});
|
180
|
-
}
|
181
|
-
|
182
|
-
private setupLogging() {
|
183
|
-
// requestContext.run
|
184
|
-
|
185
|
-
this.server.addHook('preHandler', (request, reply, done) => {
|
186
|
-
request.raw.id = request.id
|
187
|
-
reply.header('x-request-id', request.id)
|
188
|
-
httpLoggerMiddleware(request.raw, reply.raw)
|
189
|
-
// console.log('Request ID:', request.id)
|
190
|
-
// console.log('User ID:', request.user)
|
191
|
-
|
192
|
-
requestContext.run(
|
193
|
-
{ requestId: request.id, userId: "pxpxpx", username: "priyadarship4@gmail.com" },
|
194
|
-
() => {
|
195
|
-
done()
|
196
|
-
}
|
197
|
-
)
|
198
|
-
})
|
199
|
-
|
200
|
-
// this.server.addHook('onRequest', async (request, reply) => {
|
201
|
-
// const startTime = Date.now();
|
202
|
-
// request.raw.startTime = startTime;
|
203
|
-
// reply.header('x-request-id', request.id);
|
204
|
-
|
205
|
-
// Logger.info({
|
206
|
-
// requestId: request.id,
|
207
|
-
// method: request.method,
|
208
|
-
// url: request.url,
|
209
|
-
// userAgent: request.headers['user-agent'],
|
210
|
-
// ip: request.ip,
|
211
|
-
// message: 'Incoming request'
|
212
|
-
// });
|
213
|
-
// });
|
214
|
-
|
215
|
-
// this.server.addHook('onResponse', async (request, reply) => {
|
216
|
-
// const duration = Date.now() - (request.raw.startTime || Date.now());
|
217
|
-
|
218
|
-
// Logger.info({
|
219
|
-
// requestId: request.id,
|
220
|
-
// method: request.method,
|
221
|
-
// url: request.url,
|
222
|
-
// statusCode: reply.statusCode,
|
223
|
-
// duration: `${duration}ms`,
|
224
|
-
// message: 'Request completed'
|
225
|
-
// });
|
226
|
-
// });
|
227
|
-
}
|
228
|
-
|
229
|
-
private setupRouteLogging() {
|
230
|
-
const routeOptions: any[] = [];
|
231
|
-
|
232
|
-
this.server.addHook('onRoute', (routeOption) => {
|
233
|
-
routeOptions.push(routeOption);
|
234
|
-
});
|
235
|
-
|
236
|
-
this.server.addHook('onReady', (done) => {
|
237
|
-
this.printFastifyRoutes(routeOptions, { colors: true });
|
238
|
-
done();
|
239
|
-
});
|
240
|
-
}
|
241
|
-
|
242
|
-
private printFastifyRoutes(routeOptions: any[], opts: { colors: boolean }) {
|
243
|
-
const { colors } = opts;
|
244
|
-
|
245
|
-
if (routeOptions.length === 0) {
|
246
|
-
return;
|
247
|
-
}
|
248
|
-
|
249
|
-
routeOptions.sort((a, b) => a.url.localeCompare(b.url));
|
250
|
-
|
251
|
-
const logEntries = [];
|
252
|
-
logEntries.push("Available routes:");
|
253
|
-
|
254
|
-
for (const routeOption of routeOptions) {
|
255
|
-
const { method, url } = routeOption;
|
256
|
-
if (method === "HEAD") continue;
|
257
|
-
const formattedMethod = colors ? this.colorMethod(method) : method;
|
258
|
-
logEntries.push(`${formattedMethod}\t${url}`);
|
259
|
-
}
|
260
|
-
|
261
|
-
Logger.info(logEntries.join("\n"));
|
262
|
-
}
|
263
|
-
|
264
|
-
private colorMethod(method: string): string {
|
265
|
-
const COLORS = {
|
266
|
-
yellow: 33,
|
267
|
-
green: 32,
|
268
|
-
blue: 34,
|
269
|
-
red: 31,
|
270
|
-
grey: 90,
|
271
|
-
clear: 39,
|
272
|
-
};
|
273
|
-
|
274
|
-
const colorText = (color: number, string: string): string => {
|
275
|
-
return `\u001b[${color}m${string}\u001b[${COLORS.clear}m`;
|
276
|
-
};
|
277
|
-
|
278
|
-
switch (method) {
|
279
|
-
case "POST": return colorText(COLORS.yellow, method);
|
280
|
-
case "GET": return colorText(COLORS.green, method);
|
281
|
-
case "PUT": return colorText(COLORS.blue, method);
|
282
|
-
case "DELETE": return colorText(COLORS.red, method);
|
283
|
-
case "PATCH": return colorText(COLORS.grey, method);
|
284
|
-
default: return method;
|
285
|
-
}
|
286
|
-
}
|
287
|
-
|
288
|
-
public registerControllers(controllers: Function[]) {
|
289
|
-
registerControllers(this.server, controllers);
|
290
|
-
}
|
291
|
-
|
292
|
-
public async start(port?: number, host?: string) {
|
293
|
-
const serverPort = port || this.config.port || 3000;
|
294
|
-
const serverHost = host || this.config.host || '0.0.0.0';
|
295
|
-
|
296
|
-
try {
|
297
|
-
// Initialize Redis if enabled
|
298
|
-
if (this.config.enableRedis) {
|
299
|
-
Logger.info('Connecting to Redis...');
|
300
|
-
// Add Redis initialization logic here
|
301
|
-
Logger.info('Redis connected');
|
302
|
-
}
|
303
|
-
|
304
|
-
// Initialize Database if enabled
|
305
|
-
if (this.config.enableDatabase) {
|
306
|
-
Logger.info('Connecting to database...');
|
307
|
-
// Add Database initialization logic here
|
308
|
-
Logger.info('Database connected');
|
309
|
-
}
|
310
|
-
|
311
|
-
Logger.info(`Starting server at http://${serverHost}:${serverPort}`);
|
312
|
-
await this.server.listen({ port: serverPort, host: serverHost });
|
313
|
-
Logger.info(`Server listening on http://${serverHost}:${serverPort}`);
|
314
|
-
|
315
|
-
// Setup graceful shutdown
|
316
|
-
this.setupGracefulShutdown();
|
317
|
-
|
318
|
-
} catch (err) {
|
319
|
-
// Logger.error(err)
|
320
|
-
Logger.error('Failed to start server:', err as Error);
|
321
|
-
process.exit(1);
|
322
|
-
}
|
323
|
-
}
|
324
|
-
|
325
|
-
private setupGracefulShutdown() {
|
326
|
-
const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM'];
|
327
|
-
|
328
|
-
signals.forEach((signal) => {
|
329
|
-
process.on(signal, async () => {
|
330
|
-
try {
|
331
|
-
await this.server.close();
|
332
|
-
Logger.info(`Closed application on ${signal}`);
|
333
|
-
process.exit(0);
|
334
|
-
} catch (err) {
|
335
|
-
Logger.error(`Error closing application on ${signal}`, err as Error);
|
336
|
-
process.exit(1);
|
337
|
-
}
|
338
|
-
});
|
339
|
-
});
|
340
|
-
|
341
|
-
process.on('unhandledRejection', (err: Error) => {
|
342
|
-
// Logger.error(err)
|
343
|
-
Logger.error('Unhandled Rejection:', err as Error);
|
344
|
-
process.exit(1);
|
345
|
-
});
|
346
|
-
}
|
347
|
-
|
348
|
-
public getServer(): FastifyInstance {
|
349
|
-
return this.server;
|
350
|
-
}
|
351
|
-
|
352
|
-
public updateConfig(newConfig: Partial<FastifyServerConfig>) {
|
353
|
-
this.config = { ...this.config, ...newConfig };
|
354
|
-
}
|
355
|
-
}
|
@@ -1,28 +0,0 @@
|
|
1
|
-
import { Container, injectable } from "inversify";
|
2
|
-
const container = new Container();
|
3
|
-
|
4
|
-
interface BeanOptions {
|
5
|
-
scope?: 'singleton' | 'transient';
|
6
|
-
bindTo?: Function[]; // Array of interfaces to bind to
|
7
|
-
}
|
8
|
-
export function Bean(options: BeanOptions) {
|
9
|
-
return function (target: any) {
|
10
|
-
const { scope = 'singleton', bindTo = [] } = options || {};
|
11
|
-
|
12
|
-
injectable()(target);
|
13
|
-
|
14
|
-
// Bind to self (class constructor)
|
15
|
-
const binding = container.bind(target).toSelf();
|
16
|
-
scope === 'singleton' ? binding.inSingletonScope() : binding.inTransientScope();
|
17
|
-
|
18
|
-
// Bind to each specified interface
|
19
|
-
bindTo.forEach(intrfc => {
|
20
|
-
const interfaceBinding = container.bind(intrfc).to(target);
|
21
|
-
scope === 'singleton'
|
22
|
-
? interfaceBinding.inSingletonScope()
|
23
|
-
: interfaceBinding.inTransientScope();
|
24
|
-
});
|
25
|
-
};
|
26
|
-
}
|
27
|
-
|
28
|
-
export default container;
|
@@ -1,36 +0,0 @@
|
|
1
|
-
import container from '../../container/container';
|
2
|
-
import { ICacheClient } from './ICacheClient';
|
3
|
-
|
4
|
-
export function Cache(ttlSeconds: number = 60, keyGenerator?: (...args: any[]) => string): MethodDecorator {
|
5
|
-
return (target, propertyKey, descriptor) => {
|
6
|
-
const originalMethod = descriptor.value as (...args: any[]) => any;
|
7
|
-
const className = target.constructor.name;
|
8
|
-
const methodName = String(propertyKey);
|
9
|
-
|
10
|
-
descriptor.value = async function (this: any, ...args: any[]) {
|
11
|
-
const cacheClient = container.get<ICacheClient>('CacheClient');
|
12
|
-
const cacheKey = keyGenerator
|
13
|
-
? keyGenerator(...args)
|
14
|
-
: `cache:${className}:${methodName}:${JSON.stringify(args)}`;
|
15
|
-
|
16
|
-
try {
|
17
|
-
const cached = await cacheClient.get(cacheKey);
|
18
|
-
if (cached) return JSON.parse(cached);
|
19
|
-
} catch (err) {
|
20
|
-
console.error('Cache read error:', err);
|
21
|
-
}
|
22
|
-
|
23
|
-
const result = await originalMethod.apply(this, args);
|
24
|
-
|
25
|
-
try {
|
26
|
-
await cacheClient.set(cacheKey, JSON.stringify(result), ttlSeconds);
|
27
|
-
} catch (err) {
|
28
|
-
console.error('Cache write error:', err);
|
29
|
-
}
|
30
|
-
|
31
|
-
return result;
|
32
|
-
} as any;
|
33
|
-
|
34
|
-
return descriptor;
|
35
|
-
};
|
36
|
-
}
|
@@ -1,119 +0,0 @@
|
|
1
|
-
import 'reflect-metadata';
|
2
|
-
import { FastifyInstance, FastifyRequest, FastifyReply, RouteOptions } from 'fastify';
|
3
|
-
import container from '../container/container';
|
4
|
-
import Logger from '../logger/Logger';
|
5
|
-
|
6
|
-
const CONTROLLER_METADATA = 'controller:metadata';
|
7
|
-
export const ROUTE_METADATA = 'route:metadata';
|
8
|
-
|
9
|
-
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
|
10
|
-
|
11
|
-
interface RouteDefinition {
|
12
|
-
path: string;
|
13
|
-
method: HttpMethod;
|
14
|
-
handlerName: string;
|
15
|
-
options?: Partial<RouteOptions>;
|
16
|
-
}
|
17
|
-
|
18
|
-
export function Controller(prefix: string = ''): ClassDecorator {
|
19
|
-
return (target: Function) => {
|
20
|
-
Reflect.defineMetadata(CONTROLLER_METADATA, { prefix }, target);
|
21
|
-
};
|
22
|
-
}
|
23
|
-
|
24
|
-
export function registerControllers(fastify: FastifyInstance, controllers: Function[]) {
|
25
|
-
const routeOptions: any[] = [];
|
26
|
-
|
27
|
-
const fastifyWithHooks = fastify as unknown as {
|
28
|
-
addHook: (hookName: string, handler: (...args: any[]) => void) => void;
|
29
|
-
};
|
30
|
-
|
31
|
-
fastifyWithHooks.addHook("onRoute", (routeOption) => {
|
32
|
-
routeOptions.push(routeOption);
|
33
|
-
});
|
34
|
-
|
35
|
-
fastifyWithHooks.addHook("onReady", (done) => {
|
36
|
-
printFastifyRoutes(routeOptions, { colors: true });
|
37
|
-
done();
|
38
|
-
});
|
39
|
-
|
40
|
-
controllers.forEach(Controller => {
|
41
|
-
const controllerMetadata = Reflect.getMetadata(CONTROLLER_METADATA, Controller);
|
42
|
-
const routes: RouteDefinition[] = Reflect.getMetadata(ROUTE_METADATA, Controller) || [];
|
43
|
-
const controllerInstance = container.get(Controller) as Record<string, (request: FastifyRequest, reply: FastifyReply) => Promise<any>>;
|
44
|
-
|
45
|
-
const prefix = controllerMetadata?.prefix || '';
|
46
|
-
|
47
|
-
routes.forEach(route => {
|
48
|
-
const fullPath = `${prefix}${route.path}`.replace(/\/\//g, '/');
|
49
|
-
|
50
|
-
const handler = async (request: FastifyRequest, reply: FastifyReply) => {
|
51
|
-
try {
|
52
|
-
const result = await controllerInstance[route.handlerName](request, reply);
|
53
|
-
if (result !== undefined) return result;
|
54
|
-
} catch (error: any) {
|
55
|
-
Logger.error('Controller error:', error);
|
56
|
-
const statusCode = error.statusCode || 500;
|
57
|
-
const message = error.message || 'Internal Server Error';
|
58
|
-
reply.status(statusCode).send({ error: message });
|
59
|
-
}
|
60
|
-
};
|
61
|
-
|
62
|
-
const routeConfig = {
|
63
|
-
...route.options,
|
64
|
-
handler,
|
65
|
-
url: fullPath,
|
66
|
-
method: route.method
|
67
|
-
};
|
68
|
-
|
69
|
-
(fastify as any).route(routeConfig);
|
70
|
-
});
|
71
|
-
});
|
72
|
-
}
|
73
|
-
|
74
|
-
export function printFastifyRoutes(routeOptions: any[], opts: { colors: boolean }) {
|
75
|
-
const { colors } = opts;
|
76
|
-
|
77
|
-
if (routeOptions.length === 0) {
|
78
|
-
return;
|
79
|
-
}
|
80
|
-
|
81
|
-
routeOptions.sort((a, b) => a.url.localeCompare(b.url));
|
82
|
-
|
83
|
-
const logEntries = [];
|
84
|
-
logEntries.push("Available routes:");
|
85
|
-
|
86
|
-
for (const routeOption of routeOptions) {
|
87
|
-
const { method, url } = routeOption;
|
88
|
-
if (method === "HEAD") continue;
|
89
|
-
const formattedMethod = colors ? colorMethod(method) : method;
|
90
|
-
logEntries.push(`${formattedMethod}\t${url}`);
|
91
|
-
}
|
92
|
-
|
93
|
-
Logger.info(logEntries.join("\n"));
|
94
|
-
}
|
95
|
-
|
96
|
-
const COLORS = {
|
97
|
-
yellow: 33,
|
98
|
-
green: 32,
|
99
|
-
blue: 34,
|
100
|
-
red: 31,
|
101
|
-
grey: 90,
|
102
|
-
magenta: 35,
|
103
|
-
clear: 39,
|
104
|
-
};
|
105
|
-
|
106
|
-
function colorText(color: number, string: string): string {
|
107
|
-
return `\u001b[${color}m${string}\u001b[${COLORS.clear}m`;
|
108
|
-
}
|
109
|
-
|
110
|
-
function colorMethod(method: string): string {
|
111
|
-
switch (method) {
|
112
|
-
case "POST": return colorText(COLORS.yellow, method);
|
113
|
-
case "GET": return colorText(COLORS.green, method);
|
114
|
-
case "PUT": return colorText(COLORS.blue, method);
|
115
|
-
case "DELETE": return colorText(COLORS.red, method);
|
116
|
-
case "PATCH": return colorText(COLORS.grey, method);
|
117
|
-
default: return method;
|
118
|
-
}
|
119
|
-
}
|
@@ -1,25 +0,0 @@
|
|
1
|
-
import { ROUTE_METADATA } from './controller.decorator';
|
2
|
-
|
3
|
-
export function createMethodDecorator(method: string) {
|
4
|
-
return (path: string = '', options?: any): MethodDecorator => {
|
5
|
-
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
6
|
-
const routes: any[] = Reflect.getMetadata(ROUTE_METADATA, target.constructor) || [];
|
7
|
-
|
8
|
-
routes.push({
|
9
|
-
path,
|
10
|
-
method: method.toUpperCase(),
|
11
|
-
handlerName: propertyKey,
|
12
|
-
options
|
13
|
-
});
|
14
|
-
|
15
|
-
Reflect.defineMetadata(ROUTE_METADATA, routes, target.constructor);
|
16
|
-
return descriptor;
|
17
|
-
};
|
18
|
-
};
|
19
|
-
}
|
20
|
-
|
21
|
-
export const Get = createMethodDecorator('GET');
|
22
|
-
export const Post = createMethodDecorator('POST');
|
23
|
-
export const Put = createMethodDecorator('PUT');
|
24
|
-
export const Delete = createMethodDecorator('DELETE');
|
25
|
-
export const Patch = createMethodDecorator('PATCH');
|
@@ -1,23 +0,0 @@
|
|
1
|
-
export function Timed(): MethodDecorator {
|
2
|
-
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
3
|
-
const originalMethod = descriptor.value;
|
4
|
-
|
5
|
-
descriptor.value = async function (...args: any[]) {
|
6
|
-
const start = process.hrtime.bigint();
|
7
|
-
try {
|
8
|
-
const result = await originalMethod.apply(this, args);
|
9
|
-
const end = process.hrtime.bigint();
|
10
|
-
const duration = Number(end - start) / 1_000_000;
|
11
|
-
console.log(`[TIMED] ${target.constructor.name}.${String(propertyKey)} took ${duration.toFixed(2)}ms`);
|
12
|
-
return result;
|
13
|
-
} catch (error) {
|
14
|
-
const end = process.hrtime.bigint();
|
15
|
-
const duration = Number(end - start) / 1_000_000;
|
16
|
-
console.error(`[TIMED-ERROR] ${target.constructor.name}.${String(propertyKey)} failed after ${duration.toFixed(2)}ms`, error);
|
17
|
-
throw error;
|
18
|
-
}
|
19
|
-
};
|
20
|
-
|
21
|
-
return descriptor;
|
22
|
-
};
|
23
|
-
}
|
@@ -1,24 +0,0 @@
|
|
1
|
-
import container from '../../container/container';
|
2
|
-
import { IDatabaseClient } from './IDatabaseClient';
|
3
|
-
|
4
|
-
export function Transactional(): MethodDecorator {
|
5
|
-
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
6
|
-
const originalMethod = descriptor.value;
|
7
|
-
|
8
|
-
descriptor.value = async function (...args: any[]) {
|
9
|
-
const dbClient = container.get<IDatabaseClient>('DatabaseClient');
|
10
|
-
const transaction = await dbClient.startTransaction();
|
11
|
-
|
12
|
-
try {
|
13
|
-
const result = await originalMethod.apply(this, [...args, transaction.transaction]);
|
14
|
-
await transaction.commit();
|
15
|
-
return result;
|
16
|
-
} catch (error) {
|
17
|
-
await transaction.rollback();
|
18
|
-
throw error;
|
19
|
-
}
|
20
|
-
};
|
21
|
-
|
22
|
-
return descriptor;
|
23
|
-
};
|
24
|
-
}
|
package/src/index.ts
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
export * from './application/Application';
|
2
|
-
export { default as container, Bean } from './container/container';
|
3
|
-
export * from './decorators/controller.decorator';
|
4
|
-
export * from './decorators/http.decorator';
|
5
|
-
export * from './decorators/timing.decorator';
|
6
|
-
export * from './decorators/cache/cache.decorator';
|
7
|
-
export * from './decorators/cache/ICacheClient';
|
8
|
-
export * from './decorators/transaction/transactional.decorator';
|
9
|
-
export * from './decorators/transaction/IDatabaseClient';
|
10
|
-
export { default as logger, } from './logger/Logger';
|