Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@xylabs/express

Package Overview
Dependencies
Maintainers
5
Versions
313
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@xylabs/express - npm Package Compare versions

Comparing version
6.0.2
to
6.0.3
+11
dist/node/HttpStatus.d.ts
export declare const ReasonPhrases: {
readonly BAD_REQUEST: "Bad Request";
readonly INTERNAL_SERVER_ERROR: "Internal Server Error";
readonly NOT_IMPLEMENTED: "Not Implemented";
};
export declare const StatusCodes: {
readonly BAD_REQUEST: 400;
readonly INTERNAL_SERVER_ERROR: 500;
readonly NOT_IMPLEMENTED: 501;
};
//# sourceMappingURL=HttpStatus.d.ts.map
{"version":3,"file":"HttpStatus.d.ts","sourceRoot":"","sources":["../../src/HttpStatus.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;CAIhB,CAAA;AAEV,eAAO,MAAM,WAAW;;;;CAId,CAAA"}
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"notImplemented.d.ts","sourceRoot":"","sources":["../../../../src/Handler/StatusCodeHandlers/notImplemented.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAG/D,8EAA8E;AAC9E,eAAO,MAAM,cAAc,EAAE,cAE5B,CAAA"}
{"version":3,"file":"notImplemented.d.ts","sourceRoot":"","sources":["../../../../src/Handler/StatusCodeHandlers/notImplemented.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAI/D,8EAA8E;AAC9E,eAAO,MAAM,cAAc,EAAE,cAE5B,CAAA"}

@@ -25,3 +25,3 @@ // src/Handler/asyncHandler.ts

timestamp(),
printf((info) => `[${info.timestamp} ${info.level}] ${info.message}`)
printf((info) => `[${String(info.timestamp)} ${String(info.level)}] ${String(info.message)}`)
);

@@ -140,3 +140,3 @@

var getDefaultLogger = () => {
if (globalThis.xy === void 0) globalThis.xy = {};
globalThis.xy ??= {};
if (globalThis.xy.defaultLogger) return globalThis.xy.defaultLogger;

@@ -163,4 +163,15 @@ return getLogger();

// src/HttpStatus.ts
var ReasonPhrases = {
BAD_REQUEST: "Bad Request",
INTERNAL_SERVER_ERROR: "Internal Server Error",
NOT_IMPLEMENTED: "Not Implemented"
};
var StatusCodes = {
BAD_REQUEST: 400,
INTERNAL_SERVER_ERROR: 500,
NOT_IMPLEMENTED: 501
};
// src/Handler/StatusCodeHandlers/notImplemented.ts
import { ReasonPhrases, StatusCodes } from "http-status-codes";
var notImplemented = (_req, _res, next) => {

@@ -289,5 +300,3 @@ next({ message: ReasonPhrases.NOT_IMPLEMENTED, statusCode: StatusCodes.NOT_IMPLEMENTED });

var responseProfiler = (_req, res, next) => {
if (!res.locals?.meta) {
res.locals.meta = {};
}
res.locals.meta ??= {};
res.locals.meta.profile = { startTime: Date.now() };

@@ -299,10 +308,10 @@ next();

var getResponseMetadata = (res) => {
const meta = res.locals?.meta || {};
const profile = res.locals.meta?.profile;
if (profile) {
const startTime = profile?.startTime;
if (startTime) {
const meta = res.locals.meta ?? {};
const profile = meta.profile;
if (profile !== void 0) {
const startTime = profile.startTime;
if (startTime !== void 0) {
const endTime = Date.now();
const duration = endTime - startTime;
res.locals.meta.profile = {
meta.profile = {
duration,

@@ -336,3 +345,2 @@ endTime,

// src/middleware/standardResponses/standardResponses.ts
import mung from "express-mung";
var setRawResponseFormat = (res) => {

@@ -350,3 +358,14 @@ res.locals.rawResponse = true;

};
var standardResponses = mung.json(transformResponse, { mungError: true });
var standardResponses = (req, res, next) => {
const json3 = res.json.bind(res);
res.json = ((body) => {
try {
return json3(transformResponse(body, req, res));
} catch (ex) {
next(ex);
return res;
}
});
next();
};

@@ -379,3 +398,2 @@ // src/Util/compactObject.ts

import { isDefined as isDefined3, isPromise } from "@xylabs/typeof";
import { ReasonPhrases as ReasonPhrases2, StatusCodes as StatusCodes2 } from "http-status-codes";
import * as z from "zod/mini";

@@ -414,4 +432,4 @@ var EmptyParamsZod = z.catchall(z.object({}), z.string());

const err = new Error(message);
err.name = ReasonPhrases2.BAD_REQUEST;
err.statusCode = StatusCodes2.BAD_REQUEST;
err.name = ReasonPhrases.BAD_REQUEST;
err.statusCode = StatusCodes.BAD_REQUEST;
next(err);

@@ -429,4 +447,4 @@ return false;

const err = new Error(message);
err.name = ReasonPhrases2.INTERNAL_SERVER_ERROR;
err.statusCode = StatusCodes2.INTERNAL_SERVER_ERROR;
err.name = ReasonPhrases.INTERNAL_SERVER_ERROR;
err.statusCode = StatusCodes.INTERNAL_SERVER_ERROR;
res.json = originalJson;

@@ -436,3 +454,5 @@ throw err;

};
const result = handler(req, res, next);
const typedReq = req;
const typedRes = res;
const result = handler(typedReq, typedRes, next);
if (isPromise(result)) {

@@ -439,0 +459,0 @@ const resultPromise = result;

{
"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: Record<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: Record<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/mini'\n\nimport type { ExpressError } from '../Model/index.ts'\n\n/**\n * Empty Zod schema for requests with no parameters.\n */\nexport const EmptyParamsZod = z.catchall(z.object({}), z.string())\n\n/**\n * Empty Zod schema for requests with no query parameters.\n */\nexport const EmptyQueryParamsZod = z.catchall(z.object({}), 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.optional(z.json()),\n response: z.optional(z.json()),\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.core.$ZodType<Record<string, string>> = typeof EmptyQueryParamsZod,\n TQuery extends typeof EmptyQueryParamsZod | z.core.$ZodType<Record<string, string | string[]>> = typeof EmptyQueryParamsZod,\n TBody extends z.core.$ZodType<unknown> = z.core.$ZodType<unknown>,\n TResponse extends z.core.$ZodType<unknown> = z.core.$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 = z.safeParse(validator, 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 = z.safeParse(validators.response, 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: unknown = handler(req as any, res as any, next)\n if (isPromise(result)) {\n const resultPromise: Promise<unknown> = result\n await resultPromise\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"]
"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/HttpStatus.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 => `[${String(info.timestamp)} ${String(info.level)}] ${String(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: Record<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: Record<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 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", "export const ReasonPhrases = {\n BAD_REQUEST: 'Bad Request',\n INTERNAL_SERVER_ERROR: 'Internal Server Error',\n NOT_IMPLEMENTED: 'Not Implemented',\n} as const\n\nexport const StatusCodes = {\n BAD_REQUEST: 400,\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n} as const\n", "import type { RequestHandler } from 'express-serve-static-core'\n\nimport { ReasonPhrases, StatusCodes } from '../../HttpStatus.ts'\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).shift()\n // Otherwise grab the only one\n : (headerValue)\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\ninterface ResponseProfile {\n startTime: number\n}\n\ninterface ResponseMetadata extends Record<string, unknown> {\n profile?: ResponseProfile\n}\n\ninterface ResponseLocals {\n meta?: ResponseMetadata\n}\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<unknown, ResponseLocals>, next: NextFunction) => {\n res.locals.meta ??= {}\n res.locals.meta.profile = { startTime: Date.now() }\n next()\n}\n", "import type { Response } from 'express-serve-static-core'\n\nexport interface ResponseProfile {\n duration?: number\n endTime?: number\n startTime?: number\n}\n\nexport interface ResponseMetadata extends Record<string, unknown> {\n profile?: ResponseProfile\n}\n\nexport interface ResponseLocals extends Record<string, unknown> {\n meta?: ResponseMetadata\n}\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 = <TLocals extends ResponseLocals>(res: Response<unknown, TLocals>): Record<string, unknown> => {\n const meta = res.locals.meta ?? {}\n // NOTE: We should do this somewhere else to better separate concerns\n const profile = meta.profile\n if (profile !== undefined) {\n const startTime = profile.startTime\n if (startTime !== undefined) {\n const endTime = Date.now()\n const duration = endTime - startTime\n 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 type {\n Request, RequestHandler, Response,\n} from 'express-serve-static-core'\n\nimport type { ResponseLocals } from './getResponseMetadata.js'\nimport { getResponseMetadata } from './getResponseMetadata.js'\n\ninterface TransformResponseLocals extends ResponseLocals {\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 = (req, res, next) => {\n const json = res.json.bind(res)\n res.json = ((body: unknown) => {\n try {\n return json(transformResponse(body, req, res))\n } catch (ex) {\n next(ex)\n return res\n }\n }) as Response['json']\n next()\n}\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 * as z from 'zod/mini'\n\nimport { ReasonPhrases, StatusCodes } from '../HttpStatus.ts'\nimport type { ExpressError } from '../Model/index.ts'\n\n/**\n * Empty Zod schema for requests with no parameters.\n */\nexport const EmptyParamsZod = z.catchall(z.object({}), z.string())\n\n/**\n * Empty Zod schema for requests with no query parameters.\n */\nexport const EmptyQueryParamsZod = z.catchall(z.object({}), 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.optional(z.json()),\n response: z.optional(z.json()),\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.core.$ZodType<Record<string, string>> = typeof EmptyQueryParamsZod,\n TQuery extends typeof EmptyQueryParamsZod | z.core.$ZodType<Record<string, string | string[]>> = typeof EmptyQueryParamsZod,\n TBody extends z.core.$ZodType<unknown> = z.core.$ZodType<unknown>,\n TResponse extends z.core.$ZodType<unknown> = z.core.$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 = z.safeParse(validator, 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 = z.safeParse(validators.response, 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 typedReq = req as Request<Params, Res, Body, Query>\n const typedRes = res as Response<Res>\n const result: unknown = handler(typedReq, typedRes, next)\n if (isPromise(result)) {\n const resultPromise: Promise<unknown> = result\n await resultPromise\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", "json", "isDefined", "isDefined", "result", "isDefined"]
}
import type { NextFunction, Request, Response } from 'express-serve-static-core';
interface ResponseProfile {
startTime: number;
}
interface ResponseMetadata extends Record<string, unknown> {
profile?: ResponseProfile;
}
interface ResponseLocals {
meta?: ResponseMetadata;
}
/**

@@ -14,3 +23,4 @@ * Connect middleware to enable profiling of response lifecycle timing. To effectively profile

*/
export declare const responseProfiler: (_req: Request, res: Response, next: NextFunction) => void;
export declare const responseProfiler: (_req: Request, res: Response<unknown, ResponseLocals>, next: NextFunction) => void;
export {};
//# sourceMappingURL=responseProfiler.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"responseProfiler.d.ts","sourceRoot":"","sources":["../../../../src/middleware/metrics/responseProfiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAAE,OAAO,EAAE,QAAQ,EAChC,MAAM,2BAA2B,CAAA;AAElC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,SAMhF,CAAA"}
{"version":3,"file":"responseProfiler.d.ts","sourceRoot":"","sources":["../../../../src/middleware/metrics/responseProfiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAAE,OAAO,EAAE,QAAQ,EAChC,MAAM,2BAA2B,CAAA;AAElC,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,gBAAiB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,OAAO,CAAC,EAAE,eAAe,CAAA;CAC1B;AAED,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,gBAAgB,CAAA;CACxB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,OAAO,EAAE,KAAK,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,MAAM,YAAY,SAIzG,CAAA"}
import type { Response } from 'express-serve-static-core';
export interface ResponseProfile {
duration?: number;
endTime?: number;
startTime?: number;
}
export interface ResponseMetadata extends Record<string, unknown> {
profile?: ResponseProfile;
}
export interface ResponseLocals extends Record<string, unknown> {
meta?: ResponseMetadata;
}
/**

@@ -7,3 +18,3 @@ * Extracts response metadata from res.locals, computing profile duration if profiling was started.

*/
export declare const getResponseMetadata: (res: Response) => Record<string, unknown>;
export declare const getResponseMetadata: <TLocals extends ResponseLocals>(res: Response<unknown, TLocals>) => Record<string, unknown>;
//# sourceMappingURL=getResponseMetadata.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"getResponseMetadata.d.ts","sourceRoot":"","sources":["../../../../src/middleware/standardResponses/getResponseMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAEzD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,QAAQ,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAezE,CAAA"}
{"version":3,"file":"getResponseMetadata.d.ts","sourceRoot":"","sources":["../../../../src/middleware/standardResponses/getResponseMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAEzD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,OAAO,CAAC,EAAE,eAAe,CAAA;CAC1B;AAED,MAAM,WAAW,cAAe,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7D,IAAI,CAAC,EAAE,gBAAgB,CAAA;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,SAAS,cAAc,EAAE,KAAK,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAe3H,CAAA"}

@@ -1,1 +0,1 @@

{"version":3,"file":"standardResponses.d.ts","sourceRoot":"","sources":["../../../../src/middleware/standardResponses/standardResponses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACD,cAAc,EAAE,QAAQ,EAClC,MAAM,2BAA2B,CAAA;AAQlC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,QAAQ,KAAG,IAEpD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,QAAQ,KAAG,IAEtD,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,QAAQ,KAAG,OAEtD,CAAA;AAiBD;;;GAGG;AAEH,eAAO,MAAM,iBAAiB,EAAE,cAAkE,CAAA"}
{"version":3,"file":"standardResponses.d.ts","sourceRoot":"","sources":["../../../../src/middleware/standardResponses/standardResponses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACD,cAAc,EAAE,QAAQ,EAClC,MAAM,2BAA2B,CAAA;AASlC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,QAAQ,KAAG,IAEpD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,QAAQ,KAAG,IAEtD,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,QAAQ,KAAG,OAEtD,CAAA;AAiBD;;;GAGG;AAEH,eAAO,MAAM,iBAAiB,EAAE,cAW/B,CAAA"}

@@ -1,1 +0,1 @@

{"version":3,"file":"requestHandlerValidator.d.ts","sourceRoot":"","sources":["../../../src/Validation/requestHandlerValidator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAChD,MAAM,2BAA2B,CAAA;AAElC,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAI7B;;GAEG;AACH,eAAO,MAAM,cAAc,gEAAuC,CAAA;AAElE;;GAEG;AACH,eAAO,MAAM,mBAAmB,oIAAuE,CAAA;AAEvG;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;CAKnC,CAAA;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,SAAS,OAAO,mBAAmB,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,OAAO,mBAAmB,EACjH,MAAM,SAAS,OAAO,mBAAmB,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,GAAG,OAAO,mBAAmB,EAC3H,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EACjE,SAAS,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EACrE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,KAAK,CAAA;IACX,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAC,IAOQ,SAAS,CAAC,GAAG,EAAE,OAAO,+FAA0B,EAAE,GAAG,EAAE,QAAQ,0BAAK,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,KAAG,cAAc,CAkE9H"}
{"version":3,"file":"requestHandlerValidator.d.ts","sourceRoot":"","sources":["../../../src/Validation/requestHandlerValidator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAChD,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAK7B;;GAEG;AACH,eAAO,MAAM,cAAc,gEAAuC,CAAA;AAElE;;GAEG;AACH,eAAO,MAAM,mBAAmB,oIAAuE,CAAA;AAEvG;;GAEG;AACH,eAAO,MAAM,uBAAuB;;;;;CAKnC,CAAA;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,SAAS,OAAO,mBAAmB,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,OAAO,mBAAmB,EACjH,MAAM,SAAS,OAAO,mBAAmB,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,GAAG,OAAO,mBAAmB,EAC3H,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EACjE,SAAS,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EACrE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,KAAK,CAAA;IACX,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAC,IAOQ,SAAS,CAAC,GAAG,EAAE,OAAO,+FAA0B,EAAE,GAAG,EAAE,QAAQ,0BAAK,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,KAAG,cAAc,CAoE9H"}
{
"name": "@xylabs/express",
"version": "6.0.2",
"version": "6.0.3",
"description": "SDK for base code for Api repos that use express and deploy on AWS ECS",

@@ -49,5 +49,5 @@ "keywords": [

"dependencies": {
"@xylabs/assert": "~6.0.2",
"@xylabs/logger": "~6.0.2",
"@xylabs/typeof": "~6.0.2"
"@xylabs/typeof": "~6.0.3",
"@xylabs/logger": "~6.0.3",
"@xylabs/assert": "~6.0.3"
},

@@ -57,15 +57,12 @@ "devDependencies": {

"@types/connect": "^3.4.38",
"@types/express-mung": "^0.5.5",
"@types/express-serve-static-core": "^5.1.1",
"@types/node": "^25.9.1",
"@xylabs/toolchain": "^8.1.1",
"@xylabs/tsconfig": "^8.1.1",
"@xylabs/toolchain": "^8.1.4",
"@xylabs/tsconfig": "^8.1.4",
"body-parser": "^2.2.2",
"connect": "^3.7.0",
"eslint": "^10.4.0",
"express-mung": "^0.5.1",
"http-status-codes": "^2.3.0",
"rollbar": "^3.1.0",
"typescript": "^6.0.3",
"vite": "^8.0.13",
"vite": "^8.0.14",
"vitest": "^4.1.7",

@@ -76,3 +73,3 @@ "vitest-mock-extended": "^4.0.0",

"zod": "^4.4.3",
"@xylabs/vitest-extended": "~6.0.2"
"@xylabs/vitest-extended": "~6.0.3"
},

@@ -82,4 +79,2 @@ "peerDependencies": {

"connect": "^3.7",
"express-mung": "^0.5",
"http-status-codes": "^2.3",
"rollbar": "^3.1",

@@ -86,0 +81,0 @@ "winston": "^3.19",