@xylabs/express 5.0.80 → 5.0.81

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.
Files changed (65) hide show
  1. package/README.md +229 -55
  2. package/package.json +10 -14
  3. package/src/Handler/RouteDefinition/RouteDefinition.ts +0 -18
  4. package/src/Handler/RouteDefinition/addRouteDefinitions.ts +0 -9
  5. package/src/Handler/RouteDefinition/index.ts +0 -2
  6. package/src/Handler/StatusCodeHandlers/index.ts +0 -1
  7. package/src/Handler/StatusCodeHandlers/notImplemented.ts +0 -6
  8. package/src/Handler/asyncHandler.ts +0 -21
  9. package/src/Handler/errorToJsonHandler.ts +0 -16
  10. package/src/Handler/index.ts +0 -4
  11. package/src/HttpUtil/getHttpHeader.ts +0 -27
  12. package/src/HttpUtil/index.ts +0 -1
  13. package/src/Logger/LogFormats/LocalDev/index.ts +0 -1
  14. package/src/Logger/LogFormats/LocalDev/logFormatLocalDev.ts +0 -11
  15. package/src/Logger/LogFormats/Rollbar/index.ts +0 -1
  16. package/src/Logger/LogFormats/Rollbar/logFormatRollbar.ts +0 -5
  17. package/src/Logger/LogFormats/Structured/index.ts +0 -1
  18. package/src/Logger/LogFormats/Structured/logFormatStructured.ts +0 -7
  19. package/src/Logger/LogFormats/index.ts +0 -3
  20. package/src/Logger/LoggerMeta.ts +0 -1
  21. package/src/Logger/LoggerOptions.ts +0 -7
  22. package/src/Logger/LoggerVerbosity.ts +0 -1
  23. package/src/Logger/Transports/Rollbar/RollbarTransport.ts +0 -24
  24. package/src/Logger/Transports/Rollbar/canGetDefaultRollbarTransport.ts +0 -3
  25. package/src/Logger/Transports/Rollbar/getDefaultRollbarTransport.ts +0 -10
  26. package/src/Logger/Transports/Rollbar/index.ts +0 -3
  27. package/src/Logger/Transports/index.ts +0 -1
  28. package/src/Logger/WinstonVerbosity.ts +0 -5
  29. package/src/Logger/WrappedWinstonLogger.ts +0 -20
  30. package/src/Logger/getDefaultLogger.ts +0 -21
  31. package/src/Logger/getLogger.ts +0 -55
  32. package/src/Logger/index.ts +0 -13
  33. package/src/Logger/toWinstonVerbosity.ts +0 -6
  34. package/src/Model/ExpressError.ts +0 -3
  35. package/src/Model/index.ts +0 -1
  36. package/src/Performance/Counters.ts +0 -36
  37. package/src/Performance/Profiler.ts +0 -10
  38. package/src/Performance/index.ts +0 -2
  39. package/src/Util/compactObject.ts +0 -9
  40. package/src/Util/index.ts +0 -2
  41. package/src/Util/tryParse.ts +0 -17
  42. package/src/Validation/index.ts +0 -1
  43. package/src/Validation/requestHandlerValidator.ts +0 -120
  44. package/src/index.ts +0 -8
  45. package/src/middleware/caseInsensitiveRouting/caseInsensitiveRouting.ts +0 -21
  46. package/src/middleware/caseInsensitiveRouting/index.ts +0 -1
  47. package/src/middleware/customPoweredByHeader/customPoweredByHeader.ts +0 -29
  48. package/src/middleware/customPoweredByHeader/index.ts +0 -1
  49. package/src/middleware/index.ts +0 -5
  50. package/src/middleware/jsonBodyParser/index.ts +0 -1
  51. package/src/middleware/jsonBodyParser/jsonBodyParser.ts +0 -59
  52. package/src/middleware/metrics/counters.ts +0 -25
  53. package/src/middleware/metrics/index.ts +0 -2
  54. package/src/middleware/metrics/responseProfiler.ts +0 -23
  55. package/src/middleware/standardResponses/getResponseMetadata.ts +0 -18
  56. package/src/middleware/standardResponses/index.ts +0 -4
  57. package/src/middleware/standardResponses/jsonApi/README.md +0 -4
  58. package/src/middleware/standardResponses/jsonApi/error.ts +0 -52
  59. package/src/middleware/standardResponses/jsonApi/index.ts +0 -5
  60. package/src/middleware/standardResponses/jsonApi/links.ts +0 -6
  61. package/src/middleware/standardResponses/jsonApi/relationship.ts +0 -43
  62. package/src/middleware/standardResponses/jsonApi/resourceIdentifier.ts +0 -15
  63. package/src/middleware/standardResponses/jsonApi/response.ts +0 -49
  64. package/src/middleware/standardResponses/standardErrors.ts +0 -27
  65. package/src/middleware/standardResponses/standardResponses.ts +0 -61
@@ -1,24 +0,0 @@
1
- import type Rollbar from 'rollbar'
2
- import type { TransportStreamOptions } from 'winston-transport'
3
- import Transport from 'winston-transport'
4
-
5
- import { logFormatRollbar } from '../../LogFormats/index.ts'
6
-
7
- export class RollbarTransport extends Transport {
8
- protected readonly rollbar?: Rollbar
9
- constructor(
10
- opts: TransportStreamOptions,
11
- rollbar?: Rollbar,
12
- ) {
13
- super({
14
- ...opts, format: logFormatRollbar, level: 'error',
15
- })
16
- this.rollbar = rollbar
17
- }
18
-
19
- override log(info: { message?: string }, next: () => void) {
20
- this.rollbar?.error(info?.message)
21
- this.emit('logged', info?.message)
22
- next()
23
- }
24
- }
@@ -1,3 +0,0 @@
1
- export const canGetDefaultRollbarTransport = (env: { [key: string]: string | undefined }): boolean => {
2
- return env.ROLLBAR_ACCESS_TOKEN === undefined ? false : true
3
- }
@@ -1,10 +0,0 @@
1
- import { assertEx } from '@xylabs/assert'
2
- import Rollbar from 'rollbar'
3
-
4
- import { RollbarTransport } from './RollbarTransport.ts'
5
-
6
- export const getDefaultRollbarTransport = (env: { [key: string]: string | undefined }): RollbarTransport => {
7
- const accessToken = assertEx(env.ROLLBAR_ACCESS_TOKEN, () => 'Missing ROLLBAR_ACCESS_TOKEN ENV VAR')
8
- const rollbar: Rollbar = new Rollbar({ accessToken })
9
- return new RollbarTransport({}, rollbar)
10
- }
@@ -1,3 +0,0 @@
1
- export * from './canGetDefaultRollbarTransport.ts'
2
- export * from './getDefaultRollbarTransport.ts'
3
- export * from './RollbarTransport.ts'
@@ -1 +0,0 @@
1
- export * from './Rollbar/index.ts'
@@ -1,5 +0,0 @@
1
- /**
2
- * Follows NPM log levels
3
- * https://docs.npmjs.com/cli/v8/using-npm/logging#loglevel
4
- */
5
- export type WinstonVerbosity = 'error' | 'warn' | 'info' | 'http' | 'verbose' | 'debug' | 'silly'
@@ -1,20 +0,0 @@
1
- import type { LogFunction, Logger } from '@xylabs/logger'
2
- import type { Logger as Winston } from 'winston'
3
-
4
- /**
5
- * Wrap Winston logger methods to adapt to familiar
6
- * console logging methods
7
- */
8
- export class WrappedWinstonLogger implements Logger {
9
- protected readonly winston: Winston
10
- constructor(winston: Winston) {
11
- this.winston = winston
12
- }
13
-
14
- debug: LogFunction = message => this.winston.debug(message)
15
- error: LogFunction = message => this.winston.error(message)
16
- info: LogFunction = message => this.winston.info(message)
17
- log: LogFunction = message => this.winston.info(message)
18
- trace: LogFunction = message => this.winston.debug(message)
19
- warn: LogFunction = message => this.winston.warn(message)
20
- }
@@ -1,21 +0,0 @@
1
- import type { Logger } from '@xylabs/logger'
2
-
3
- import { getLogger } from './getLogger.ts'
4
- import type { WrappedWinstonLogger } from './WrappedWinstonLogger.ts'
5
-
6
- /**
7
- * Static instance to prevent multiple instances of the same logger
8
- * with the same config
9
- */
10
-
11
- declare global {
12
- var xy: {
13
- defaultLogger?: WrappedWinstonLogger
14
- }
15
- }
16
-
17
- export const getDefaultLogger = (): Logger => {
18
- if (globalThis.xy === undefined) globalThis.xy = {}
19
- if (globalThis.xy.defaultLogger) return globalThis.xy.defaultLogger
20
- return getLogger()
21
- }
@@ -1,55 +0,0 @@
1
- import type { Logger } from '@xylabs/logger'
2
- import { createLogger, transports as winstonTransports } from 'winston'
3
- import type TransportStream from 'winston-transport'
4
-
5
- import { logFormatLocalDev, logFormatStructured } from './LogFormats/index.ts'
6
- import type { LoggerVerbosity } from './LoggerVerbosity.ts'
7
- import { toWinstonVerbosity } from './toWinstonVerbosity.ts'
8
- import { canGetDefaultRollbarTransport, getDefaultRollbarTransport } from './Transports/index.ts'
9
- import type { WinstonVerbosity } from './WinstonVerbosity.ts'
10
- import { WrappedWinstonLogger } from './WrappedWinstonLogger.ts'
11
-
12
- const exitOnError = false
13
- const handleRejections = true
14
-
15
- const { Console } = winstonTransports
16
- const consoleTransport = new Console()
17
- const format = process.env.NODE_ENV === 'development' ? logFormatLocalDev : logFormatStructured
18
- const transports: TransportStream[] = [consoleTransport]
19
- if (canGetDefaultRollbarTransport(process.env)) {
20
- try {
21
- const rollbarTransport = getDefaultRollbarTransport(process.env)
22
- transports.push(rollbarTransport)
23
- } catch {
24
- // NOTE: No error here, just gracefully adding logger if ENV VARs
25
- // were preset
26
- }
27
- }
28
-
29
- const loggers: Record<WinstonVerbosity, Logger | undefined> = {
30
- debug: undefined,
31
- error: undefined,
32
- http: undefined,
33
- info: undefined,
34
- silly: undefined,
35
- verbose: undefined,
36
- warn: undefined,
37
- }
38
-
39
- export const getLogger = (minVerbosity: LoggerVerbosity = 'info'): Logger => {
40
- const level = toWinstonVerbosity(minVerbosity)
41
- const existing = loggers[level]
42
- if (existing) return existing
43
- const logger = new WrappedWinstonLogger(
44
- createLogger({
45
- exitOnError,
46
- format,
47
- handleRejections,
48
- level,
49
- rejectionHandlers: transports,
50
- transports,
51
- }),
52
- )
53
- loggers[level] = logger
54
- return logger
55
- }
@@ -1,13 +0,0 @@
1
- export * from './getDefaultLogger.ts'
2
- export * from './getLogger.ts'
3
- export * from './LoggerMeta.ts'
4
- export * from './LoggerOptions.ts'
5
- export * from './LoggerVerbosity.ts'
6
- export * from './WrappedWinstonLogger.ts'
7
- import type { LogFunction as XyLabsLogFunction, Logger as XyLabsLogger } from '@xylabs/logger'
8
-
9
- /** @deprecated use from @xylabs/logger instead */
10
- export type LogFunction = XyLabsLogFunction
11
-
12
- /** @deprecated use from @xylabs/logger instead */
13
- export type Logger = XyLabsLogger
@@ -1,6 +0,0 @@
1
- import type { LoggerVerbosity } from './LoggerVerbosity.ts'
2
- import type { WinstonVerbosity } from './WinstonVerbosity.ts'
3
-
4
- export const toWinstonVerbosity = (loggerVerbosity: LoggerVerbosity): WinstonVerbosity => {
5
- return loggerVerbosity === 'all' ? 'silly' : loggerVerbosity
6
- }
@@ -1,3 +0,0 @@
1
- export interface ExpressError extends Error {
2
- statusCode?: number
3
- }
@@ -1 +0,0 @@
1
- export * from './ExpressError.ts'
@@ -1,36 +0,0 @@
1
- export class Counters {
2
- static counters: Record<string, number> = {}
3
-
4
- static inc(name: string, count = 1) {
5
- this.catchError(name, (name: string) => {
6
- this.counters[name] = (this.counters[name] ?? 0) + count
7
- })
8
- }
9
-
10
- static max(name: string, count: number) {
11
- this.catchError(name, (name: string) => {
12
- const currentValue = this.counters[name]
13
- if (currentValue === undefined || count > currentValue) {
14
- this.counters[name] = count
15
- }
16
- })
17
- }
18
-
19
- static min(name: string, count: number) {
20
- this.catchError(name, (name: string) => {
21
- const currentValue = this.counters[name]
22
- if (currentValue === undefined || count < currentValue) {
23
- this.counters[name] = count
24
- }
25
- })
26
- }
27
-
28
- private static catchError = (name: string, func: (name: string) => void) => {
29
- try {
30
- func(name)
31
- } catch {
32
- this.counters[name] = 0
33
- this.inc('CountersErrors')
34
- }
35
- }
36
- }
@@ -1,10 +0,0 @@
1
- export class Profiler {
2
- stats: Record<string, number> = {}
3
-
4
- async profile<T>(name: string, promise: Promise<T>) {
5
- const start = Date.now()
6
- const result = await promise
7
- this.stats[name] = Date.now() - start
8
- return result
9
- }
10
- }
@@ -1,2 +0,0 @@
1
- export * from './Counters.ts'
2
- export * from './Profiler.ts'
@@ -1,9 +0,0 @@
1
- export const compactObject = <T extends Record<string, unknown>>(obj: T) => {
2
- const result: Record<string, unknown> = {}
3
- for (const key in obj) {
4
- if (obj[key] !== undefined && obj[key] !== null) {
5
- result[key] = obj[key]
6
- }
7
- }
8
- return result as T
9
- }
package/src/Util/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './compactObject.ts'
2
- export * from './tryParse.ts'
@@ -1,17 +0,0 @@
1
- import { isDefined } from '@xylabs/typeof'
2
-
3
- export type ParseFunc<T = number> = (value: string) => T
4
-
5
- /**
6
- * @deprecated use zod instead
7
- */
8
- export const tryParse = <T = number>(func: ParseFunc<T>, value?: string) => {
9
- try {
10
- const result = isDefined(value) ? func(value) : null
11
- if (!Number.isNaN(result) && result !== null) {
12
- return result
13
- }
14
- } catch {
15
- return
16
- }
17
- }
@@ -1 +0,0 @@
1
- export * from './requestHandlerValidator.ts'
@@ -1,120 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { isDefined, isPromise } from '@xylabs/typeof'
3
- import type {
4
- NextFunction, Request, RequestHandler, Response,
5
- } from 'express'
6
- import { ReasonPhrases, StatusCodes } from 'http-status-codes'
7
- import * as z from 'zod'
8
-
9
- import type { ExpressError } from '../Model/index.ts'
10
-
11
- /**
12
- * Empty Zod schema for requests with no parameters.
13
- */
14
- export const EmptyParamsZod = z.object({}).catchall(z.string())
15
-
16
- /**
17
- * Empty Zod schema for requests with no query parameters.
18
- */
19
- export const EmptyQueryParamsZod = z.object({}).catchall(z.union([z.string(), z.array(z.string())]))
20
-
21
- /**
22
- * Default validation schemas for request handler validator.
23
- */
24
- export const ValidateRequestDefaults = {
25
- params: EmptyParamsZod,
26
- query: EmptyQueryParamsZod,
27
- body: z.json().optional(),
28
- response: z.json().optional(),
29
- }
30
-
31
- type ValidatableRequestKey = 'params' | 'query' | 'body'
32
-
33
- /**
34
- * Factory for Express middleware that validates request and response objects using Zod schemas.
35
- * @param schemas The Zod schemas to use for validation.
36
- * @returns A middleware function for validating requests and responses.
37
- */
38
- export function requestHandlerValidator<
39
- TParams extends typeof EmptyQueryParamsZod | z.ZodType<Record<string, string>> = typeof EmptyQueryParamsZod,
40
- TQuery extends typeof EmptyQueryParamsZod | z.ZodType<Record<string, string | string[]>> = typeof EmptyQueryParamsZod,
41
- TBody extends z.ZodType<unknown> = z.ZodType<unknown>,
42
- TResponse extends z.ZodType<unknown> = z.ZodType<unknown>,
43
- >(schemas?: Partial<{
44
- body: TBody
45
- params: TParams
46
- query: TQuery
47
- response: TResponse
48
- }>) {
49
- type Params = z.infer<TParams>
50
- type Query = z.infer<TQuery>
51
- type Body = z.infer<TBody>
52
- type Res = z.infer<TResponse>
53
- const validators = { ...ValidateRequestDefaults, ...schemas }
54
-
55
- return (handler: (req: Request<Params, Res, Body, Query>, res: Response<Res>, next: NextFunction) => unknown): RequestHandler => {
56
- return async (req: Request, res: Response, next: NextFunction) => {
57
- const originalJson = res.json.bind(res)
58
- try {
59
- // Validate incoming request
60
- const errors: string[] = []
61
- const keys: ValidatableRequestKey[] = ['params', 'query', 'body']
62
- for (const key of keys) {
63
- const validator = validators[key]
64
- const result = validator.safeParse(req[key])
65
- if (result.success) {
66
- if (isDefined(result.data)) Object.assign(req[key], result.data)
67
- } else {
68
- errors.push(
69
- ...result.error.issues.map(
70
- issue => (issue.path.length === 0)
71
- ? `${key}: ${issue.message}`
72
- : `${key}.${issue.path.join('.')}: ${issue.message}`,
73
- ),
74
- )
75
- }
76
- }
77
-
78
- // If there were validation errors, short-circuit and return Bad Request
79
- if (errors.length > 0) {
80
- const message = errors.join('; ')
81
- const err: ExpressError = new Error(message)
82
- err.name = ReasonPhrases.BAD_REQUEST
83
- err.statusCode = StatusCodes.BAD_REQUEST
84
- next(err)
85
- return false
86
- }
87
-
88
- // Wrap res.json to validate outgoing response
89
- res.json = (data: any) => {
90
- const result = validators.response.safeParse(data)
91
- if (result.success) {
92
- return originalJson(result.data)
93
- } else {
94
- const message = result.error.issues.map(
95
- issue => (issue.path.length === 0)
96
- ? `response: ${issue.message}`
97
- : `response.${issue.path.join('.')}: ${issue.message}`,
98
- ).join('; ')
99
- const err: ExpressError = new Error(message)
100
- err.name = ReasonPhrases.INTERNAL_SERVER_ERROR
101
- err.statusCode = StatusCodes.INTERNAL_SERVER_ERROR
102
-
103
- // Restore original json function in case the error handler wants to use it
104
- res.json = originalJson
105
- throw err
106
- }
107
- }
108
-
109
- // Automatically handle async errors
110
- const result = handler(req as any, res as any, next)
111
- if (result && isPromise(result)) {
112
- await result
113
- }
114
- } catch (err) {
115
- res.json = originalJson
116
- next(err)
117
- }
118
- }
119
- }
120
- }
package/src/index.ts DELETED
@@ -1,8 +0,0 @@
1
- export * from './Handler/index.ts'
2
- export * from './HttpUtil/index.ts'
3
- export * from './Logger/index.ts'
4
- export * from './middleware/index.ts'
5
- export * from './Model/index.ts'
6
- export * from './Performance/index.ts'
7
- export * from './Util/index.ts'
8
- export * from './Validation/index.ts'
@@ -1,21 +0,0 @@
1
- import type { Express } from 'express'
2
-
3
- const setting = 'case sensitive routing'
4
-
5
- /**
6
- * Enable case sensitivity. When enabled, "/Foo" and "/foo" are different
7
- * routes. When disabled, "/Foo" and "/foo" are treated the same.
8
- * @param app The Express app to disable the header on.
9
- */
10
- export const enableCaseSensitiveRouting = (app: Express) => {
11
- app.enable(setting)
12
- }
13
-
14
- /**
15
- * Disable case sensitivity. When enabled, "/Foo" and "/foo" are different
16
- * routes. When disabled, "/Foo" and "/foo" are treated the same.
17
- * @param app The Express app to disable the header on.
18
- */
19
- export const disableCaseSensitiveRouting = (app: Express) => {
20
- app.disable(setting)
21
- }
@@ -1 +0,0 @@
1
- export * from './caseInsensitiveRouting.ts'
@@ -1,29 +0,0 @@
1
- import type {
2
- Express, NextFunction, Request, Response,
3
- } from 'express'
4
-
5
- const header = 'X-Powered-By'
6
- const setting = 'x-powered-by'
7
-
8
- /**
9
- * By default Express appends the `X-Powered-By: Express` header to
10
- * all responses. Calling this method enables that behavior.
11
- * @param app The Express app to disable the header on.
12
- */
13
- export const enableExpressDefaultPoweredByHeader = (app: Express) => {
14
- app.enable(setting)
15
- }
16
-
17
- /**
18
- * By default Express appends the `X-Powered-By: Express` header to
19
- * all responses. Calling this method disables that behavior.
20
- * @param app The Express app to disable the header on.
21
- */
22
- export const disableExpressDefaultPoweredByHeader = (app: Express) => {
23
- app.disable(setting)
24
- }
25
-
26
- export const customPoweredByHeader = (req: Request, res: Response, next: NextFunction) => {
27
- res.setHeader(header, 'XYO')
28
- next()
29
- }
@@ -1 +0,0 @@
1
- export * from './customPoweredByHeader.ts'
@@ -1,5 +0,0 @@
1
- export * from './caseInsensitiveRouting/index.ts'
2
- export * from './customPoweredByHeader/index.ts'
3
- export * from './jsonBodyParser/index.ts'
4
- export * from './metrics/index.ts'
5
- export * from './standardResponses/index.ts'
@@ -1 +0,0 @@
1
- export * from './jsonBodyParser.ts'
@@ -1,59 +0,0 @@
1
- import type { OptionsJson } from 'body-parser'
2
- import bodyParser from 'body-parser'
3
- import type { NextHandleFunction } from 'connect'
4
-
5
- import { getDefaultLogger } from '../../Logger/index.ts'
6
-
7
- /**
8
- * The default maximum request body size for the JSON Body Parser
9
- */
10
- export const DefaultJsonBodyParserOptionsLimit = '100kb'
11
-
12
- /**
13
- * The default MIME types for the JSON Body Parser
14
- */
15
- export const DefaultJsonBodyParserOptionsTypes = ['application/json', 'text/json']
16
-
17
- /**
18
- * The default options for the JSON Body Parser
19
- */
20
- export const DefaultJsonBodyParserOptions: OptionsJson = {
21
- limit: DefaultJsonBodyParserOptionsLimit,
22
- type: DefaultJsonBodyParserOptionsTypes,
23
- }
24
-
25
- /**
26
- * Gets the default JSON Body Parser options merged with the supplied options
27
- * with the supplied options taking precedence
28
- * @param options The options to override the default JSON Body Parser options with
29
- * @returns The combined JSON Body Parser options with the supplied values taking
30
- * precedence over the default
31
- */
32
- export const getJsonBodyParserOptions = (options?: Partial<OptionsJson>): OptionsJson => {
33
- return options ? { ...DefaultJsonBodyParserOptions, ...options } : DefaultJsonBodyParserOptions
34
- }
35
-
36
- /**
37
- * Get a JSON Body Parser connect middleware handler
38
- * @param options The options for the JSON Body Parser
39
- * @returns A middleware function that parses JSON bodies
40
- */
41
- export const getJsonBodyParser = (options: OptionsJson = DefaultJsonBodyParserOptions): NextHandleFunction => {
42
- // Create closed instance of bodyParser to prevent instantiation of new instance on every request
43
- const parser = bodyParser.json(options)
44
-
45
- return (req, res, next) => {
46
- // If we do not trap this error, then it dumps too much to log, usually happens if request aborted
47
- try {
48
- parser(req, res, next)
49
- } catch (ex) {
50
- const error = ex as Error
51
- getDefaultLogger().log(`bodyParser failed [${error?.name}]: ${error?.message}`)
52
- }
53
- }
54
- }
55
-
56
- /**
57
- * A JSON Body Parser middleware handler initialized with the default options
58
- */
59
- export const jsonBodyParser = getJsonBodyParser()
@@ -1,25 +0,0 @@
1
- import type {
2
- Application, NextFunction, Request, Response,
3
- } from 'express'
4
-
5
- import { Counters } from '../../Performance/index.ts'
6
-
7
- export const useRequestCounters = (app: Application): void => {
8
- // Configure Global counters
9
- app.use((req: Request, res: Response, next: NextFunction) => {
10
- Counters.inc(req.path)
11
- Counters.inc('_calls')
12
- next()
13
- })
14
-
15
- app.get('/stats', (req: Request, res: Response, next: NextFunction) => {
16
- /* #swagger.tags = ['Metrics'] */
17
- /* #swagger.summary = 'Get the counters for single instance of diviner' */
18
- res.json({
19
- alive: true,
20
- avgTime: `${((Counters.counters._totalTime ?? 0) / (Counters.counters._calls ?? 1)).toFixed(2)}ms`,
21
- counters: Counters.counters,
22
- })
23
- next()
24
- })
25
- }
@@ -1,2 +0,0 @@
1
- export * from './counters.ts'
2
- export * from './responseProfiler.ts'
@@ -1,23 +0,0 @@
1
- import type {
2
- NextFunction, Request, Response,
3
- } from 'express'
4
-
5
- /**
6
- * Connect middleware to enable profiling of response lifecycle timing. To effectively profile
7
- * the response timing, this middleware needs to be called first when initializing your Express
8
- * App
9
- * @example
10
- * const app = express()
11
- * app.use(responseProfiler)
12
- * // other initialization ...
13
- * @param _req The request
14
- * @param res The response
15
- * @param next The next function
16
- */
17
- export const responseProfiler = (_req: Request, res: Response, next: NextFunction) => {
18
- if (!res.locals?.meta) {
19
- res.locals.meta = {}
20
- }
21
- res.locals.meta.profile = { startTime: Date.now() }
22
- next()
23
- }
@@ -1,18 +0,0 @@
1
- import type { Response } from 'express'
2
-
3
- export const getResponseMetadata = (res: Response): Record<string, unknown> => {
4
- const meta: Record<string, unknown> = res.locals?.meta || {}
5
- // NOTE: We should do this somewhere else to better separate concerns
6
- const profile = res.locals.meta?.profile
7
- if (profile) {
8
- const startTime = profile?.startTime
9
- if (startTime) {
10
- const endTime = Date.now()
11
- const duration = endTime - startTime
12
- res.locals.meta.profile = {
13
- duration, endTime, startTime,
14
- }
15
- }
16
- }
17
- return meta
18
- }
@@ -1,4 +0,0 @@
1
- export * from './getResponseMetadata.ts'
2
- export * from './jsonApi/index.ts'
3
- export * from './standardErrors.ts'
4
- export * from './standardResponses.ts'
@@ -1,4 +0,0 @@
1
- # JSON API
2
-
3
- The following interfaces/types attempt to capture the
4
- [JSON API 1.0](https://jsonapi.org/) specification as closely as possible