UNPKG

@catbee/utils

Version:

A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.

710 lines (706 loc) 20.9 kB
/* * The MIT License * * Copyright (c) 2026 Catbee Technologies. https://catbee.in/license * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import * as express_rate_limit from 'express-rate-limit'; import { RequestHandler, Router } from 'express'; /** * Supported HTTP methods for route decorators */ type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'options' | 'head' | 'trace' | 'connect'; /** * Represents a route definition for controller methods */ interface RouteDefinition { /** The URL path for this route */ path: string; /** HTTP method for this route */ method: HttpMethod; /** Name of the handler method in the controller class */ handlerName: string; } /** * Parameter decoration definition for method parameters */ interface ParamDefinition { /** Parameter position in method signature */ index: number; /** Type of parameter (query, body, etc.) */ type: 'query' | 'param' | 'body' | 'req' | 'res' | 'logger' | 'reqHeader' | 'reqId' | 'cookie'; /** Optional key for extracting specific property */ key?: string; /** Optional ParamOptions for advanced extraction */ options?: ParamOptions; } type CachedRateLimiter = { limiter: ReturnType<typeof express_rate_limit.rateLimit>; config: string; }; type Constructor<T = any> = new (...args: any[]) => T; declare class DIContainer { private readonly instances; private readonly constructing; private readonly propertyInjections; register<T>(target: Constructor<T>): void; /** * Register a property injection to be resolved when the target class is instantiated */ registerPropertyInjection(target: object, propertyKey: string | symbol, injectClass: Constructor): void; get<T>(target: Constructor<T>): T; private applyPropertyInjections; clear(): void; } /** * Injectable decorator for marking classes as injectable. * * @returns Class decorator that marks a class as injectable and registers it with the DI container. */ declare function Injectable(): ClassDecorator; /** * Inject decorator for injecting dependencies into class properties. * * @param targetClass - The class to inject * @returns Property decorator that injects the specified class into the property */ declare function Inject<T>(targetClass: new (...args: any[]) => T): PropertyDecorator; /** * Inject function for retrieving instances from the DI container. * @param targetClass - The class to inject * * @returns The instance of the requested class * * @example * const a = inject(TestClass); */ declare function inject<T>(targetClass: new (...args: any[]) => T): T; /** * Decorator for GET HTTP method routes. * * @param path - URL path for the route * @returns Method decorator * * @example * ```ts * @Get('/users') * getUsers() { * return this.userService.findAll(); * } * ``` */ declare const Get: (path: string) => MethodDecorator; /** * Decorator for POST HTTP method routes. * * @param path - URL path for the route * @returns Method decorator * * @example * ```ts * @Post('/users') * createUser(@Body() userData: any) { * return this.userService.create(userData); * } * ``` */ declare const Post: (path: string) => MethodDecorator; /** * Decorator for PUT HTTP method routes. * * @param path - URL path for the route * @returns Method decorator */ declare const Put: (path: string) => MethodDecorator; /** * Decorator for PATCH HTTP method routes. * * @param path - URL path for the route * @returns Method decorator */ declare const Patch: (path: string) => MethodDecorator; /** * Decorator for DELETE HTTP method routes. * * @param path - URL path for the route * @returns Method decorator */ declare const Delete: (path: string) => MethodDecorator; /** * Decorator for OPTIONS HTTP method routes. * * @param path - URL path for the route * @returns Method decorator */ declare const Options: (path: string) => MethodDecorator; /** * Decorator for HEAD HTTP method routes. * * @param path - URL path for the route * @returns Method decorator */ declare const Head: (path: string) => MethodDecorator; /** * Decorator for TRACE HTTP method routes. * * @param path - URL path for the route * @returns Method decorator */ declare const Trace: (path: string) => MethodDecorator; /** * Decorator for CONNECT HTTP method routes. * * @param path - URL path for the route * @returns Method decorator */ declare const Connect: (path: string) => MethodDecorator; /** * Decorator that marks a class as a controller with a base path. * Used as the entry point for routing configuration. * * @param basePath - Base URL path for all routes in this controller * @returns Class decorator * * @example * ```ts * @Controller('/api/users') * class UserController { * // Controller methods... * } * ``` */ declare function Controller(basePath: string): ClassDecorator; /** * Decorator that applies middleware to a controller method or an entire controller. * Multiple middlewares can be applied and will execute in order. * * @param middlewares - Express middleware functions to apply * @returns Method decorator or Class decorator * * @example * ```ts * @Get('/protected') * @Use(authMiddleware, loggingMiddleware) * getProtectedResource() { * // This route is protected by auth middleware * } * * @Controller('/api') * @Use(commonMiddleware) * class ApiController { * // All routes in this controller use the middleware * } * ``` */ declare function Use(...middlewares: RequestHandler[]): MethodDecorator & ClassDecorator; type StrNumBool = 'string' | 'number' | 'boolean'; /** * Options for parameter decorators * @template T - Type of the parameter value after transformation * * @property type - Base type of the parameter (default: 'string')' * @property dataType - Data structure type (single, array, object) * @property delimiter - Delimiter for array types * @property default - Default value if parameter is missing * @property required - Whether the parameter is required * @property throwError - Throw error on validation failure * @property validate - Custom validation function * @property transform - Custom transformation function */ interface ParamOptions<T = any> { /** Base type of the parameter (default: 'string') */ type?: StrNumBool; /** Data structure type (default: 'single') */ dataType?: 'single' | 'array' | 'object'; /** Delimiter for array types (default: ',') */ delimiter?: string; /** Default value if parameter is missing */ default?: T; /** Whether the parameter is required (default: false) */ required?: boolean; /** Throw error on validation failure (default: true) */ throwError?: boolean; /** Minimum value for number type */ min?: number; /** Maximum value for number type */ max?: number; /** Regex pattern the value must match */ pattern?: RegExp; /** Name of the pattern for error messages */ patternName?: string; /** Custom validation function */ validate?: (value: any) => boolean; /** Custom transformation function */ transform?: (value: any) => any; } declare function createParamDecorator(type: ParamDefinition['type'], key?: string): (paramKey?: string) => ParameterDecorator; declare function createParamDecoratorWithoutParam(type: ParamDefinition['type']): () => ParameterDecorator; /** * Decorator that extracts query parameters from request. * * @param paramKey - Optional key to extract specific query parameter * @param options - Optional ParamOptions * @returns Parameter decorator * * @example * ```ts * @Get('/search') * search(@Query('term') term: string, @Query('page', { type: 'number', default: 1 }) page: number) { * // term will contain the value of req.query.term * // page will contain the numeric value of req.query.page or default to 1 * } * ``` */ declare const Query: (paramKey?: string, options?: ParamOptions) => ParameterDecorator; /** * Decorator that extracts route parameters from request. * * @param paramKey - Optional key to extract specific route parameter * @param options - Optional ParamOptions * @returns Parameter decorator * * @example * ```ts * @Get('/users/:id') * getUser(@Param('id') id: string) { * // id will contain the value of req.params.id * } * ``` */ declare const Param: (paramKey?: string, options?: ParamOptions) => ParameterDecorator; /** * Decorator that extracts body or body property from request. * * @param paramKey - Optional key to extract specific body property * @returns Parameter decorator * * @example * ```ts * @Post('/users') * createUser(@Body() userData: any) { * // userData will contain the entire req.body * } * * @Post('/update') * updateName(@Body('name') name: string) { * // name will contain the value of req.body.name * } * ``` */ declare const Body: (paramKey?: string) => ParameterDecorator; /** * Decorator that injects a logger instance. * @returns Parameter decorator * * @example * ```ts * @Get('/log') * log(@ReqLogger() logger: Logger) { * logger.info('Logging request...'); * } * ``` */ declare const ReqLogger: () => ParameterDecorator; /** * Decorator that extracts request ID from headers. * @returns Parameter decorator * * @example * ```ts * @Get('/data') * getData(@ReqId() reqId: string) { * // reqId will contain the value of req.headers['x-request-id'] or req.id * } * ``` */ declare const ReqId: () => ParameterDecorator; /** * Decorator that extracts request headers. * @param key - Optional key to extract specific header * @returns Parameter decorator * * @example * ```ts * @Get('/data') * getData(@ReqHeader('Authorization') authHeader: string) { * // authHeader will contain the value of req.headers['authorization'] * } * ``` */ declare const ReqHeader: (paramKey?: string) => ParameterDecorator; /** * Decorator that extracts cookies from request. * @param key - Optional key to extract specific cookie * @returns Parameter decorator * * @example * ```ts * @Get('/data') * getData(@ReqCookie('session_id') sessionId: string) { * // sessionId will contain the value of req.cookies['session_id'] * } * ``` */ declare const ReqCookie: (paramKey?: string) => ParameterDecorator; /** * Decorator that injects the entire request object. * * @returns Parameter decorator * * @example * ```ts * @Get('/complex') * complex(@Req() req: Request) { * // Access the full request object * console.log(req.headers); * } * ``` */ declare const Req: () => ParameterDecorator; /** * Decorator that injects the response object. * * @returns Parameter decorator * * @example * ```ts * @Get('/custom') * custom(@Res() res: Response) { * // Direct access to response object * return res.status(201).send('Created'); * } * ``` */ declare const Res: () => ParameterDecorator; /** * Decorator that sets a custom HTTP status code for a response. * * @param status - HTTP status code to use * @returns Method decorator * * @example * ```ts * @Post('/users') * @HttpCode(201) * createUser(@Body() userData: any) { * // Response will have 201 Created status code * return { id: '123', ...userData }; * } * ``` */ declare function HttpCode(status: number): MethodDecorator; /** * Decorator that adds a custom HTTP header to the response. * * @param header - Header name-value pairs or a single header name and value * @param value - Header value if a single header name is provided * @returns Method decorator * * @example * ```ts * @Get('/data') * @Header('Cache-Control', 'max-age=60') * getData() { * // Response will include the Cache-Control header * return { data: '...' }; * } */ declare function Header(name: string, value: string): MethodDecorator & ClassDecorator; /** * Decorator that adds a custom HTTP headers to the response. * * @param headers - Header name-value pairs or a single header name and value * @param value - Header value if a single header name is provided * @returns Method decorator * * @example * ```ts * @Get('/data') * @Headers('Cache-Control', 'max-age=60') * getData() { * // Response will include the Cache-Control header * return { data: '...' }; * } * * @Get('/data/:id') * @Headers({ * 'Cache-Control': 'max-age=60', * 'X-Custom-Header': 'custom-value', * 'Content-Security-Policy': "default-src 'self'" * }) * getData() { * // Response will include all specified headers * return { data: '...' }; * } * * ``` */ declare function Headers(headers: Record<string, string> | string, value?: string): MethodDecorator & ClassDecorator; /** * Decorator that registers a function to run before route handler execution. * Useful for pre-processing or logging. * * @param fn - Function to execute before the handler * @returns Method decorator or Class decorator * * @example * ```ts * @Get('/users/:id') * @Before((req, res) => console.log(`Accessing user ${req.params.id}`)) * getUser(@Param('id') id: string) { * // Function will log before this handler runs * } * * @Controller('/api') * @Before((req, res) => console.log(`API access: ${req.path}`)) * class ApiController { * // Hook runs before all routes in this controller * } * ``` */ declare function Before(fn: Function): MethodDecorator & ClassDecorator; /** * Decorator that registers a function to run after route handler execution. * Can access the handler's result. * * @param fn - Function to execute after the handler * @returns Method decorator or Class decorator * * @example * ```ts * @Get('/users/:id') * @After((req, res, result) => console.log(`User data sent: ${JSON.stringify(result)}`)) * getUser(@Param('id') id: string) { * // After this handler, the function will log the returned data * return { id, name: 'Example' }; * } * * @Controller('/api') * @After((req, res, result) => console.log(`API response: ${JSON.stringify(result)}`)) * class ApiController { * // Hook runs after all routes in this controller * } * ``` */ declare function After(fn: Function): MethodDecorator & ClassDecorator; /** * Decorator that requires specific roles for accessing a route. * Must be used with authentication middleware. * * Check req.user.roles for user roles[]. * * @param roles - List of roles that can access this route * @returns Method decorator * * @example * ```ts * @Get('/admin/settings') * @Roles('admin', 'superuser') * getSettings() { * // Only admins and superusers can access * return { settings: [...] }; * } * ``` */ declare function Roles(...roles: string[]): MethodDecorator & ClassDecorator; /** * Decorator that redirects to another URL. * * @param url - URL to redirect to (can be absolute or relative) * @param statusCode - HTTP status code for redirect (default: 302) * @returns Method decorator * * @example * ```ts * @Get('/old-path') * @Redirect('/new-path', 301) * redirectToNewPath() { * // This method won't be executed; automatic redirect happens * } * * @Get('/dynamic-redirect') * @Redirect() * getDynamicRedirect() { * // Return an object with url and optionally statusCode * return { url: '/calculated-path', statusCode: 307 }; * } * ``` */ declare function Redirect(url?: string, statusCode?: number): MethodDecorator; /** * Decorator that adds caching to a route response. * * @param ttlSeconds - Time to live in seconds for the cache * @returns Method decorator * * @example * ```ts * @Get('/data') * @Cache(300) // Cache for 5 minutes * getData() { * return { data: 'expensive operation result' }; * } * ``` */ declare function Cache(ttlSeconds: number): MethodDecorator & ClassDecorator; /** * Decorator that applies rate limiting to a route. * Note: Requires 'express-rate-limit' package to be installed. * * @param limit - Maximum number of requests allowed in the window * @param windowMs - Time window in milliseconds * @returns Method decorator * * Default Options: * - standardHeaders: true * - legacyHeaders: false * * @example * ```ts * @Post('/login') * @RateLimit({ max: 5, windowMs: 60000, standardHeaders: true, legacyHeaders: false }) // 5 requests per minute * login(@Body() credentials: LoginDto) { * return this.authService.login(credentials); * } * ``` */ declare function RateLimit(options: { max: number; windowMs: number; standardHeaders?: boolean; legacyHeaders?: boolean; }): MethodDecorator & ClassDecorator; /** * Decorator that sets the content type for the response. * * @param type - MIME type for the response * @returns Method decorator or Class decorator * * @example * ```ts * @Get('/download') * @ContentType('application/pdf') * downloadPdf() { * return this.fileService.generatePdf(); * } * * @Controller('/api/json') * @ContentType('application/json') * class JsonApiController { * // All routes in this controller use this content type * } * ``` */ declare function ContentType(type: string): MethodDecorator & ClassDecorator; /** * Decorator that adds API versioning to a route. * * @param version - Version string for the API endpoint * @param options - Versioning options * @returns Method decorator * * Default Options: * - addPrefix: true * - addHeader: true * - headerName: 'X-API-Version' * * @example * ```ts * * @Get('/users') * @Version('v2') * getUsersV2() { * return this.userService.findAllV2(); * } * * @Get('/users') * @Version('v2', { addPrefix: true, addHeader: true, headerName: 'X-API-Version' }) * getUsersV2() { * // Route becomes /v2/users * return this.userService.findAllV2(); * } * ``` */ declare function Version(version: string, options?: { addPrefix?: boolean; addHeader?: boolean; headerName?: string; }): MethodDecorator & ClassDecorator; /** * Decorator that sets a timeout for route execution. * * @param ms - Timeout in milliseconds * @returns Method decorator * * @example * ```ts * @Get('/slow-operation') * @Timeout(30000) // 30 second timeout * slowOperation() { * return this.heavyService.processData(); * } * ``` */ declare function Timeout(ms: number): MethodDecorator & ClassDecorator; /** * Decorator that adds comprehensive logging to a route. * * @param options - Logging configuration options * @returns Method decorator * * Default Options: * - logEntry: true * - logExit: true * - logBody: false * - logParams: false * - logResponse: false * * @example * ```ts * @Post('/users') * @Log({ * logEntry: true, * logExit: true, * logBody: true, * logParams: true, * logResponse: false * }) * createUser(@Body() userData: any) { * return this.userService.create(userData); * } * ``` */ declare function Log(options?: { logEntry?: boolean; logExit?: boolean; logBody?: boolean; logParams?: boolean; logResponse?: boolean; }): MethodDecorator & ClassDecorator; /** * Registers all controller classes with the provided router. * This function processes all decorators and sets up the Express routes. * * @param router - Express router instance * @param controllers - Array of controller classes */ declare function registerControllers(router: Router, controllers: any[]): void; export { After, Before, Body, Cache, Connect, ContentType, Controller, DIContainer, Delete, Get, Head, Header, Headers, HttpCode, Inject, Injectable, Log, Options, Param, Patch, Post, Put, Query, RateLimit, Redirect, Req, ReqCookie, ReqHeader, ReqId, ReqLogger, Res, Roles, Timeout, Trace, Use, Version, createParamDecorator, createParamDecoratorWithoutParam, inject, registerControllers }; export type { CachedRateLimiter, HttpMethod, ParamDefinition, ParamOptions, RouteDefinition };