@xylabs/express 4.8.0-rc.2 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  [![logo][]](https://xylabs.com)
2
2
 
3
- # @xylabs/sdk-api-express-ecs-js
3
+ # @xylabs/express
4
4
 
5
5
  [![main-build][]][main-build-link]
6
6
  [![npm-badge][]][npm-link]
@@ -25,13 +25,13 @@ SDK for base code for Api repos that use express and deploy on AWS ECS
25
25
  Using npm:
26
26
 
27
27
  ```sh
28
- npm i --save @xylabs/sdk-api-express-ecs
28
+ npm i --save @xylabs/express
29
29
  ```
30
30
 
31
31
  Using yarn:
32
32
 
33
33
  ```sh
34
- yarn add @xylabs/sdk-api-express-ecs
34
+ yarn add @xylabs/express
35
35
  ```
36
36
 
37
37
  ## Scripts
@@ -52,11 +52,11 @@ See the [LICENSE](LICENSE) file for license details
52
52
  [Made with 🔥 and ❄️ by XY Labs](https://xylabs.com)
53
53
 
54
54
  [logo]: https://cdn.xy.company/img/brand/XYPersistentCompany_Logo_Icon_Colored.svg
55
- [main-build]: https://github.com/xylabs/sdk-api-express-ecs-js/actions/workflows/build.yml/badge.svg
56
- [main-build-link]: https://github.com/xylabs/sdk-api-express-ecs-js/actions/workflows/build.yml
57
- [npm-badge]: https://img.shields.io/npm/v/@xylabs/sdk-api-express-ecs.svg
58
- [npm-link]: https://www.npmjs.com/package/@xylabs/sdk-api-express-ecs
55
+ [main-build]: https://github.com/xylabs/express/actions/workflows/build.yml/badge.svg
56
+ [main-build-link]: https://github.com/xylabs/express/actions/workflows/build.yml
57
+ [npm-badge]: https://img.shields.io/npm/v/@xylabs/express.svg
58
+ [npm-link]: https://www.npmjs.com/package/@xylabs/express
59
59
  [codacy-badge]: https://app.codacy.com/project/badge/Grade/84270ff9f2aa4a669269191b715aa8d7
60
- [codacy-link]: https://www.codacy.com/gh/xylabs/sdk-api-express-ecs-js/dashboard?utm_source=github.com&utm_medium=referral&utm_content=xylabs/sdk-api-express-ecs-js&utm_campaign=Badge_Grade
60
+ [codacy-link]: https://www.codacy.com/gh/xylabs/express/dashboard?utm_source=github.com&utm_medium=referral&utm_content=xylabs/express&utm_campaign=Badge_Grade
61
61
  [codeclimate-badge]: https://api.codeclimate.com/v1/badges/1c8255608f551b2119d6/maintainability
62
- [codeclimate-link]: https://codeclimate.com/github/xylabs/sdk-api-express-ecs-js/maintainability
62
+ [codeclimate-link]: https://codeclimate.com/github/xylabs/express/maintainability
@@ -338,11 +338,19 @@ var standardErrors = (err, req, res, next) => {
338
338
 
339
339
  // src/middleware/standardResponses/standardResponses.ts
340
340
  import mung from "express-mung";
341
+ var setRawResponseFormat = (res) => {
342
+ res.locals.rawResponse = true;
343
+ };
344
+ var clearRawResponseFormat = (res) => {
345
+ res.locals.rawResponse = false;
346
+ };
347
+ var isRawResponseFormatSet = (res) => {
348
+ return res.locals.rawResponse ? true : false;
349
+ };
341
350
  var transformResponse = (body, _req, res) => {
342
- const meta = getResponseMetadata(res);
343
- return { data: body, meta };
351
+ return isRawResponseFormatSet(res) ? body : res.statusCode >= 200 && res.statusCode < 300 ? { data: body, meta: getResponseMetadata(res) } : { error: body, meta: getResponseMetadata(res) };
344
352
  };
345
- var standardResponses = mung.json(transformResponse, { mungError: false });
353
+ var standardResponses = mung.json(transformResponse, { mungError: true });
346
354
 
347
355
  // src/Util/compactObject.ts
348
356
  var compactObject = (obj) => {
@@ -379,6 +387,7 @@ export {
379
387
  DefaultJsonBodyParserOptionsTypes,
380
388
  Profiler,
381
389
  asyncHandler,
390
+ clearRawResponseFormat,
382
391
  compactObject,
383
392
  customPoweredByHeader,
384
393
  disableCaseSensitiveRouting,
@@ -393,12 +402,13 @@ export {
393
402
  getJsonBodyParserOptions,
394
403
  getLogger,
395
404
  getResponseMetadata,
405
+ isRawResponseFormatSet,
396
406
  jsonBodyParser,
397
407
  notImplemented,
398
408
  responseProfiler,
409
+ setRawResponseFormat,
399
410
  standardErrors,
400
411
  standardResponses,
401
- transformResponse,
402
412
  tryParse,
403
413
  tryParseFloat,
404
414
  tryParseInt,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/AWS/getEnvFromAws.ts","../../src/Handler/asyncHandler.ts","../../src/Handler/errorToJsonHandler.ts","../../src/Handler/StatusCodeHandlers/notImplemented.ts","../../src/HttpUtil/getHttpHeader.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/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"],"sourcesContent":["import { SecretsManager } from '@aws-sdk/client-secrets-manager'\nimport NodeCache from 'node-cache'\n\nconst region = 'us-east-1'\nconst envCache = new NodeCache({ stdTTL: 3600 * 24 })\n\nexport const getEnvFromAws = async (secretId: string) => {\n const cacheResult = envCache.get<Record<string, string>>(secretId)\n if (cacheResult) {\n return cacheResult\n } else {\n const client = new SecretsManager({ region })\n const awsResult = await client.getSecretValue({ SecretId: secretId })\n console.log(`ENV read from AWS Success [${awsResult?.Name}, ${!!awsResult?.SecretString}, ${!!awsResult?.SecretBinary}]`)\n if (awsResult?.SecretString) {\n const secretObject = JSON.parse(awsResult?.SecretString) as Record<string, string>\n console.log(`ENV read from AWS [${Object.entries(secretObject).length}]`)\n envCache.set(secretId, secretObject)\n return secretObject\n } else {\n throw new Error('Missing SecretString')\n }\n }\n}\n","import type {\n NextFunction, Request, RequestHandler, Response,\n} from 'express'\nimport type { ParamsDictionary, Query } from 'express-serve-static-core'\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\nexport interface Empty {}\n\nexport type NoReqParams = ParamsDictionary\nexport type NoResBody = Empty\nexport type NoReqBody = Empty\nexport type NoReqQuery = Query\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type NoLocals = Record<string, any>\n","import type {\n NextFunction, Request, Response,\n} from 'express'\n\nimport type { ExpressError } from '../Model/index.ts'\n\nexport const errorToJsonHandler = (error: ExpressError, req: Request, res: Response, next: NextFunction) => {\n if (error) {\n console.error(error.message)\n if (!error.statusCode) error.statusCode = 500\n res.status(error.statusCode).send({ error: error.message })\n }\n next(error)\n}\n","import type { RequestHandler } from 'express'\nimport { ReasonPhrases, StatusCodes } from 'http-status-codes'\n\nexport const notImplemented: RequestHandler = (_req, _res, next) => {\n next({ message: ReasonPhrases.NOT_IMPLEMENTED, statusCode: StatusCodes.NOT_IMPLEMENTED })\n}\n","import 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 = 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 { createLogger, transports as winstonTransports } from 'winston'\nimport type TransportStream from 'winston-transport'\n\nimport { logFormatLocalDev, logFormatStructured } from './LogFormats/index.ts'\nimport type { Logger } from './Logger.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\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\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\nexport const logFormatRollbar = simple()\n","import { format } from 'winston'\n\nconst {\n combine, timestamp, json,\n} = format\n\nexport const logFormatStructured = combine(timestamp(), json())\n","import type { LoggerVerbosity } from './LoggerVerbosity.ts'\nimport type { WinstonVerbosity } from './WinstonVerbosity.ts'\n\nexport const toWinstonVerbosity = (loggerVerbosity: LoggerVerbosity): WinstonVerbosity => {\n return loggerVerbosity === 'all' ? 'silly' : loggerVerbosity\n}\n","export const canGetDefaultRollbarTransport = (env: { [key: string]: string | undefined }): boolean => {\n return env.ROLLBAR_ACCESS_TOKEN ? true : false\n}\n","import { assertEx } from '@xylabs/assert'\nimport Rollbar from 'rollbar'\n\nimport { RollbarTransport } from './RollbarTransport.ts'\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\nexport class RollbarTransport extends Transport {\n constructor(\n opts: TransportStreamOptions,\n protected readonly rollbar?: Rollbar,\n ) {\n super({\n ...opts, format: logFormatRollbar, level: 'error',\n })\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 { Logger as Winston } from 'winston'\n\nimport type { LogFunction, Logger } from './Logger.ts'\n\n/**\n * Wrap Winston logger methods to adapt to familiar\n * console logging methods\n */\nexport class WrappedWinstonLogger implements Logger {\n constructor(protected readonly winston: Winston) {}\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 warn: LogFunction = message => this.winston.warn(message)\n}\n","import { getLogger } from './getLogger.ts'\nimport type { Logger } from './Logger.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\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'\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'\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\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\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 console.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","export 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","export 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'\n\nimport { Counters } from '../../Performance/index.ts'\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'\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'\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 type {\n NextFunction, Request, Response,\n} from 'express'\n\nimport type { ExpressError } from '../../Model/index.ts'\nimport type { ApiError } from './jsonApi/index.ts'\n\nexport const standardErrors = (err: ExpressError, req: Request, res: Response, next: NextFunction) => {\n if (!err) {\n next(err)\n return\n }\n console.error(err.message)\n if (!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 { Request, Response } from 'express'\nimport mung from 'express-mung'\n\nimport { getResponseMetadata } from './getResponseMetadata.ts'\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 */\nexport const transformResponse = (body: unknown, _req: Request, res: Response) => {\n const meta = getResponseMetadata(res)\n return { data: body, meta }\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 = mung.json(transformResponse, { mungError: false })\n","export 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","export type ParseFunc<T = number> = (value: string) => T\n\nexport const tryParse = <T = number>(func: ParseFunc<T>, value?: string) => {\n try {\n const result = value ? func(value) : null\n if (!Number.isNaN(result) && result !== null) {\n return result\n }\n } catch {\n return\n }\n}\n\nexport const tryParseFloat = (value?: string) => {\n return tryParse(Number.parseFloat, value)\n}\n\nexport const tryParseInt = (value?: string) => {\n return tryParse(Number.parseInt, value)\n}\n"],"mappings":"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","names":["header","format","format","combine","timestamp","format","setting","name"]}
1
+ {"version":3,"sources":["../../src/AWS/getEnvFromAws.ts","../../src/Handler/asyncHandler.ts","../../src/Handler/errorToJsonHandler.ts","../../src/Handler/StatusCodeHandlers/notImplemented.ts","../../src/HttpUtil/getHttpHeader.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/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"],"sourcesContent":["import { SecretsManager } from '@aws-sdk/client-secrets-manager'\nimport NodeCache from 'node-cache'\n\nconst region = 'us-east-1'\nconst envCache = new NodeCache({ stdTTL: 3600 * 24 })\n\nexport const getEnvFromAws = async (secretId: string) => {\n const cacheResult = envCache.get<Record<string, string>>(secretId)\n if (cacheResult) {\n return cacheResult\n } else {\n const client = new SecretsManager({ region })\n const awsResult = await client.getSecretValue({ SecretId: secretId })\n console.log(`ENV read from AWS Success [${awsResult?.Name}, ${!!awsResult?.SecretString}, ${!!awsResult?.SecretBinary}]`)\n if (awsResult?.SecretString) {\n const secretObject = JSON.parse(awsResult?.SecretString) as Record<string, string>\n console.log(`ENV read from AWS [${Object.entries(secretObject).length}]`)\n envCache.set(secretId, secretObject)\n return secretObject\n } else {\n throw new Error('Missing SecretString')\n }\n }\n}\n","import type {\n NextFunction, Request, RequestHandler, Response,\n} from 'express'\nimport type { ParamsDictionary, Query } from 'express-serve-static-core'\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\nexport interface Empty {}\n\nexport type NoReqParams = ParamsDictionary\nexport type NoResBody = Empty\nexport type NoReqBody = Empty\nexport type NoReqQuery = Query\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type NoLocals = Record<string, any>\n","import type {\n NextFunction, Request, Response,\n} from 'express'\n\nimport type { ExpressError } from '../Model/index.ts'\n\nexport const errorToJsonHandler = (error: ExpressError, req: Request, res: Response, next: NextFunction) => {\n if (error) {\n console.error(error.message)\n if (!error.statusCode) error.statusCode = 500\n res.status(error.statusCode).send({ error: error.message })\n }\n next(error)\n}\n","import type { RequestHandler } from 'express'\nimport { ReasonPhrases, StatusCodes } from 'http-status-codes'\n\nexport const notImplemented: RequestHandler = (_req, _res, next) => {\n next({ message: ReasonPhrases.NOT_IMPLEMENTED, statusCode: StatusCodes.NOT_IMPLEMENTED })\n}\n","import 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 = 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 { createLogger, transports as winstonTransports } from 'winston'\nimport type TransportStream from 'winston-transport'\n\nimport { logFormatLocalDev, logFormatStructured } from './LogFormats/index.ts'\nimport type { Logger } from './Logger.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\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\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\nexport const logFormatRollbar = simple()\n","import { format } from 'winston'\n\nconst {\n combine, timestamp, json,\n} = format\n\nexport const logFormatStructured = combine(timestamp(), json())\n","import type { LoggerVerbosity } from './LoggerVerbosity.ts'\nimport type { WinstonVerbosity } from './WinstonVerbosity.ts'\n\nexport const toWinstonVerbosity = (loggerVerbosity: LoggerVerbosity): WinstonVerbosity => {\n return loggerVerbosity === 'all' ? 'silly' : loggerVerbosity\n}\n","export const canGetDefaultRollbarTransport = (env: { [key: string]: string | undefined }): boolean => {\n return env.ROLLBAR_ACCESS_TOKEN ? true : false\n}\n","import { assertEx } from '@xylabs/assert'\nimport Rollbar from 'rollbar'\n\nimport { RollbarTransport } from './RollbarTransport.ts'\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\nexport class RollbarTransport extends Transport {\n constructor(\n opts: TransportStreamOptions,\n protected readonly rollbar?: Rollbar,\n ) {\n super({\n ...opts, format: logFormatRollbar, level: 'error',\n })\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 { Logger as Winston } from 'winston'\n\nimport type { LogFunction, Logger } from './Logger.ts'\n\n/**\n * Wrap Winston logger methods to adapt to familiar\n * console logging methods\n */\nexport class WrappedWinstonLogger implements Logger {\n constructor(protected readonly winston: Winston) {}\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 warn: LogFunction = message => this.winston.warn(message)\n}\n","import { getLogger } from './getLogger.ts'\nimport type { Logger } from './Logger.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\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'\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'\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\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\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 console.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","export 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","export 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'\n\nimport { Counters } from '../../Performance/index.ts'\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'\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'\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 type {\n NextFunction, Request, Response,\n} from 'express'\n\nimport type { ExpressError } from '../../Model/index.ts'\nimport type { ApiError } from './jsonApi/index.ts'\n\nexport const standardErrors = (err: ExpressError, req: Request, res: Response, next: NextFunction) => {\n if (!err) {\n next(err)\n return\n }\n console.error(err.message)\n if (!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'\nimport mung from 'express-mung'\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","export 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","export type ParseFunc<T = number> = (value: string) => T\n\nexport const tryParse = <T = number>(func: ParseFunc<T>, value?: string) => {\n try {\n const result = value ? func(value) : null\n if (!Number.isNaN(result) && result !== null) {\n return result\n }\n } catch {\n return\n }\n}\n\nexport const tryParseFloat = (value?: string) => {\n return tryParse(Number.parseFloat, value)\n}\n\nexport const tryParseInt = (value?: string) => {\n return tryParse(Number.parseInt, value)\n}\n"],"mappings":"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","names":["header","format","format","combine","timestamp","format","setting","name"]}
@@ -1,18 +1,27 @@
1
- import type { Request, Response } from 'express';
1
+ import type { RequestHandler, Response } from 'express';
2
2
  /**
3
- * Transforms each response to conform to the standard response format (compatible with JSON API)
4
- * @param body The original request body
5
- * @param _req The request
6
- * @param res The response
7
- * @returns The transformed response body
3
+ * Flags the response to forgo the standard response envelope
4
+ * and return the raw response body to the client
5
+ * @param res The response to disable the standard response format on
8
6
  */
9
- export declare const transformResponse: (body: unknown, _req: Request, res: Response) => {
10
- data: unknown;
11
- meta: Record<string, unknown>;
12
- };
7
+ export declare const setRawResponseFormat: (res: Response) => void;
8
+ /**
9
+ * Clears any flags on the response, allowing the response to
10
+ * use the default standard response envelope
11
+ * @param res The response to set to the standard response format
12
+ */
13
+ export declare const clearRawResponseFormat: (res: Response) => void;
14
+ /**
15
+ * Checks if there are any flags on the response that would cause it
16
+ * to forgo the standard response envelope and return the raw response
17
+ * body to the client
18
+ * @param res
19
+ * @returns True if there are any flags on the response, false otherwise
20
+ */
21
+ export declare const isRawResponseFormatSet: (res: Response) => boolean;
13
22
  /**
14
23
  * Connect middleware to enable the transform of all responses to match
15
24
  * the standard response format (compatible with JSON API)
16
25
  */
17
- export declare const standardResponses: import("express").RequestHandler<import(".store/@types-express-serve-static-core-npm-4.19.6-cc0017aaf4/package").ParamsDictionary, any, any, import(".store/@types-qs-npm-6.9.18-125db28c30/package").ParsedQs, Record<string, any>>;
26
+ export declare const standardResponses: RequestHandler;
18
27
  //# sourceMappingURL=standardResponses.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"standardResponses.d.ts","sourceRoot":"","sources":["../../../../src/middleware/standardResponses/standardResponses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAKhD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,OAAO,EAAE,MAAM,OAAO,EAAE,KAAK,QAAQ;;;CAG5E,CAAA;AAED;;;GAGG;AAEH,eAAO,MAAM,iBAAiB,sOAAqD,CAAA"}
1
+ {"version":3,"file":"standardResponses.d.ts","sourceRoot":"","sources":["../../../../src/middleware/standardResponses/standardResponses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACD,cAAc,EAAE,QAAQ,EAClC,MAAM,SAAS,CAAA;AAShB;;;;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"}
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/express",
3
- "version": "4.8.0-rc.2",
4
- "stableVersion": "4.7.1",
3
+ "version": "4.8.0",
5
4
  "description": "SDK for base code for Api repos that use express and deploy on AWS ECS",
6
5
  "keywords": [
7
6
  "xylabs",
@@ -46,9 +45,9 @@
46
45
  "coverage": "vitest --coverage"
47
46
  },
48
47
  "dependencies": {
49
- "@aws-sdk/client-secrets-manager": "^3.758.0",
50
- "@xylabs/assert": "^4.8.0-rc.2",
51
- "body-parser": "^1.20.3",
48
+ "@aws-sdk/client-secrets-manager": "^3.782.0",
49
+ "@xylabs/assert": "^4.8.0",
50
+ "body-parser": "^2.2.0",
52
51
  "express-mung": "^0.5.1",
53
52
  "http-status-codes": "^2.3.0",
54
53
  "node-cache": "^5.1.2",
@@ -62,19 +61,19 @@
62
61
  "@types/express": "^4.17.21",
63
62
  "@types/express-mung": "^0.5.5",
64
63
  "@types/express-serve-static-core": "^5.0.6",
65
- "@types/node": "^22.13.10",
66
- "@xylabs/ts-scripts-yarn3": "^6.1.3",
67
- "@xylabs/tsconfig": "^6.1.3",
68
- "@xylabs/vitest-extended": "^4.8.0-rc.2",
69
- "body-parser": "^1.20.3",
64
+ "@types/node": "^22.14.0",
65
+ "@xylabs/ts-scripts-yarn3": "^6.2.1",
66
+ "@xylabs/tsconfig": "^6.2.1",
67
+ "@xylabs/vitest-extended": "^4.8.0",
68
+ "body-parser": "^2.2.0",
70
69
  "express": "^4.21.2",
71
70
  "express-mung": "^0.5.1",
72
71
  "http-status-codes": "^2.3.0",
73
72
  "node-cache": "^5.1.2",
74
73
  "rollbar": "^2.26.4",
75
- "typescript": "^5.8.2",
76
- "vitest": "^3.0.9",
77
- "vitest-mock-extended": "^3.0.1",
74
+ "typescript": "^5.8.3",
75
+ "vitest": "^3.1.1",
76
+ "vitest-mock-extended": "^3.1.0",
78
77
  "winston": "^3.17.0",
79
78
  "winston-transport": "^4.9.0"
80
79
  },
@@ -1,7 +1,42 @@
1
- import type { Request, Response } from 'express'
1
+ import type {
2
+ Request, RequestHandler, Response,
3
+ } from 'express'
2
4
  import mung from 'express-mung'
3
5
 
4
- import { getResponseMetadata } from './getResponseMetadata.ts'
6
+ import { getResponseMetadata } from './getResponseMetadata.js'
7
+
8
+ interface TransformResponseLocals {
9
+ rawResponse?: boolean
10
+ }
11
+
12
+ /**
13
+ * Flags the response to forgo the standard response envelope
14
+ * and return the raw response body to the client
15
+ * @param res The response to disable the standard response format on
16
+ */
17
+ export const setRawResponseFormat = (res: Response): void => {
18
+ res.locals.rawResponse = true
19
+ }
20
+
21
+ /**
22
+ * Clears any flags on the response, allowing the response to
23
+ * use the default standard response envelope
24
+ * @param res The response to set to the standard response format
25
+ */
26
+ export const clearRawResponseFormat = (res: Response): void => {
27
+ res.locals.rawResponse = false
28
+ }
29
+
30
+ /**
31
+ * Checks if there are any flags on the response that would cause it
32
+ * to forgo the standard response envelope and return the raw response
33
+ * body to the client
34
+ * @param res
35
+ * @returns True if there are any flags on the response, false otherwise
36
+ */
37
+ export const isRawResponseFormatSet = (res: Response): boolean => {
38
+ return res.locals.rawResponse ? true : false
39
+ }
5
40
 
6
41
  /**
7
42
  * Transforms each response to conform to the standard response format (compatible with JSON API)
@@ -10,9 +45,12 @@ import { getResponseMetadata } from './getResponseMetadata.ts'
10
45
  * @param res The response
11
46
  * @returns The transformed response body
12
47
  */
13
- export const transformResponse = (body: unknown, _req: Request, res: Response) => {
14
- const meta = getResponseMetadata(res)
15
- return { data: body, meta }
48
+ const transformResponse = (body: unknown, _req: Request, res: Response<unknown, TransformResponseLocals>) => {
49
+ return isRawResponseFormatSet(res)
50
+ ? body
51
+ : (res.statusCode >= 200 && res.statusCode < 300)
52
+ ? { data: body, meta: getResponseMetadata(res) }
53
+ : { error: body, meta: getResponseMetadata(res) }
16
54
  }
17
55
 
18
56
  /**
@@ -20,4 +58,4 @@ export const transformResponse = (body: unknown, _req: Request, res: Response) =
20
58
  * the standard response format (compatible with JSON API)
21
59
  */
22
60
 
23
- export const standardResponses = mung.json(transformResponse, { mungError: false })
61
+ export const standardResponses: RequestHandler = mung.json(transformResponse, { mungError: true })