@xylabs/express 5.0.90 → 5.0.91
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/dist/node/Logger/LogFormats/LocalDev/logFormatLocalDev.d.ts +2 -1
- package/dist/node/Logger/LogFormats/LocalDev/logFormatLocalDev.d.ts.map +1 -1
- package/dist/node/Logger/LogFormats/Rollbar/logFormatRollbar.d.ts +2 -1
- package/dist/node/Logger/LogFormats/Rollbar/logFormatRollbar.d.ts.map +1 -1
- package/dist/node/Logger/LogFormats/Structured/logFormatStructured.d.ts +2 -1
- package/dist/node/Logger/LogFormats/Structured/logFormatStructured.d.ts.map +1 -1
- package/dist/node/index.mjs.map +1 -1
- package/package.json +13 -10
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logform } from 'winston';
|
|
1
2
|
/** Winston log format for local development with colorized output and timestamps. */
|
|
2
|
-
export declare const logFormatLocalDev:
|
|
3
|
+
export declare const logFormatLocalDev: Logform.Format;
|
|
3
4
|
//# sourceMappingURL=logFormatLocalDev.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logFormatLocalDev.d.ts","sourceRoot":"","sources":["../../../../../src/Logger/LogFormats/LocalDev/logFormatLocalDev.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logFormatLocalDev.d.ts","sourceRoot":"","sources":["../../../../../src/Logger/LogFormats/LocalDev/logFormatLocalDev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAOtC,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAIvC,CAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logform } from 'winston';
|
|
1
2
|
/** Winston log format for Rollbar using simple text output. */
|
|
2
|
-
export declare const logFormatRollbar:
|
|
3
|
+
export declare const logFormatRollbar: Logform.Format;
|
|
3
4
|
//# sourceMappingURL=logFormatRollbar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logFormatRollbar.d.ts","sourceRoot":"","sources":["../../../../../src/Logger/LogFormats/Rollbar/logFormatRollbar.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logFormatRollbar.d.ts","sourceRoot":"","sources":["../../../../../src/Logger/LogFormats/Rollbar/logFormatRollbar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAKtC,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,EAAE,OAAO,CAAC,MAAiB,CAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logform } from 'winston';
|
|
1
2
|
/** Winston log format for production with structured JSON output and timestamps. */
|
|
2
|
-
export declare const logFormatStructured:
|
|
3
|
+
export declare const logFormatStructured: Logform.Format;
|
|
3
4
|
//# sourceMappingURL=logFormatStructured.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logFormatStructured.d.ts","sourceRoot":"","sources":["../../../../../src/Logger/LogFormats/Structured/logFormatStructured.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logFormatStructured.d.ts","sourceRoot":"","sources":["../../../../../src/Logger/LogFormats/Structured/logFormatStructured.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAOtC,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,EAAE,OAAO,CAAC,MAAqC,CAAA"}
|
package/dist/node/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/Handler/asyncHandler.ts","../../src/Handler/errorToJsonHandler.ts","../../src/Logger/getLogger.ts","../../src/Logger/LogFormats/LocalDev/logFormatLocalDev.ts","../../src/Logger/LogFormats/Rollbar/logFormatRollbar.ts","../../src/Logger/LogFormats/Structured/logFormatStructured.ts","../../src/Logger/toWinstonVerbosity.ts","../../src/Logger/Transports/Rollbar/canGetDefaultRollbarTransport.ts","../../src/Logger/Transports/Rollbar/getDefaultRollbarTransport.ts","../../src/Logger/Transports/Rollbar/RollbarTransport.ts","../../src/Logger/WrappedWinstonLogger.ts","../../src/Logger/getDefaultLogger.ts","../../src/Handler/RouteDefinition/addRouteDefinitions.ts","../../src/Handler/StatusCodeHandlers/notImplemented.ts","../../src/HttpUtil/getHttpHeader.ts","../../src/middleware/caseInsensitiveRouting/caseInsensitiveRouting.ts","../../src/middleware/customPoweredByHeader/customPoweredByHeader.ts","../../src/middleware/jsonBodyParser/jsonBodyParser.ts","../../src/Performance/Counters.ts","../../src/Performance/Profiler.ts","../../src/middleware/metrics/counters.ts","../../src/middleware/metrics/responseProfiler.ts","../../src/middleware/standardResponses/getResponseMetadata.ts","../../src/middleware/standardResponses/standardErrors.ts","../../src/middleware/standardResponses/standardResponses.ts","../../src/Util/compactObject.ts","../../src/Util/tryParse.ts","../../src/Validation/requestHandlerValidator.ts"],"sourcesContent":["import type {\n NextFunction, ParamsDictionary, Query, Request, RequestHandler, Response,\n} from 'express-serve-static-core'\n\n/**\n * Wraps an async Express request handler to forward rejected promises to the error handler.\n * @param fn The async request handler to wrap.\n * @returns A request handler that catches async errors and passes them to next().\n */\nexport function asyncHandler<P = NoReqParams, ResBody = NoResBody, ReqBody = NoReqBody, ReqQuery = NoReqQuery, Locals extends NoLocals = NoLocals>(\n fn: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,\n) {\n return (req: Request<P, ResBody, ReqBody, ReqQuery, Locals>, res: Response<ResBody, Locals>, next: NextFunction) => {\n return Promise.resolve(fn(req, res, next)).catch(next)\n }\n}\n\n/** Empty object type used as a default for request/response body generics. */\nexport interface Empty {}\n\n/** Default type for request route parameters. */\nexport type NoReqParams = ParamsDictionary\n/** Default type for response body when none is specified. */\nexport type NoResBody = Empty\n/** Default type for request body when none is specified. */\nexport type NoReqBody = Empty\n/** Default type for request query parameters. */\nexport type NoReqQuery = Query\n/** Default type for response locals. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type NoLocals = Record<string, any>\n","import { isError, isNumber } from '@xylabs/typeof'\nimport type {\n NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nimport { getDefaultLogger } from '../Logger/index.ts'\nimport type { ExpressError } from '../Model/index.ts'\n\n/**\n * Express error handler that logs the error and sends a JSON response with the error message and status code.\n * @param error The Express error to handle.\n * @param req The incoming request.\n * @param res The outgoing response.\n * @param next The next middleware function.\n */\nexport const errorToJsonHandler = (error: ExpressError, req: Request, res: Response, next: NextFunction) => {\n if (isError(error)) {\n getDefaultLogger().error(error.message)\n if (!isNumber(error.statusCode)) error.statusCode = 500\n res.status(error.statusCode).send({ error: error.message })\n }\n next(error)\n}\n","import type { Logger } from '@xylabs/logger'\nimport { createLogger, transports as winstonTransports } from 'winston'\nimport type TransportStream from 'winston-transport'\n\nimport { logFormatLocalDev, logFormatStructured } from './LogFormats/index.ts'\nimport type { LoggerVerbosity } from './LoggerVerbosity.ts'\nimport { toWinstonVerbosity } from './toWinstonVerbosity.ts'\nimport { canGetDefaultRollbarTransport, getDefaultRollbarTransport } from './Transports/index.ts'\nimport type { WinstonVerbosity } from './WinstonVerbosity.ts'\nimport { WrappedWinstonLogger } from './WrappedWinstonLogger.ts'\n\nconst exitOnError = false\nconst handleRejections = true\n\nconst { Console } = winstonTransports\nconst consoleTransport = new Console()\nconst format = process.env.NODE_ENV === 'development' ? logFormatLocalDev : logFormatStructured\nconst transports: TransportStream[] = [consoleTransport]\nif (canGetDefaultRollbarTransport(process.env)) {\n try {\n const rollbarTransport = getDefaultRollbarTransport(process.env)\n transports.push(rollbarTransport)\n } catch {\n // NOTE: No error here, just gracefully adding logger if ENV VARs\n // were preset\n }\n}\n\nconst loggers: Record<WinstonVerbosity, Logger | undefined> = {\n debug: undefined,\n error: undefined,\n http: undefined,\n info: undefined,\n silly: undefined,\n verbose: undefined,\n warn: undefined,\n}\n\n/**\n * Returns a cached Winston-backed logger at the specified verbosity level.\n * @param minVerbosity The minimum log level to output. Defaults to 'info'.\n * @returns A logger instance configured for the given verbosity.\n */\nexport const getLogger = (minVerbosity: LoggerVerbosity = 'info'): Logger => {\n const level = toWinstonVerbosity(minVerbosity)\n const existing = loggers[level]\n if (existing) return existing\n const logger = new WrappedWinstonLogger(\n createLogger({\n exitOnError,\n format,\n handleRejections,\n level,\n rejectionHandlers: transports,\n transports,\n }),\n )\n loggers[level] = logger\n return logger\n}\n","import { format } from 'winston'\n\nconst {\n colorize, combine, timestamp, printf,\n} = format\n\n/** Winston log format for local development with colorized output and timestamps. */\nexport const logFormatLocalDev = combine(\n colorize(),\n timestamp(),\n printf(info => `[${info.timestamp} ${info.level}] ${info.message}`),\n)\n","import { format } from 'winston'\n\nconst { simple } = format\n\n/** Winston log format for Rollbar using simple text output. */\nexport const logFormatRollbar = simple()\n","import { format } from 'winston'\n\nconst {\n combine, timestamp, json,\n} = format\n\n/** Winston log format for production with structured JSON output and timestamps. */\nexport const logFormatStructured = combine(timestamp(), json())\n","import type { LoggerVerbosity } from './LoggerVerbosity.ts'\nimport type { WinstonVerbosity } from './WinstonVerbosity.ts'\n\n/**\n * Converts a LoggerVerbosity level to the corresponding Winston log level.\n * @param loggerVerbosity The application-level verbosity to convert.\n * @returns The equivalent Winston verbosity level.\n */\nexport const toWinstonVerbosity = (loggerVerbosity: LoggerVerbosity): WinstonVerbosity => {\n return loggerVerbosity === 'all' ? 'silly' : loggerVerbosity\n}\n","/**\n * Checks whether the ROLLBAR_ACCESS_TOKEN environment variable is set.\n * @param env The environment variables to check.\n * @returns True if the Rollbar access token is available.\n */\nexport const canGetDefaultRollbarTransport = (env: { [key: string]: string | undefined }): boolean => {\n return env.ROLLBAR_ACCESS_TOKEN === undefined ? false : true\n}\n","import { assertEx } from '@xylabs/assert'\nimport Rollbar from 'rollbar'\n\nimport { RollbarTransport } from './RollbarTransport.ts'\n\n/**\n * Creates a RollbarTransport using the ROLLBAR_ACCESS_TOKEN from the environment.\n * @param env The environment variables containing the Rollbar access token.\n * @returns A configured RollbarTransport instance.\n */\nexport const getDefaultRollbarTransport = (env: { [key: string]: string | undefined }): RollbarTransport => {\n const accessToken = assertEx(env.ROLLBAR_ACCESS_TOKEN, () => 'Missing ROLLBAR_ACCESS_TOKEN ENV VAR')\n const rollbar: Rollbar = new Rollbar({ accessToken })\n return new RollbarTransport({}, rollbar)\n}\n","import type Rollbar from 'rollbar'\nimport type { TransportStreamOptions } from 'winston-transport'\nimport Transport from 'winston-transport'\n\nimport { logFormatRollbar } from '../../LogFormats/index.ts'\n\n/** Winston transport that forwards error-level log messages to Rollbar. */\nexport class RollbarTransport extends Transport {\n protected readonly rollbar?: Rollbar\n constructor(\n opts: TransportStreamOptions,\n rollbar?: Rollbar,\n ) {\n super({\n ...opts, format: logFormatRollbar, level: 'error',\n })\n this.rollbar = rollbar\n }\n\n override log(info: { message?: string }, next: () => void) {\n this.rollbar?.error(info?.message)\n this.emit('logged', info?.message)\n next()\n }\n}\n","import type { LogFunction, Logger } from '@xylabs/logger'\nimport type { Logger as Winston } from 'winston'\n\n/**\n * Wrap Winston logger methods to adapt to familiar\n * console logging methods\n */\nexport class WrappedWinstonLogger implements Logger {\n protected readonly winston: Winston\n constructor(winston: Winston) {\n this.winston = winston\n }\n\n debug: LogFunction = message => this.winston.debug(message)\n error: LogFunction = message => this.winston.error(message)\n info: LogFunction = message => this.winston.info(message)\n log: LogFunction = message => this.winston.info(message)\n trace: LogFunction = message => this.winston.debug(message)\n warn: LogFunction = message => this.winston.warn(message)\n}\n","import type { Logger } from '@xylabs/logger'\n\nimport { getLogger } from './getLogger.ts'\nimport type { WrappedWinstonLogger } from './WrappedWinstonLogger.ts'\n\n/**\n * Static instance to prevent multiple instances of the same logger\n * with the same config\n */\n\ndeclare global {\n var xy: {\n defaultLogger?: WrappedWinstonLogger\n }\n}\n\n/**\n * Returns the singleton default logger instance, creating one if it does not exist.\n * @returns The default logger.\n */\nexport const getDefaultLogger = (): Logger => {\n if (globalThis.xy === undefined) globalThis.xy = {}\n if (globalThis.xy.defaultLogger) return globalThis.xy.defaultLogger\n return getLogger()\n}\n","import type { Express } from 'express-serve-static-core'\n\nimport type { RouteDefinition } from './RouteDefinition.ts'\n\n/**\n * Registers an array of route definitions on an Express application.\n * @param app The Express application to register routes on.\n * @param routeDefinitions The route definitions to register.\n */\nexport const addRouteDefinitions = (app: Express, routeDefinitions: RouteDefinition[]) => {\n for (const definition of routeDefinitions) {\n app[definition.method](definition.path, definition.handlers)\n }\n}\n","import type { RequestHandler } from 'express-serve-static-core'\nimport { ReasonPhrases, StatusCodes } from 'http-status-codes'\n\n/** Express request handler that responds with a 501 Not Implemented error. */\nexport const notImplemented: RequestHandler = (_req, _res, next) => {\n next({ message: ReasonPhrases.NOT_IMPLEMENTED, statusCode: StatusCodes.NOT_IMPLEMENTED })\n}\n","import { isDefined } from '@xylabs/typeof'\nimport type { Request } from 'express-serve-static-core'\n\n/**\n * Since there can be multiple of certain HTTP headers or\n * to prevent ugliness if someone did send us multiple\n * instances of a header we only expect one of, this\n * method grabs the 1st/only one of the desired header\n * @param header The header to find\n * @param req The received HTTP request (with headers)\n * @returns The first or only occurrence of the specified HTTP header\n */\nexport const getHttpHeader = (header: string, req: Request): string | undefined => {\n const headerValue = req.headers[header]\n const value\n // If the header exists\n = isDefined(headerValue)\n // If there's multiple of the same header\n ? Array.isArray(headerValue)\n // Grab the first one\n ? (headerValue as string[]).shift()\n // Otherwise grab the only one\n : (headerValue as string)\n // Otherwise undefined\n : undefined\n return value\n}\n","import type { Express } from 'express-serve-static-core'\n\nconst setting = 'case sensitive routing'\n\n/**\n * Enable case sensitivity. When enabled, \"/Foo\" and \"/foo\" are different\n * routes. When disabled, \"/Foo\" and \"/foo\" are treated the same.\n * @param app The Express app to disable the header on.\n */\nexport const enableCaseSensitiveRouting = (app: Express) => {\n app.enable(setting)\n}\n\n/**\n * Disable case sensitivity. When enabled, \"/Foo\" and \"/foo\" are different\n * routes. When disabled, \"/Foo\" and \"/foo\" are treated the same.\n * @param app The Express app to disable the header on.\n */\nexport const disableCaseSensitiveRouting = (app: Express) => {\n app.disable(setting)\n}\n","import type {\n Express, NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nconst header = 'X-Powered-By'\nconst setting = 'x-powered-by'\n\n/**\n * By default Express appends the `X-Powered-By: Express` header to\n * all responses. Calling this method enables that behavior.\n * @param app The Express app to disable the header on.\n */\nexport const enableExpressDefaultPoweredByHeader = (app: Express) => {\n app.enable(setting)\n}\n\n/**\n * By default Express appends the `X-Powered-By: Express` header to\n * all responses. Calling this method disables that behavior.\n * @param app The Express app to disable the header on.\n */\nexport const disableExpressDefaultPoweredByHeader = (app: Express) => {\n app.disable(setting)\n}\n\n/** Express middleware that sets the X-Powered-By header to 'XYO'. */\nexport const customPoweredByHeader = (req: Request, res: Response, next: NextFunction) => {\n res.setHeader(header, 'XYO')\n next()\n}\n","import type { OptionsJson } from 'body-parser'\nimport bodyParser from 'body-parser'\nimport type { NextHandleFunction } from 'connect'\n\nimport { getDefaultLogger } from '../../Logger/index.ts'\n\n/**\n * The default maximum request body size for the JSON Body Parser\n */\nexport const DefaultJsonBodyParserOptionsLimit = '100kb'\n\n/**\n * The default MIME types for the JSON Body Parser\n */\nexport const DefaultJsonBodyParserOptionsTypes = ['application/json', 'text/json']\n\n/**\n * The default options for the JSON Body Parser\n */\nexport const DefaultJsonBodyParserOptions: OptionsJson = {\n limit: DefaultJsonBodyParserOptionsLimit,\n type: DefaultJsonBodyParserOptionsTypes,\n}\n\n/**\n * Gets the default JSON Body Parser options merged with the supplied options\n * with the supplied options taking precedence\n * @param options The options to override the default JSON Body Parser options with\n * @returns The combined JSON Body Parser options with the supplied values taking\n * precedence over the default\n */\nexport const getJsonBodyParserOptions = (options?: Partial<OptionsJson>): OptionsJson => {\n return options ? { ...DefaultJsonBodyParserOptions, ...options } : DefaultJsonBodyParserOptions\n}\n\n/**\n * Get a JSON Body Parser connect middleware handler\n * @param options The options for the JSON Body Parser\n * @returns A middleware function that parses JSON bodies\n */\nexport const getJsonBodyParser = (options: OptionsJson = DefaultJsonBodyParserOptions): NextHandleFunction => {\n // Create closed instance of bodyParser to prevent instantiation of new instance on every request\n const parser = bodyParser.json(options)\n\n return (req, res, next) => {\n // If we do not trap this error, then it dumps too much to log, usually happens if request aborted\n try {\n parser(req, res, next)\n } catch (ex) {\n const error = ex as Error\n getDefaultLogger().log(`bodyParser failed [${error?.name}]: ${error?.message}`)\n }\n }\n}\n\n/**\n * A JSON Body Parser middleware handler initialized with the default options\n */\nexport const jsonBodyParser = getJsonBodyParser()\n","/** Static counter registry for tracking named numeric metrics. */\nexport class Counters {\n static counters: Record<string, number> = {}\n\n static inc(name: string, count = 1) {\n this.catchError(name, (name: string) => {\n this.counters[name] = (this.counters[name] ?? 0) + count\n })\n }\n\n static max(name: string, count: number) {\n this.catchError(name, (name: string) => {\n const currentValue = this.counters[name]\n if (currentValue === undefined || count > currentValue) {\n this.counters[name] = count\n }\n })\n }\n\n static min(name: string, count: number) {\n this.catchError(name, (name: string) => {\n const currentValue = this.counters[name]\n if (currentValue === undefined || count < currentValue) {\n this.counters[name] = count\n }\n })\n }\n\n private static catchError = (name: string, func: (name: string) => void) => {\n try {\n func(name)\n } catch {\n this.counters[name] = 0\n this.inc('CountersErrors')\n }\n }\n}\n","/** Measures and records the execution duration of async operations by name. */\nexport class Profiler {\n stats: Record<string, number> = {}\n\n async profile<T>(name: string, promise: Promise<T>) {\n const start = Date.now()\n const result = await promise\n this.stats[name] = Date.now() - start\n return result\n }\n}\n","import type {\n Application, NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nimport { Counters } from '../../Performance/index.ts'\n\n/**\n * Registers middleware that increments per-path request counters and exposes a /stats endpoint.\n * @param app The Express application to attach counters to.\n */\nexport const useRequestCounters = (app: Application): void => {\n // Configure Global counters\n app.use((req: Request, res: Response, next: NextFunction) => {\n Counters.inc(req.path)\n Counters.inc('_calls')\n next()\n })\n\n app.get('/stats', (req: Request, res: Response, next: NextFunction) => {\n /* #swagger.tags = ['Metrics'] */\n /* #swagger.summary = 'Get the counters for single instance of diviner' */\n res.json({\n alive: true,\n avgTime: `${((Counters.counters._totalTime ?? 0) / (Counters.counters._calls ?? 1)).toFixed(2)}ms`,\n counters: Counters.counters,\n })\n next()\n })\n}\n","import type {\n NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\n/**\n * Connect middleware to enable profiling of response lifecycle timing. To effectively profile\n * the response timing, this middleware needs to be called first when initializing your Express\n * App\n * @example\n * const app = express()\n * app.use(responseProfiler)\n * // other initialization ...\n * @param _req The request\n * @param res The response\n * @param next The next function\n */\nexport const responseProfiler = (_req: Request, res: Response, next: NextFunction) => {\n if (!res.locals?.meta) {\n res.locals.meta = {}\n }\n res.locals.meta.profile = { startTime: Date.now() }\n next()\n}\n","import type { Response } from 'express-serve-static-core'\n\n/**\n * Extracts response metadata from res.locals, computing profile duration if profiling was started.\n * @param res The Express response to extract metadata from.\n * @returns The metadata record including any profiling information.\n */\nexport const getResponseMetadata = (res: Response): Record<string, unknown> => {\n const meta: Record<string, unknown> = res.locals?.meta || {}\n // NOTE: We should do this somewhere else to better separate concerns\n const profile = res.locals.meta?.profile\n if (profile) {\n const startTime = profile?.startTime\n if (startTime) {\n const endTime = Date.now()\n const duration = endTime - startTime\n res.locals.meta.profile = {\n duration, endTime, startTime,\n }\n }\n }\n return meta\n}\n","import { isError } from '@xylabs/typeof'\nimport type {\n NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nimport { getDefaultLogger } from '../../Logger/index.ts'\nimport type { ExpressError } from '../../Model/index.ts'\nimport type { ApiError } from './jsonApi/index.ts'\n\n/**\n * Express error handler that logs the error and sends a JSON:API-compliant error response.\n * @param err The error to handle, or undefined if no error.\n * @param req The incoming request.\n * @param res The outgoing response.\n * @param next The next middleware function.\n */\nexport const standardErrors = (err: ExpressError | undefined, req: Request, res: Response, next: NextFunction) => {\n if (!isError(err)) {\n next(err)\n return\n }\n getDefaultLogger().error(err.message)\n err.statusCode = err.statusCode ?? 500\n\n const error: ApiError = {\n detail: err.message,\n status: `${err.statusCode}`,\n title: err.name,\n }\n\n res.status(err.statusCode).json(error)\n\n next(err)\n}\n","import mung from 'express-mung'\nimport type {\n Request, RequestHandler, Response,\n} from 'express-serve-static-core'\n\nimport { getResponseMetadata } from './getResponseMetadata.js'\n\ninterface TransformResponseLocals {\n rawResponse?: boolean\n}\n\n/**\n * Flags the response to forgo the standard response envelope\n * and return the raw response body to the client\n * @param res The response to disable the standard response format on\n */\nexport const setRawResponseFormat = (res: Response): void => {\n res.locals.rawResponse = true\n}\n\n/**\n * Clears any flags on the response, allowing the response to\n * use the default standard response envelope\n * @param res The response to set to the standard response format\n */\nexport const clearRawResponseFormat = (res: Response): void => {\n res.locals.rawResponse = false\n}\n\n/**\n * Checks if there are any flags on the response that would cause it\n * to forgo the standard response envelope and return the raw response\n * body to the client\n * @param res\n * @returns True if there are any flags on the response, false otherwise\n */\nexport const isRawResponseFormatSet = (res: Response): boolean => {\n return res.locals.rawResponse ? true : false\n}\n\n/**\n * Transforms each response to conform to the standard response format (compatible with JSON API)\n * @param body The original request body\n * @param _req The request\n * @param res The response\n * @returns The transformed response body\n */\nconst transformResponse = (body: unknown, _req: Request, res: Response<unknown, TransformResponseLocals>) => {\n return isRawResponseFormatSet(res)\n ? body\n : (res.statusCode >= 200 && res.statusCode < 300)\n ? { data: body, meta: getResponseMetadata(res) }\n : { error: body, meta: getResponseMetadata(res) }\n}\n\n/**\n * Connect middleware to enable the transform of all responses to match\n * the standard response format (compatible with JSON API)\n */\n\nexport const standardResponses: RequestHandler = mung.json(transformResponse, { mungError: true })\n","/**\n * Returns a shallow copy of the object with all null and undefined values removed.\n * @param obj The object to compact.\n * @returns A new object with only defined, non-null properties.\n */\nexport const compactObject = <T extends Record<string, unknown>>(obj: T) => {\n const result: Record<string, unknown> = {}\n for (const key in obj) {\n if (obj[key] !== undefined && obj[key] !== null) {\n result[key] = obj[key]\n }\n }\n return result as T\n}\n","import { isDefined } from '@xylabs/typeof'\n\n/** A function that parses a string value into the target type. */\nexport type ParseFunc<T = number> = (value: string) => T\n\n/**\n * @deprecated use zod instead\n */\nexport const tryParse = <T = number>(func: ParseFunc<T>, value?: string) => {\n try {\n const result = isDefined(value) ? func(value) : null\n if (!Number.isNaN(result) && result !== null) {\n return result\n }\n } catch {\n return\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { isDefined, isPromise } from '@xylabs/typeof'\nimport type {\n NextFunction, Request, RequestHandler, Response,\n} from 'express-serve-static-core'\nimport { ReasonPhrases, StatusCodes } from 'http-status-codes'\nimport * as z from 'zod'\n\nimport type { ExpressError } from '../Model/index.ts'\n\n/**\n * Empty Zod schema for requests with no parameters.\n */\nexport const EmptyParamsZod = z.object({}).catchall(z.string())\n\n/**\n * Empty Zod schema for requests with no query parameters.\n */\nexport const EmptyQueryParamsZod = z.object({}).catchall(z.union([z.string(), z.array(z.string())]))\n\n/**\n * Default validation schemas for request handler validator.\n */\nexport const ValidateRequestDefaults = {\n params: EmptyParamsZod,\n query: EmptyQueryParamsZod,\n body: z.json().optional(),\n response: z.json().optional(),\n}\n\ntype ValidatableRequestKey = 'params' | 'query' | 'body'\n\n/**\n * Factory for Express middleware that validates request and response objects using Zod schemas.\n * @param schemas The Zod schemas to use for validation.\n * @returns A middleware function for validating requests and responses.\n */\nexport function requestHandlerValidator<\n TParams extends typeof EmptyQueryParamsZod | z.ZodType<Record<string, string>> = typeof EmptyQueryParamsZod,\n TQuery extends typeof EmptyQueryParamsZod | z.ZodType<Record<string, string | string[]>> = typeof EmptyQueryParamsZod,\n TBody extends z.ZodType<unknown> = z.ZodType<unknown>,\n TResponse extends z.ZodType<unknown> = z.ZodType<unknown>,\n>(schemas?: Partial<{\n body: TBody\n params: TParams\n query: TQuery\n response: TResponse\n}>) {\n type Params = z.infer<TParams>\n type Query = z.infer<TQuery>\n type Body = z.infer<TBody>\n type Res = z.infer<TResponse>\n const validators = { ...ValidateRequestDefaults, ...schemas }\n\n return (handler: (req: Request<Params, Res, Body, Query>, res: Response<Res>, next: NextFunction) => unknown): RequestHandler => {\n return async (req: Request, res: Response, next: NextFunction) => {\n const originalJson = res.json.bind(res)\n try {\n // Validate incoming request\n const errors: string[] = []\n const keys: ValidatableRequestKey[] = ['params', 'query', 'body']\n for (const key of keys) {\n const validator = validators[key]\n const result = validator.safeParse(req[key])\n if (result.success) {\n if (isDefined(result.data)) Object.assign(req[key], result.data)\n } else {\n errors.push(\n ...result.error.issues.map(\n issue => (issue.path.length === 0)\n ? `${key}: ${issue.message}`\n : `${key}.${issue.path.join('.')}: ${issue.message}`,\n ),\n )\n }\n }\n\n // If there were validation errors, short-circuit and return Bad Request\n if (errors.length > 0) {\n const message = errors.join('; ')\n const err: ExpressError = new Error(message)\n err.name = ReasonPhrases.BAD_REQUEST\n err.statusCode = StatusCodes.BAD_REQUEST\n next(err)\n return false\n }\n\n // Wrap res.json to validate outgoing response\n res.json = (data: any) => {\n const result = validators.response.safeParse(data)\n if (result.success) {\n return originalJson(result.data)\n } else {\n const message = result.error.issues.map(\n issue => (issue.path.length === 0)\n ? `response: ${issue.message}`\n : `response.${issue.path.join('.')}: ${issue.message}`,\n ).join('; ')\n const err: ExpressError = new Error(message)\n err.name = ReasonPhrases.INTERNAL_SERVER_ERROR\n err.statusCode = StatusCodes.INTERNAL_SERVER_ERROR\n\n // Restore original json function in case the error handler wants to use it\n res.json = originalJson\n throw err\n }\n }\n\n // Automatically handle async errors\n const result = handler(req as any, res as any, next)\n if (result && isPromise(result)) {\n await result\n }\n } catch (err) {\n res.json = originalJson\n next(err)\n }\n }\n }\n}\n"],"mappings":"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","names":["format","format","combine","timestamp","format","header","setting","name","isError","isError","isDefined","isDefined","ReasonPhrases","StatusCodes","result"]}
|
|
1
|
+
{"version":3,"sources":["../../src/Handler/asyncHandler.ts","../../src/Handler/errorToJsonHandler.ts","../../src/Logger/getLogger.ts","../../src/Logger/LogFormats/LocalDev/logFormatLocalDev.ts","../../src/Logger/LogFormats/Rollbar/logFormatRollbar.ts","../../src/Logger/LogFormats/Structured/logFormatStructured.ts","../../src/Logger/toWinstonVerbosity.ts","../../src/Logger/Transports/Rollbar/canGetDefaultRollbarTransport.ts","../../src/Logger/Transports/Rollbar/getDefaultRollbarTransport.ts","../../src/Logger/Transports/Rollbar/RollbarTransport.ts","../../src/Logger/WrappedWinstonLogger.ts","../../src/Logger/getDefaultLogger.ts","../../src/Handler/RouteDefinition/addRouteDefinitions.ts","../../src/Handler/StatusCodeHandlers/notImplemented.ts","../../src/HttpUtil/getHttpHeader.ts","../../src/middleware/caseInsensitiveRouting/caseInsensitiveRouting.ts","../../src/middleware/customPoweredByHeader/customPoweredByHeader.ts","../../src/middleware/jsonBodyParser/jsonBodyParser.ts","../../src/Performance/Counters.ts","../../src/Performance/Profiler.ts","../../src/middleware/metrics/counters.ts","../../src/middleware/metrics/responseProfiler.ts","../../src/middleware/standardResponses/getResponseMetadata.ts","../../src/middleware/standardResponses/standardErrors.ts","../../src/middleware/standardResponses/standardResponses.ts","../../src/Util/compactObject.ts","../../src/Util/tryParse.ts","../../src/Validation/requestHandlerValidator.ts"],"sourcesContent":["import type {\n NextFunction, ParamsDictionary, Query, Request, RequestHandler, Response,\n} from 'express-serve-static-core'\n\n/**\n * Wraps an async Express request handler to forward rejected promises to the error handler.\n * @param fn The async request handler to wrap.\n * @returns A request handler that catches async errors and passes them to next().\n */\nexport function asyncHandler<P = NoReqParams, ResBody = NoResBody, ReqBody = NoReqBody, ReqQuery = NoReqQuery, Locals extends NoLocals = NoLocals>(\n fn: RequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,\n) {\n return (req: Request<P, ResBody, ReqBody, ReqQuery, Locals>, res: Response<ResBody, Locals>, next: NextFunction) => {\n return Promise.resolve(fn(req, res, next)).catch(next)\n }\n}\n\n/** Empty object type used as a default for request/response body generics. */\nexport interface Empty {}\n\n/** Default type for request route parameters. */\nexport type NoReqParams = ParamsDictionary\n/** Default type for response body when none is specified. */\nexport type NoResBody = Empty\n/** Default type for request body when none is specified. */\nexport type NoReqBody = Empty\n/** Default type for request query parameters. */\nexport type NoReqQuery = Query\n/** Default type for response locals. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type NoLocals = Record<string, any>\n","import { isError, isNumber } from '@xylabs/typeof'\nimport type {\n NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nimport { getDefaultLogger } from '../Logger/index.ts'\nimport type { ExpressError } from '../Model/index.ts'\n\n/**\n * Express error handler that logs the error and sends a JSON response with the error message and status code.\n * @param error The Express error to handle.\n * @param req The incoming request.\n * @param res The outgoing response.\n * @param next The next middleware function.\n */\nexport const errorToJsonHandler = (error: ExpressError, req: Request, res: Response, next: NextFunction) => {\n if (isError(error)) {\n getDefaultLogger().error(error.message)\n if (!isNumber(error.statusCode)) error.statusCode = 500\n res.status(error.statusCode).send({ error: error.message })\n }\n next(error)\n}\n","import type { Logger } from '@xylabs/logger'\nimport { createLogger, transports as winstonTransports } from 'winston'\nimport type TransportStream from 'winston-transport'\n\nimport { logFormatLocalDev, logFormatStructured } from './LogFormats/index.ts'\nimport type { LoggerVerbosity } from './LoggerVerbosity.ts'\nimport { toWinstonVerbosity } from './toWinstonVerbosity.ts'\nimport { canGetDefaultRollbarTransport, getDefaultRollbarTransport } from './Transports/index.ts'\nimport type { WinstonVerbosity } from './WinstonVerbosity.ts'\nimport { WrappedWinstonLogger } from './WrappedWinstonLogger.ts'\n\nconst exitOnError = false\nconst handleRejections = true\n\nconst { Console } = winstonTransports\nconst consoleTransport = new Console()\nconst format = process.env.NODE_ENV === 'development' ? logFormatLocalDev : logFormatStructured\nconst transports: TransportStream[] = [consoleTransport]\nif (canGetDefaultRollbarTransport(process.env)) {\n try {\n const rollbarTransport = getDefaultRollbarTransport(process.env)\n transports.push(rollbarTransport)\n } catch {\n // NOTE: No error here, just gracefully adding logger if ENV VARs\n // were preset\n }\n}\n\nconst loggers: Record<WinstonVerbosity, Logger | undefined> = {\n debug: undefined,\n error: undefined,\n http: undefined,\n info: undefined,\n silly: undefined,\n verbose: undefined,\n warn: undefined,\n}\n\n/**\n * Returns a cached Winston-backed logger at the specified verbosity level.\n * @param minVerbosity The minimum log level to output. Defaults to 'info'.\n * @returns A logger instance configured for the given verbosity.\n */\nexport const getLogger = (minVerbosity: LoggerVerbosity = 'info'): Logger => {\n const level = toWinstonVerbosity(minVerbosity)\n const existing = loggers[level]\n if (existing) return existing\n const logger = new WrappedWinstonLogger(\n createLogger({\n exitOnError,\n format,\n handleRejections,\n level,\n rejectionHandlers: transports,\n transports,\n }),\n )\n loggers[level] = logger\n return logger\n}\n","import type { Logform } from 'winston'\nimport { format } from 'winston'\n\nconst {\n colorize, combine, timestamp, printf,\n} = format\n\n/** Winston log format for local development with colorized output and timestamps. */\nexport const logFormatLocalDev: Logform.Format = combine(\n colorize(),\n timestamp(),\n printf(info => `[${info.timestamp} ${info.level}] ${info.message}`),\n)\n","import type { Logform } from 'winston'\nimport { format } from 'winston'\n\nconst { simple } = format\n\n/** Winston log format for Rollbar using simple text output. */\nexport const logFormatRollbar: Logform.Format = simple()\n","import type { Logform } from 'winston'\nimport { format } from 'winston'\n\nconst {\n combine, timestamp, json,\n} = format\n\n/** Winston log format for production with structured JSON output and timestamps. */\nexport const logFormatStructured: Logform.Format = combine(timestamp(), json())\n","import type { LoggerVerbosity } from './LoggerVerbosity.ts'\nimport type { WinstonVerbosity } from './WinstonVerbosity.ts'\n\n/**\n * Converts a LoggerVerbosity level to the corresponding Winston log level.\n * @param loggerVerbosity The application-level verbosity to convert.\n * @returns The equivalent Winston verbosity level.\n */\nexport const toWinstonVerbosity = (loggerVerbosity: LoggerVerbosity): WinstonVerbosity => {\n return loggerVerbosity === 'all' ? 'silly' : loggerVerbosity\n}\n","/**\n * Checks whether the ROLLBAR_ACCESS_TOKEN environment variable is set.\n * @param env The environment variables to check.\n * @returns True if the Rollbar access token is available.\n */\nexport const canGetDefaultRollbarTransport = (env: { [key: string]: string | undefined }): boolean => {\n return env.ROLLBAR_ACCESS_TOKEN === undefined ? false : true\n}\n","import { assertEx } from '@xylabs/assert'\nimport Rollbar from 'rollbar'\n\nimport { RollbarTransport } from './RollbarTransport.ts'\n\n/**\n * Creates a RollbarTransport using the ROLLBAR_ACCESS_TOKEN from the environment.\n * @param env The environment variables containing the Rollbar access token.\n * @returns A configured RollbarTransport instance.\n */\nexport const getDefaultRollbarTransport = (env: { [key: string]: string | undefined }): RollbarTransport => {\n const accessToken = assertEx(env.ROLLBAR_ACCESS_TOKEN, () => 'Missing ROLLBAR_ACCESS_TOKEN ENV VAR')\n const rollbar: Rollbar = new Rollbar({ accessToken })\n return new RollbarTransport({}, rollbar)\n}\n","import type Rollbar from 'rollbar'\nimport type { TransportStreamOptions } from 'winston-transport'\nimport Transport from 'winston-transport'\n\nimport { logFormatRollbar } from '../../LogFormats/index.ts'\n\n/** Winston transport that forwards error-level log messages to Rollbar. */\nexport class RollbarTransport extends Transport {\n protected readonly rollbar?: Rollbar\n constructor(\n opts: TransportStreamOptions,\n rollbar?: Rollbar,\n ) {\n super({\n ...opts, format: logFormatRollbar, level: 'error',\n })\n this.rollbar = rollbar\n }\n\n override log(info: { message?: string }, next: () => void) {\n this.rollbar?.error(info?.message)\n this.emit('logged', info?.message)\n next()\n }\n}\n","import type { LogFunction, Logger } from '@xylabs/logger'\nimport type { Logger as Winston } from 'winston'\n\n/**\n * Wrap Winston logger methods to adapt to familiar\n * console logging methods\n */\nexport class WrappedWinstonLogger implements Logger {\n protected readonly winston: Winston\n constructor(winston: Winston) {\n this.winston = winston\n }\n\n debug: LogFunction = message => this.winston.debug(message)\n error: LogFunction = message => this.winston.error(message)\n info: LogFunction = message => this.winston.info(message)\n log: LogFunction = message => this.winston.info(message)\n trace: LogFunction = message => this.winston.debug(message)\n warn: LogFunction = message => this.winston.warn(message)\n}\n","import type { Logger } from '@xylabs/logger'\n\nimport { getLogger } from './getLogger.ts'\nimport type { WrappedWinstonLogger } from './WrappedWinstonLogger.ts'\n\n/**\n * Static instance to prevent multiple instances of the same logger\n * with the same config\n */\n\ndeclare global {\n var xy: {\n defaultLogger?: WrappedWinstonLogger\n }\n}\n\n/**\n * Returns the singleton default logger instance, creating one if it does not exist.\n * @returns The default logger.\n */\nexport const getDefaultLogger = (): Logger => {\n if (globalThis.xy === undefined) globalThis.xy = {}\n if (globalThis.xy.defaultLogger) return globalThis.xy.defaultLogger\n return getLogger()\n}\n","import type { Express } from 'express-serve-static-core'\n\nimport type { RouteDefinition } from './RouteDefinition.ts'\n\n/**\n * Registers an array of route definitions on an Express application.\n * @param app The Express application to register routes on.\n * @param routeDefinitions The route definitions to register.\n */\nexport const addRouteDefinitions = (app: Express, routeDefinitions: RouteDefinition[]) => {\n for (const definition of routeDefinitions) {\n app[definition.method](definition.path, definition.handlers)\n }\n}\n","import type { RequestHandler } from 'express-serve-static-core'\nimport { ReasonPhrases, StatusCodes } from 'http-status-codes'\n\n/** Express request handler that responds with a 501 Not Implemented error. */\nexport const notImplemented: RequestHandler = (_req, _res, next) => {\n next({ message: ReasonPhrases.NOT_IMPLEMENTED, statusCode: StatusCodes.NOT_IMPLEMENTED })\n}\n","import { isDefined } from '@xylabs/typeof'\nimport type { Request } from 'express-serve-static-core'\n\n/**\n * Since there can be multiple of certain HTTP headers or\n * to prevent ugliness if someone did send us multiple\n * instances of a header we only expect one of, this\n * method grabs the 1st/only one of the desired header\n * @param header The header to find\n * @param req The received HTTP request (with headers)\n * @returns The first or only occurrence of the specified HTTP header\n */\nexport const getHttpHeader = (header: string, req: Request): string | undefined => {\n const headerValue = req.headers[header]\n const value\n // If the header exists\n = isDefined(headerValue)\n // If there's multiple of the same header\n ? Array.isArray(headerValue)\n // Grab the first one\n ? (headerValue as string[]).shift()\n // Otherwise grab the only one\n : (headerValue as string)\n // Otherwise undefined\n : undefined\n return value\n}\n","import type { Express } from 'express-serve-static-core'\n\nconst setting = 'case sensitive routing'\n\n/**\n * Enable case sensitivity. When enabled, \"/Foo\" and \"/foo\" are different\n * routes. When disabled, \"/Foo\" and \"/foo\" are treated the same.\n * @param app The Express app to disable the header on.\n */\nexport const enableCaseSensitiveRouting = (app: Express) => {\n app.enable(setting)\n}\n\n/**\n * Disable case sensitivity. When enabled, \"/Foo\" and \"/foo\" are different\n * routes. When disabled, \"/Foo\" and \"/foo\" are treated the same.\n * @param app The Express app to disable the header on.\n */\nexport const disableCaseSensitiveRouting = (app: Express) => {\n app.disable(setting)\n}\n","import type {\n Express, NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nconst header = 'X-Powered-By'\nconst setting = 'x-powered-by'\n\n/**\n * By default Express appends the `X-Powered-By: Express` header to\n * all responses. Calling this method enables that behavior.\n * @param app The Express app to disable the header on.\n */\nexport const enableExpressDefaultPoweredByHeader = (app: Express) => {\n app.enable(setting)\n}\n\n/**\n * By default Express appends the `X-Powered-By: Express` header to\n * all responses. Calling this method disables that behavior.\n * @param app The Express app to disable the header on.\n */\nexport const disableExpressDefaultPoweredByHeader = (app: Express) => {\n app.disable(setting)\n}\n\n/** Express middleware that sets the X-Powered-By header to 'XYO'. */\nexport const customPoweredByHeader = (req: Request, res: Response, next: NextFunction) => {\n res.setHeader(header, 'XYO')\n next()\n}\n","import type { OptionsJson } from 'body-parser'\nimport bodyParser from 'body-parser'\nimport type { NextHandleFunction } from 'connect'\n\nimport { getDefaultLogger } from '../../Logger/index.ts'\n\n/**\n * The default maximum request body size for the JSON Body Parser\n */\nexport const DefaultJsonBodyParserOptionsLimit = '100kb'\n\n/**\n * The default MIME types for the JSON Body Parser\n */\nexport const DefaultJsonBodyParserOptionsTypes = ['application/json', 'text/json']\n\n/**\n * The default options for the JSON Body Parser\n */\nexport const DefaultJsonBodyParserOptions: OptionsJson = {\n limit: DefaultJsonBodyParserOptionsLimit,\n type: DefaultJsonBodyParserOptionsTypes,\n}\n\n/**\n * Gets the default JSON Body Parser options merged with the supplied options\n * with the supplied options taking precedence\n * @param options The options to override the default JSON Body Parser options with\n * @returns The combined JSON Body Parser options with the supplied values taking\n * precedence over the default\n */\nexport const getJsonBodyParserOptions = (options?: Partial<OptionsJson>): OptionsJson => {\n return options ? { ...DefaultJsonBodyParserOptions, ...options } : DefaultJsonBodyParserOptions\n}\n\n/**\n * Get a JSON Body Parser connect middleware handler\n * @param options The options for the JSON Body Parser\n * @returns A middleware function that parses JSON bodies\n */\nexport const getJsonBodyParser = (options: OptionsJson = DefaultJsonBodyParserOptions): NextHandleFunction => {\n // Create closed instance of bodyParser to prevent instantiation of new instance on every request\n const parser = bodyParser.json(options)\n\n return (req, res, next) => {\n // If we do not trap this error, then it dumps too much to log, usually happens if request aborted\n try {\n parser(req, res, next)\n } catch (ex) {\n const error = ex as Error\n getDefaultLogger().log(`bodyParser failed [${error?.name}]: ${error?.message}`)\n }\n }\n}\n\n/**\n * A JSON Body Parser middleware handler initialized with the default options\n */\nexport const jsonBodyParser = getJsonBodyParser()\n","/** Static counter registry for tracking named numeric metrics. */\nexport class Counters {\n static counters: Record<string, number> = {}\n\n static inc(name: string, count = 1) {\n this.catchError(name, (name: string) => {\n this.counters[name] = (this.counters[name] ?? 0) + count\n })\n }\n\n static max(name: string, count: number) {\n this.catchError(name, (name: string) => {\n const currentValue = this.counters[name]\n if (currentValue === undefined || count > currentValue) {\n this.counters[name] = count\n }\n })\n }\n\n static min(name: string, count: number) {\n this.catchError(name, (name: string) => {\n const currentValue = this.counters[name]\n if (currentValue === undefined || count < currentValue) {\n this.counters[name] = count\n }\n })\n }\n\n private static catchError = (name: string, func: (name: string) => void) => {\n try {\n func(name)\n } catch {\n this.counters[name] = 0\n this.inc('CountersErrors')\n }\n }\n}\n","/** Measures and records the execution duration of async operations by name. */\nexport class Profiler {\n stats: Record<string, number> = {}\n\n async profile<T>(name: string, promise: Promise<T>) {\n const start = Date.now()\n const result = await promise\n this.stats[name] = Date.now() - start\n return result\n }\n}\n","import type {\n Application, NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nimport { Counters } from '../../Performance/index.ts'\n\n/**\n * Registers middleware that increments per-path request counters and exposes a /stats endpoint.\n * @param app The Express application to attach counters to.\n */\nexport const useRequestCounters = (app: Application): void => {\n // Configure Global counters\n app.use((req: Request, res: Response, next: NextFunction) => {\n Counters.inc(req.path)\n Counters.inc('_calls')\n next()\n })\n\n app.get('/stats', (req: Request, res: Response, next: NextFunction) => {\n /* #swagger.tags = ['Metrics'] */\n /* #swagger.summary = 'Get the counters for single instance of diviner' */\n res.json({\n alive: true,\n avgTime: `${((Counters.counters._totalTime ?? 0) / (Counters.counters._calls ?? 1)).toFixed(2)}ms`,\n counters: Counters.counters,\n })\n next()\n })\n}\n","import type {\n NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\n/**\n * Connect middleware to enable profiling of response lifecycle timing. To effectively profile\n * the response timing, this middleware needs to be called first when initializing your Express\n * App\n * @example\n * const app = express()\n * app.use(responseProfiler)\n * // other initialization ...\n * @param _req The request\n * @param res The response\n * @param next The next function\n */\nexport const responseProfiler = (_req: Request, res: Response, next: NextFunction) => {\n if (!res.locals?.meta) {\n res.locals.meta = {}\n }\n res.locals.meta.profile = { startTime: Date.now() }\n next()\n}\n","import type { Response } from 'express-serve-static-core'\n\n/**\n * Extracts response metadata from res.locals, computing profile duration if profiling was started.\n * @param res The Express response to extract metadata from.\n * @returns The metadata record including any profiling information.\n */\nexport const getResponseMetadata = (res: Response): Record<string, unknown> => {\n const meta: Record<string, unknown> = res.locals?.meta || {}\n // NOTE: We should do this somewhere else to better separate concerns\n const profile = res.locals.meta?.profile\n if (profile) {\n const startTime = profile?.startTime\n if (startTime) {\n const endTime = Date.now()\n const duration = endTime - startTime\n res.locals.meta.profile = {\n duration, endTime, startTime,\n }\n }\n }\n return meta\n}\n","import { isError } from '@xylabs/typeof'\nimport type {\n NextFunction, Request, Response,\n} from 'express-serve-static-core'\n\nimport { getDefaultLogger } from '../../Logger/index.ts'\nimport type { ExpressError } from '../../Model/index.ts'\nimport type { ApiError } from './jsonApi/index.ts'\n\n/**\n * Express error handler that logs the error and sends a JSON:API-compliant error response.\n * @param err The error to handle, or undefined if no error.\n * @param req The incoming request.\n * @param res The outgoing response.\n * @param next The next middleware function.\n */\nexport const standardErrors = (err: ExpressError | undefined, req: Request, res: Response, next: NextFunction) => {\n if (!isError(err)) {\n next(err)\n return\n }\n getDefaultLogger().error(err.message)\n err.statusCode = err.statusCode ?? 500\n\n const error: ApiError = {\n detail: err.message,\n status: `${err.statusCode}`,\n title: err.name,\n }\n\n res.status(err.statusCode).json(error)\n\n next(err)\n}\n","import mung from 'express-mung'\nimport type {\n Request, RequestHandler, Response,\n} from 'express-serve-static-core'\n\nimport { getResponseMetadata } from './getResponseMetadata.js'\n\ninterface TransformResponseLocals {\n rawResponse?: boolean\n}\n\n/**\n * Flags the response to forgo the standard response envelope\n * and return the raw response body to the client\n * @param res The response to disable the standard response format on\n */\nexport const setRawResponseFormat = (res: Response): void => {\n res.locals.rawResponse = true\n}\n\n/**\n * Clears any flags on the response, allowing the response to\n * use the default standard response envelope\n * @param res The response to set to the standard response format\n */\nexport const clearRawResponseFormat = (res: Response): void => {\n res.locals.rawResponse = false\n}\n\n/**\n * Checks if there are any flags on the response that would cause it\n * to forgo the standard response envelope and return the raw response\n * body to the client\n * @param res\n * @returns True if there are any flags on the response, false otherwise\n */\nexport const isRawResponseFormatSet = (res: Response): boolean => {\n return res.locals.rawResponse ? true : false\n}\n\n/**\n * Transforms each response to conform to the standard response format (compatible with JSON API)\n * @param body The original request body\n * @param _req The request\n * @param res The response\n * @returns The transformed response body\n */\nconst transformResponse = (body: unknown, _req: Request, res: Response<unknown, TransformResponseLocals>) => {\n return isRawResponseFormatSet(res)\n ? body\n : (res.statusCode >= 200 && res.statusCode < 300)\n ? { data: body, meta: getResponseMetadata(res) }\n : { error: body, meta: getResponseMetadata(res) }\n}\n\n/**\n * Connect middleware to enable the transform of all responses to match\n * the standard response format (compatible with JSON API)\n */\n\nexport const standardResponses: RequestHandler = mung.json(transformResponse, { mungError: true })\n","/**\n * Returns a shallow copy of the object with all null and undefined values removed.\n * @param obj The object to compact.\n * @returns A new object with only defined, non-null properties.\n */\nexport const compactObject = <T extends Record<string, unknown>>(obj: T) => {\n const result: Record<string, unknown> = {}\n for (const key in obj) {\n if (obj[key] !== undefined && obj[key] !== null) {\n result[key] = obj[key]\n }\n }\n return result as T\n}\n","import { isDefined } from '@xylabs/typeof'\n\n/** A function that parses a string value into the target type. */\nexport type ParseFunc<T = number> = (value: string) => T\n\n/**\n * @deprecated use zod instead\n */\nexport const tryParse = <T = number>(func: ParseFunc<T>, value?: string) => {\n try {\n const result = isDefined(value) ? func(value) : null\n if (!Number.isNaN(result) && result !== null) {\n return result\n }\n } catch {\n return\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { isDefined, isPromise } from '@xylabs/typeof'\nimport type {\n NextFunction, Request, RequestHandler, Response,\n} from 'express-serve-static-core'\nimport { ReasonPhrases, StatusCodes } from 'http-status-codes'\nimport * as z from 'zod'\n\nimport type { ExpressError } from '../Model/index.ts'\n\n/**\n * Empty Zod schema for requests with no parameters.\n */\nexport const EmptyParamsZod = z.object({}).catchall(z.string())\n\n/**\n * Empty Zod schema for requests with no query parameters.\n */\nexport const EmptyQueryParamsZod = z.object({}).catchall(z.union([z.string(), z.array(z.string())]))\n\n/**\n * Default validation schemas for request handler validator.\n */\nexport const ValidateRequestDefaults = {\n params: EmptyParamsZod,\n query: EmptyQueryParamsZod,\n body: z.json().optional(),\n response: z.json().optional(),\n}\n\ntype ValidatableRequestKey = 'params' | 'query' | 'body'\n\n/**\n * Factory for Express middleware that validates request and response objects using Zod schemas.\n * @param schemas The Zod schemas to use for validation.\n * @returns A middleware function for validating requests and responses.\n */\nexport function requestHandlerValidator<\n TParams extends typeof EmptyQueryParamsZod | z.ZodType<Record<string, string>> = typeof EmptyQueryParamsZod,\n TQuery extends typeof EmptyQueryParamsZod | z.ZodType<Record<string, string | string[]>> = typeof EmptyQueryParamsZod,\n TBody extends z.ZodType<unknown> = z.ZodType<unknown>,\n TResponse extends z.ZodType<unknown> = z.ZodType<unknown>,\n>(schemas?: Partial<{\n body: TBody\n params: TParams\n query: TQuery\n response: TResponse\n}>) {\n type Params = z.infer<TParams>\n type Query = z.infer<TQuery>\n type Body = z.infer<TBody>\n type Res = z.infer<TResponse>\n const validators = { ...ValidateRequestDefaults, ...schemas }\n\n return (handler: (req: Request<Params, Res, Body, Query>, res: Response<Res>, next: NextFunction) => unknown): RequestHandler => {\n return async (req: Request, res: Response, next: NextFunction) => {\n const originalJson = res.json.bind(res)\n try {\n // Validate incoming request\n const errors: string[] = []\n const keys: ValidatableRequestKey[] = ['params', 'query', 'body']\n for (const key of keys) {\n const validator = validators[key]\n const result = validator.safeParse(req[key])\n if (result.success) {\n if (isDefined(result.data)) Object.assign(req[key], result.data)\n } else {\n errors.push(\n ...result.error.issues.map(\n issue => (issue.path.length === 0)\n ? `${key}: ${issue.message}`\n : `${key}.${issue.path.join('.')}: ${issue.message}`,\n ),\n )\n }\n }\n\n // If there were validation errors, short-circuit and return Bad Request\n if (errors.length > 0) {\n const message = errors.join('; ')\n const err: ExpressError = new Error(message)\n err.name = ReasonPhrases.BAD_REQUEST\n err.statusCode = StatusCodes.BAD_REQUEST\n next(err)\n return false\n }\n\n // Wrap res.json to validate outgoing response\n res.json = (data: any) => {\n const result = validators.response.safeParse(data)\n if (result.success) {\n return originalJson(result.data)\n } else {\n const message = result.error.issues.map(\n issue => (issue.path.length === 0)\n ? `response: ${issue.message}`\n : `response.${issue.path.join('.')}: ${issue.message}`,\n ).join('; ')\n const err: ExpressError = new Error(message)\n err.name = ReasonPhrases.INTERNAL_SERVER_ERROR\n err.statusCode = StatusCodes.INTERNAL_SERVER_ERROR\n\n // Restore original json function in case the error handler wants to use it\n res.json = originalJson\n throw err\n }\n }\n\n // Automatically handle async errors\n const result = handler(req as any, res as any, next)\n if (result && isPromise(result)) {\n await result\n }\n } catch (err) {\n res.json = originalJson\n next(err)\n }\n }\n }\n}\n"],"mappings":"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","names":["format","format","combine","timestamp","format","header","setting","name","isError","isError","isDefined","isDefined","ReasonPhrases","StatusCodes","result"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xylabs/express",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.91",
|
|
4
4
|
"description": "SDK for base code for Api repos that use express and deploy on AWS ECS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"xylabs",
|
|
@@ -44,12 +44,13 @@
|
|
|
44
44
|
"dist",
|
|
45
45
|
"!**/*.bench.*",
|
|
46
46
|
"!**/*.spec.*",
|
|
47
|
-
"!**/*.test.*"
|
|
47
|
+
"!**/*.test.*",
|
|
48
|
+
"README.md"
|
|
48
49
|
],
|
|
49
50
|
"dependencies": {
|
|
50
|
-
"@xylabs/assert": "~5.0.
|
|
51
|
-
"@xylabs/logger": "~5.0.
|
|
52
|
-
"@xylabs/typeof": "~5.0.
|
|
51
|
+
"@xylabs/assert": "~5.0.90",
|
|
52
|
+
"@xylabs/logger": "~5.0.90",
|
|
53
|
+
"@xylabs/typeof": "~5.0.90",
|
|
53
54
|
"body-parser": "~2.2.2",
|
|
54
55
|
"connect": "^3.7.0",
|
|
55
56
|
"express-mung": "~0.5.1",
|
|
@@ -64,14 +65,16 @@
|
|
|
64
65
|
"@types/express-mung": "~0.5.5",
|
|
65
66
|
"@types/express-serve-static-core": "^5.1.1",
|
|
66
67
|
"@types/node": "~25.5.0",
|
|
67
|
-
"@xylabs/ts-scripts-
|
|
68
|
-
"@xylabs/
|
|
69
|
-
"@xylabs/
|
|
68
|
+
"@xylabs/ts-scripts-common": "~7.6.2",
|
|
69
|
+
"@xylabs/ts-scripts-pnpm": "~7.6.2",
|
|
70
|
+
"@xylabs/tsconfig": "~7.6.2",
|
|
71
|
+
"@xylabs/vitest-extended": "~5.0.90",
|
|
70
72
|
"body-parser": "~2.2.2",
|
|
71
73
|
"express-mung": "~0.5.1",
|
|
72
74
|
"http-status-codes": "~2.3.0",
|
|
73
75
|
"rollbar": "~3.1.0",
|
|
74
|
-
"typescript": "
|
|
76
|
+
"typescript": "^5",
|
|
77
|
+
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
|
75
78
|
"vitest": "^4.1.2",
|
|
76
79
|
"vitest-mock-extended": "~3.1.0",
|
|
77
80
|
"winston": "~3.19.0",
|
|
@@ -83,7 +86,7 @@
|
|
|
83
86
|
},
|
|
84
87
|
"volta": {
|
|
85
88
|
"node": "22.3.0",
|
|
86
|
-
"
|
|
89
|
+
"pnpm": "10.12.1"
|
|
87
90
|
},
|
|
88
91
|
"publishConfig": {
|
|
89
92
|
"access": "public"
|