@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.
- package/README.md +229 -55
- package/package.json +10 -14
- package/src/Handler/RouteDefinition/RouteDefinition.ts +0 -18
- package/src/Handler/RouteDefinition/addRouteDefinitions.ts +0 -9
- package/src/Handler/RouteDefinition/index.ts +0 -2
- package/src/Handler/StatusCodeHandlers/index.ts +0 -1
- package/src/Handler/StatusCodeHandlers/notImplemented.ts +0 -6
- package/src/Handler/asyncHandler.ts +0 -21
- package/src/Handler/errorToJsonHandler.ts +0 -16
- package/src/Handler/index.ts +0 -4
- package/src/HttpUtil/getHttpHeader.ts +0 -27
- package/src/HttpUtil/index.ts +0 -1
- package/src/Logger/LogFormats/LocalDev/index.ts +0 -1
- package/src/Logger/LogFormats/LocalDev/logFormatLocalDev.ts +0 -11
- package/src/Logger/LogFormats/Rollbar/index.ts +0 -1
- package/src/Logger/LogFormats/Rollbar/logFormatRollbar.ts +0 -5
- package/src/Logger/LogFormats/Structured/index.ts +0 -1
- package/src/Logger/LogFormats/Structured/logFormatStructured.ts +0 -7
- package/src/Logger/LogFormats/index.ts +0 -3
- package/src/Logger/LoggerMeta.ts +0 -1
- package/src/Logger/LoggerOptions.ts +0 -7
- package/src/Logger/LoggerVerbosity.ts +0 -1
- package/src/Logger/Transports/Rollbar/RollbarTransport.ts +0 -24
- package/src/Logger/Transports/Rollbar/canGetDefaultRollbarTransport.ts +0 -3
- package/src/Logger/Transports/Rollbar/getDefaultRollbarTransport.ts +0 -10
- package/src/Logger/Transports/Rollbar/index.ts +0 -3
- package/src/Logger/Transports/index.ts +0 -1
- package/src/Logger/WinstonVerbosity.ts +0 -5
- package/src/Logger/WrappedWinstonLogger.ts +0 -20
- package/src/Logger/getDefaultLogger.ts +0 -21
- package/src/Logger/getLogger.ts +0 -55
- package/src/Logger/index.ts +0 -13
- package/src/Logger/toWinstonVerbosity.ts +0 -6
- package/src/Model/ExpressError.ts +0 -3
- package/src/Model/index.ts +0 -1
- package/src/Performance/Counters.ts +0 -36
- package/src/Performance/Profiler.ts +0 -10
- package/src/Performance/index.ts +0 -2
- package/src/Util/compactObject.ts +0 -9
- package/src/Util/index.ts +0 -2
- package/src/Util/tryParse.ts +0 -17
- package/src/Validation/index.ts +0 -1
- package/src/Validation/requestHandlerValidator.ts +0 -120
- package/src/index.ts +0 -8
- package/src/middleware/caseInsensitiveRouting/caseInsensitiveRouting.ts +0 -21
- package/src/middleware/caseInsensitiveRouting/index.ts +0 -1
- package/src/middleware/customPoweredByHeader/customPoweredByHeader.ts +0 -29
- package/src/middleware/customPoweredByHeader/index.ts +0 -1
- package/src/middleware/index.ts +0 -5
- package/src/middleware/jsonBodyParser/index.ts +0 -1
- package/src/middleware/jsonBodyParser/jsonBodyParser.ts +0 -59
- package/src/middleware/metrics/counters.ts +0 -25
- package/src/middleware/metrics/index.ts +0 -2
- package/src/middleware/metrics/responseProfiler.ts +0 -23
- package/src/middleware/standardResponses/getResponseMetadata.ts +0 -18
- package/src/middleware/standardResponses/index.ts +0 -4
- package/src/middleware/standardResponses/jsonApi/README.md +0 -4
- package/src/middleware/standardResponses/jsonApi/error.ts +0 -52
- package/src/middleware/standardResponses/jsonApi/index.ts +0 -5
- package/src/middleware/standardResponses/jsonApi/links.ts +0 -6
- package/src/middleware/standardResponses/jsonApi/relationship.ts +0 -43
- package/src/middleware/standardResponses/jsonApi/resourceIdentifier.ts +0 -15
- package/src/middleware/standardResponses/jsonApi/response.ts +0 -49
- package/src/middleware/standardResponses/standardErrors.ts +0 -27
- 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,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 +0,0 @@
|
|
|
1
|
-
export * from './Rollbar/index.ts'
|
|
@@ -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
|
-
}
|
package/src/Logger/getLogger.ts
DELETED
|
@@ -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
|
-
}
|
package/src/Logger/index.ts
DELETED
|
@@ -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
|
-
}
|
package/src/Model/index.ts
DELETED
|
@@ -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
|
-
}
|
package/src/Performance/index.ts
DELETED
package/src/Util/index.ts
DELETED
package/src/Util/tryParse.ts
DELETED
|
@@ -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
|
-
}
|
package/src/Validation/index.ts
DELETED
|
@@ -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'
|
package/src/middleware/index.ts
DELETED
|
@@ -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,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
|
-
}
|