@naturalcycles/backend-lib 2.73.3 → 3.0.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/dist/admin/admin.mw.d.ts +4 -4
- package/dist/admin/base.admin.service.d.ts +11 -12
- package/dist/db/httpDBRequestHandler.d.ts +2 -2
- package/dist/index.d.ts +25 -24
- package/dist/index.js +28 -50
- package/dist/sentry/sentry.shared.service.d.ts +3 -3
- package/dist/server/appEngineLogMiddleware.d.ts +13 -0
- package/dist/server/{handlers/createGaeLogMiddleware.js → appEngineLogMiddleware.js} +4 -4
- package/dist/server/{handlers/asyncLocalStorage.mw.d.ts → asyncLocalStorageMiddleware.d.ts} +4 -4
- package/dist/server/{handlers/asyncLocalStorage.mw.js → asyncLocalStorageMiddleware.js} +5 -5
- package/dist/server/{handlers/bodyParserTimeout.mw.d.ts → bodyParserTimeoutMiddleware.d.ts} +4 -4
- package/dist/server/{handlers/bodyParserTimeout.mw.js → bodyParserTimeoutMiddleware.js} +10 -7
- package/dist/server/catchWrapper.d.ts +2 -2
- package/dist/server/createDefaultApp.d.ts +2 -2
- package/dist/server/createDefaultApp.js +13 -13
- package/dist/server/createDefaultApp.model.d.ts +8 -8
- package/dist/server/deployInfo.util.d.ts +1 -1
- package/dist/server/genericErrorMiddleware.d.ts +12 -0
- package/dist/server/{handlers/genericErrorHandler.mw.js → genericErrorMiddleware.js} +14 -7
- package/dist/server/getDefaultRouter.d.ts +2 -2
- package/dist/server/methodOverrideMiddleware.d.ts +8 -0
- package/dist/server/{handlers/methodOverride.mw.js → methodOverrideMiddleware.js} +3 -3
- package/dist/server/notFoundMiddleware.d.ts +2 -0
- package/dist/server/notFoundMiddleware.js +10 -0
- package/dist/server/okMiddleware.d.ts +2 -0
- package/dist/server/{handlers/okHandler.mw.js → okMiddleware.js} +3 -3
- package/dist/server/{handlers/reqValidation.mw.d.ts → reqValidationMiddleware.d.ts} +2 -2
- package/dist/server/{handlers/reqValidation.mw.js → reqValidationMiddleware.js} +0 -0
- package/dist/server/request.log.util.d.ts +2 -2
- package/dist/server/request.util.d.ts +10 -2
- package/dist/server/request.util.js +8 -0
- package/dist/server/requestTimeoutMiddleware.d.ts +31 -0
- package/dist/server/requestTimeoutMiddleware.js +68 -0
- package/dist/server/{handlers/safeJsonMiddleware.d.ts → safeJsonMiddleware.d.ts} +2 -2
- package/dist/server/{handlers/safeJsonMiddleware.js → safeJsonMiddleware.js} +0 -0
- package/dist/server/server.model.d.ts +37 -0
- package/dist/server/server.model.js +2 -0
- package/dist/server/serverStatsMiddleware.d.ts +13 -0
- package/dist/server/{handlers/serverStatsMiddleware.js → serverStatsMiddleware.js} +2 -2
- package/dist/server/serverStatusMiddleware.d.ts +3 -0
- package/dist/server/{handlers/statusHandler.js → serverStatusMiddleware.js} +7 -7
- package/dist/server/simpleRequestLoggerMiddleware.d.ts +12 -0
- package/dist/server/{handlers/simpleRequestLogger.mw.js → simpleRequestLoggerMiddleware.js} +5 -5
- package/dist/server/startServer.model.d.ts +2 -2
- package/dist/server/{handlers/validate.mw.d.ts → validateMiddleware.d.ts} +5 -5
- package/dist/server/{handlers/validate.mw.js → validateMiddleware.js} +0 -0
- package/dist/testing/express.test.service.d.ts +5 -5
- package/package.json +1 -1
- package/src/admin/admin.mw.ts +7 -4
- package/src/admin/base.admin.service.ts +11 -12
- package/src/admin/secureHeader.mw.ts +2 -2
- package/src/db/httpDBRequestHandler.ts +2 -3
- package/src/index.ts +54 -68
- package/src/sentry/sentry.shared.service.ts +3 -4
- package/src/server/{handlers/createGaeLogMiddleware.ts → appEngineLogMiddleware.ts} +4 -25
- package/src/server/{handlers/asyncLocalStorage.mw.ts → asyncLocalStorageMiddleware.ts} +5 -5
- package/src/server/{handlers/bodyParserTimeout.mw.ts → bodyParserTimeoutMiddleware.ts} +14 -13
- package/src/server/catchWrapper.ts +2 -2
- package/src/server/createDefaultApp.model.ts +8 -8
- package/src/server/createDefaultApp.ts +22 -19
- package/src/server/deployInfo.util.ts +1 -1
- package/src/server/{handlers/genericErrorHandler.mw.ts → genericErrorMiddleware.ts} +19 -13
- package/src/server/getDefaultRouter.ts +2 -2
- package/src/server/{handlers/methodOverride.mw.ts → methodOverrideMiddleware.ts} +5 -3
- package/src/server/notFoundMiddleware.ts +8 -0
- package/src/server/okMiddleware.ts +7 -0
- package/src/server/{handlers/reqValidation.mw.ts → reqValidationMiddleware.ts} +2 -2
- package/src/server/request.log.util.ts +2 -2
- package/src/server/request.util.ts +10 -2
- package/src/server/requestTimeoutMiddleware.ts +117 -0
- package/src/server/{handlers/safeJsonMiddleware.ts → safeJsonMiddleware.ts} +3 -3
- package/src/server/server.model.ts +56 -0
- package/src/server/{handlers/serverStatsMiddleware.ts → serverStatsMiddleware.ts} +4 -5
- package/src/server/{handlers/statusHandler.ts → serverStatusMiddleware.ts} +5 -5
- package/src/server/{handlers/simpleRequestLogger.mw.ts → simpleRequestLoggerMiddleware.ts} +8 -7
- package/src/server/startServer.model.ts +2 -2
- package/src/server/{handlers/validate.mw.ts → validateMiddleware.ts} +6 -6
- package/src/testing/express.test.service.ts +6 -7
- package/dist/server/handlers/createGaeLogMiddleware.d.ts +0 -30
- package/dist/server/handlers/genericErrorHandler.mw.d.ts +0 -13
- package/dist/server/handlers/methodOverride.mw.d.ts +0 -8
- package/dist/server/handlers/notFoundHandler.mw.d.ts +0 -2
- package/dist/server/handlers/notFoundHandler.mw.js +0 -9
- package/dist/server/handlers/okHandler.mw.d.ts +0 -2
- package/dist/server/handlers/requestTimeout.mw.d.ts +0 -16
- package/dist/server/handlers/requestTimeout.mw.js +0 -34
- package/dist/server/handlers/sentryErrorHandler.mw.d.ts +0 -10
- package/dist/server/handlers/sentryErrorHandler.mw.js +0 -26
- package/dist/server/handlers/serverStatsMiddleware.d.ts +0 -13
- package/dist/server/handlers/simpleRequestLogger.mw.d.ts +0 -12
- package/dist/server/handlers/statusHandler.d.ts +0 -3
- package/src/server/handlers/notFoundHandler.mw.ts +0 -7
- package/src/server/handlers/okHandler.mw.ts +0 -7
- package/src/server/handlers/requestTimeout.mw.ts +0 -62
- package/src/server/handlers/sentryErrorHandler.mw.ts +0 -34
package/src/index.ts
CHANGED
|
@@ -10,57 +10,60 @@ import { FirebaseSharedService } from './admin/firebase.shared.service'
|
|
|
10
10
|
import { createSecureHeaderMiddleware, SecureHeaderMiddlewareCfg } from './admin/secureHeader.mw'
|
|
11
11
|
import { BaseEnv } from './env/env.model'
|
|
12
12
|
import { EnvSharedService, EnvSharedServiceCfg } from './env/env.shared.service'
|
|
13
|
-
|
|
13
|
+
export * from './gae/appEngine.util'
|
|
14
14
|
import { SentrySharedService, SentrySharedServiceCfg } from './sentry/sentry.shared.service'
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
export * from './server/catchWrapper'
|
|
16
|
+
export * from './server/createDefaultApp'
|
|
17
17
|
import {
|
|
18
18
|
DefaultAppCfg,
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
BackendRequestHandlerCfg,
|
|
20
|
+
BackendRequestHandlerWithPath,
|
|
21
21
|
} from './server/createDefaultApp.model'
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
export * from './server/deployInfo.util'
|
|
23
|
+
export * from './server/getDefaultRouter'
|
|
24
24
|
import {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
bodyParserTimeoutMiddleware,
|
|
26
|
+
BodyParserTimeoutMiddlewareCfg,
|
|
27
27
|
clearBodyParserTimeout,
|
|
28
|
-
} from './server/
|
|
29
|
-
|
|
28
|
+
} from './server/bodyParserTimeoutMiddleware'
|
|
29
|
+
export * from './server/genericErrorMiddleware'
|
|
30
|
+
export * from './server/serverStatsMiddleware'
|
|
30
31
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
} from './server/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
import { reqValidation, ReqValidationOptions } from './server/
|
|
32
|
+
methodOverrideMiddleware,
|
|
33
|
+
MethodOverrideMiddlewareCfg,
|
|
34
|
+
} from './server/methodOverrideMiddleware'
|
|
35
|
+
export * from './server/notFoundMiddleware'
|
|
36
|
+
export * from './server/okMiddleware'
|
|
37
|
+
import { RequestTimeoutMiddlewareCfg } from './server/requestTimeoutMiddleware'
|
|
38
|
+
export * from './server/requestTimeoutMiddleware'
|
|
39
|
+
import { reqValidation, ReqValidationOptions } from './server/reqValidationMiddleware'
|
|
39
40
|
import {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
} from './server/
|
|
43
|
-
import {
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
simpleRequestLoggerMiddleware,
|
|
42
|
+
SimpleRequestLoggerMiddlewareCfg,
|
|
43
|
+
} from './server/simpleRequestLoggerMiddleware'
|
|
44
|
+
import { serverStatusMiddleware, getServerStatusData } from './server/serverStatusMiddleware'
|
|
45
|
+
export * from './server/validateMiddleware'
|
|
46
|
+
export * from './server/request.log.util'
|
|
46
47
|
import { BackendServer, startServer } from './server/startServer'
|
|
47
48
|
import { StartServerCfg, StartServerData } from './server/startServer.model'
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
export * from './server/asyncLocalStorageMiddleware'
|
|
50
|
+
import type {
|
|
51
|
+
BackendRequest,
|
|
52
|
+
BackendRequestHandler,
|
|
53
|
+
BackendResponse,
|
|
54
|
+
BackendErrorRequestHandler,
|
|
55
|
+
BackendRouter,
|
|
56
|
+
BackendApplication,
|
|
57
|
+
} from './server/server.model'
|
|
58
|
+
export * from './server/appEngineLogMiddleware'
|
|
59
|
+
export * from './server/safeJsonMiddleware'
|
|
57
60
|
export * from './server/request.util'
|
|
58
61
|
|
|
59
62
|
export type {
|
|
60
|
-
|
|
63
|
+
MethodOverrideMiddlewareCfg,
|
|
61
64
|
SentrySharedServiceCfg,
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
BackendRequestHandlerWithPath,
|
|
66
|
+
BackendRequestHandlerCfg,
|
|
64
67
|
DefaultAppCfg,
|
|
65
68
|
StartServerCfg,
|
|
66
69
|
StartServerData,
|
|
@@ -71,11 +74,16 @@ export type {
|
|
|
71
74
|
AdminInfo,
|
|
72
75
|
RequireAdminCfg,
|
|
73
76
|
SecureHeaderMiddlewareCfg,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
BodyParserTimeoutMiddlewareCfg,
|
|
78
|
+
RequestTimeoutMiddlewareCfg,
|
|
79
|
+
SimpleRequestLoggerMiddlewareCfg,
|
|
77
80
|
ReqValidationOptions,
|
|
78
|
-
|
|
81
|
+
BackendRequest,
|
|
82
|
+
BackendRequestHandler,
|
|
83
|
+
BackendResponse,
|
|
84
|
+
BackendErrorRequestHandler,
|
|
85
|
+
BackendRouter,
|
|
86
|
+
BackendApplication,
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
export {
|
|
@@ -83,39 +91,17 @@ export {
|
|
|
83
91
|
SentrySharedService,
|
|
84
92
|
EnvSharedService,
|
|
85
93
|
reqValidation,
|
|
86
|
-
|
|
87
|
-
genericErrorHandler,
|
|
88
|
-
methodOverride,
|
|
89
|
-
createDefaultApp,
|
|
94
|
+
methodOverrideMiddleware,
|
|
90
95
|
startServer,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
isGAE,
|
|
94
|
-
statusHandler,
|
|
95
|
-
statusHandlerData,
|
|
96
|
-
okHandler,
|
|
97
|
-
getDeployInfo,
|
|
96
|
+
serverStatusMiddleware,
|
|
97
|
+
getServerStatusData,
|
|
98
98
|
onFinished,
|
|
99
|
-
respondWithError,
|
|
100
|
-
logRequest,
|
|
101
99
|
FirebaseSharedService,
|
|
102
100
|
createAdminMiddleware,
|
|
103
101
|
BaseAdminService,
|
|
104
102
|
loginHtml,
|
|
105
103
|
createSecureHeaderMiddleware,
|
|
106
|
-
|
|
104
|
+
bodyParserTimeoutMiddleware,
|
|
107
105
|
clearBodyParserTimeout,
|
|
108
|
-
|
|
109
|
-
simpleRequestLogger,
|
|
110
|
-
coloredHttpCode,
|
|
111
|
-
validateBody,
|
|
112
|
-
validateParams,
|
|
113
|
-
validateQuery,
|
|
114
|
-
createAsyncLocalStorage,
|
|
115
|
-
getRequest,
|
|
116
|
-
getRequestLogger,
|
|
117
|
-
requestLogger,
|
|
118
|
-
serverStatsHTMLHandler,
|
|
119
|
-
serverStatsMiddleware,
|
|
120
|
-
safeJsonMiddleware,
|
|
106
|
+
simpleRequestLoggerMiddleware,
|
|
121
107
|
}
|
|
@@ -3,8 +3,7 @@ import { inspectAny, inspectAnyStringifyFn } from '@naturalcycles/nodejs-lib'
|
|
|
3
3
|
import { Severity } from '@sentry/node'
|
|
4
4
|
import type { Breadcrumb, NodeOptions } from '@sentry/node'
|
|
5
5
|
import type * as SentryLib from '@sentry/node'
|
|
6
|
-
import {
|
|
7
|
-
import { getRequestLogger } from '../index'
|
|
6
|
+
import { BackendErrorRequestHandler, BackendRequestHandler, getRequestLogger } from '../index'
|
|
8
7
|
|
|
9
8
|
export interface SentrySharedServiceCfg extends NodeOptions {}
|
|
10
9
|
|
|
@@ -51,7 +50,7 @@ export class SentrySharedService {
|
|
|
51
50
|
*
|
|
52
51
|
* UPD: to be tested. Without it - request is not enriched and the error is less useful.
|
|
53
52
|
*/
|
|
54
|
-
getRequestHandler():
|
|
53
|
+
getRequestHandler(): BackendRequestHandler {
|
|
55
54
|
return this.sentry().Handlers.requestHandler()
|
|
56
55
|
}
|
|
57
56
|
|
|
@@ -60,7 +59,7 @@ export class SentrySharedService {
|
|
|
60
59
|
*
|
|
61
60
|
* @deprecated
|
|
62
61
|
*/
|
|
63
|
-
getErrorHandler():
|
|
62
|
+
getErrorHandler(): BackendErrorRequestHandler {
|
|
64
63
|
return this.sentry().Handlers.errorHandler()
|
|
65
64
|
}
|
|
66
65
|
|
|
@@ -1,29 +1,8 @@
|
|
|
1
1
|
import { inspect } from 'util'
|
|
2
2
|
import { dimGrey } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
3
3
|
import { inspectAny } from '@naturalcycles/nodejs-lib'
|
|
4
|
-
import { AnyObject,
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Use this interface instead of express.Request in cases when TypeScript gives an error, because it haven't "included" this very file
|
|
9
|
-
*/
|
|
10
|
-
export interface RequestWithLog extends Request {
|
|
11
|
-
log: CommonLogFunction
|
|
12
|
-
warn: CommonLogFunction
|
|
13
|
-
error: CommonLogFunction
|
|
14
|
-
|
|
15
|
-
requestId?: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
declare module 'http' {
|
|
19
|
-
interface IncomingMessage {
|
|
20
|
-
log: CommonLogFunction
|
|
21
|
-
warn: CommonLogFunction
|
|
22
|
-
error: CommonLogFunction
|
|
23
|
-
|
|
24
|
-
requestId?: string
|
|
25
|
-
}
|
|
26
|
-
}
|
|
4
|
+
import { AnyObject, CommonLogger } from '@naturalcycles/js-lib'
|
|
5
|
+
import { BackendRequestHandler } from './server.model'
|
|
27
6
|
|
|
28
7
|
const { GOOGLE_CLOUD_PROJECT, GAE_INSTANCE } = process.env
|
|
29
8
|
const isGAE = !!GAE_INSTANCE
|
|
@@ -71,7 +50,7 @@ function logToDev(requestId: string | null, args: any[]): void {
|
|
|
71
50
|
)
|
|
72
51
|
}
|
|
73
52
|
|
|
74
|
-
export function
|
|
53
|
+
export function appEngineLogMiddleware(): BackendRequestHandler {
|
|
75
54
|
if (!isGAE || !GOOGLE_CLOUD_PROJECT) {
|
|
76
55
|
// Local machine, return "simple" logToDev middleware with request numbering
|
|
77
56
|
return function gaeLogMiddlewareDev(req, res, next) {
|
|
@@ -84,7 +63,7 @@ export function createGAELogMiddleware(): RequestHandler {
|
|
|
84
63
|
|
|
85
64
|
// Otherwise, we're in AppEngine
|
|
86
65
|
|
|
87
|
-
return function
|
|
66
|
+
return function appEngineLogHandler(req, res, next) {
|
|
88
67
|
const traceHeader = req.header('x-cloud-trace-context')
|
|
89
68
|
if (traceHeader) {
|
|
90
69
|
const [trace] = traceHeader.split('/')
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'async_hooks'
|
|
2
2
|
import { _lazyValue, CommonLogger } from '@naturalcycles/js-lib'
|
|
3
|
-
import {
|
|
4
|
-
import { gaeLogger, devLogger } from './
|
|
3
|
+
import { BackendRequest, BackendRequestHandler } from './server.model'
|
|
4
|
+
import { gaeLogger, devLogger } from './appEngineLogMiddleware'
|
|
5
5
|
|
|
6
6
|
const { GAE_INSTANCE } = process.env
|
|
7
7
|
const isGAE = !!GAE_INSTANCE
|
|
8
8
|
|
|
9
9
|
export interface RequestLocalStorage {
|
|
10
|
-
req:
|
|
10
|
+
req: BackendRequest
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// Singleton, for simplicity
|
|
14
14
|
// Create it lazily (on demand)
|
|
15
15
|
const storage = _lazyValue(() => new AsyncLocalStorage<RequestLocalStorage>())
|
|
16
16
|
|
|
17
|
-
export function
|
|
17
|
+
export function asyncLocalStorageMiddleware(): BackendRequestHandler {
|
|
18
18
|
return (req, res, next) => {
|
|
19
19
|
const store: RequestLocalStorage = {
|
|
20
20
|
req,
|
|
@@ -24,7 +24,7 @@ export function createAsyncLocalStorage(): RequestHandler {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function getRequest():
|
|
27
|
+
export function getRequest(): BackendRequest | undefined {
|
|
28
28
|
return storage().getStore()?.req
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { HttpError } from '@naturalcycles/js-lib'
|
|
2
|
-
import {
|
|
3
|
-
import { respondWithError } from '../../index'
|
|
2
|
+
import { BackendRequestHandler, respondWithError } from '../index'
|
|
4
3
|
|
|
5
|
-
export interface
|
|
4
|
+
export interface BodyParserTimeoutMiddlewareCfg {
|
|
6
5
|
/**
|
|
7
6
|
* @default 10
|
|
8
7
|
*/
|
|
@@ -19,16 +18,14 @@ export interface BodyParserTimeoutCfg {
|
|
|
19
18
|
httpStatus?: string
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
interface RequestWithTimeout extends Request {
|
|
23
|
-
_bodyParserTimeout?: NodeJS.Timeout
|
|
24
|
-
}
|
|
25
|
-
|
|
26
21
|
const code = 'BODY_PARSER_TIMEOUT'
|
|
27
22
|
|
|
28
23
|
/**
|
|
29
24
|
* Should be called BEFORE bodyParser
|
|
30
25
|
*/
|
|
31
|
-
export function
|
|
26
|
+
export function bodyParserTimeoutMiddleware(
|
|
27
|
+
cfg: BodyParserTimeoutMiddlewareCfg = {},
|
|
28
|
+
): BackendRequestHandler {
|
|
32
29
|
const { timeoutSeconds, httpStatusCode, httpStatus } = {
|
|
33
30
|
timeoutSeconds: 10,
|
|
34
31
|
httpStatusCode: 400,
|
|
@@ -38,8 +35,12 @@ export function bodyParserTimeout(cfg: BodyParserTimeoutCfg = {}): RequestHandle
|
|
|
38
35
|
|
|
39
36
|
const timeout = timeoutSeconds * 1000
|
|
40
37
|
|
|
41
|
-
return (req
|
|
42
|
-
|
|
38
|
+
return (req, res, next) => {
|
|
39
|
+
// If requestTimeout was previously set - cancel it first
|
|
40
|
+
// Then set the new requestTimeout and handler
|
|
41
|
+
if (req.bodyParserTimeout) clearTimeout(req.bodyParserTimeout)
|
|
42
|
+
|
|
43
|
+
req.bodyParserTimeout = setTimeout(() => {
|
|
43
44
|
respondWithError(
|
|
44
45
|
req,
|
|
45
46
|
res,
|
|
@@ -58,9 +59,9 @@ export function bodyParserTimeout(cfg: BodyParserTimeoutCfg = {}): RequestHandle
|
|
|
58
59
|
/**
|
|
59
60
|
* Should be called AFTER bodyParser
|
|
60
61
|
*/
|
|
61
|
-
export function clearBodyParserTimeout():
|
|
62
|
-
return (req
|
|
63
|
-
|
|
62
|
+
export function clearBodyParserTimeout(): BackendRequestHandler {
|
|
63
|
+
return (req, res, next) => {
|
|
64
|
+
clearTimeout(req.bodyParserTimeout!)
|
|
64
65
|
next()
|
|
65
66
|
}
|
|
66
67
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendRequestHandler } from './server.model'
|
|
2
2
|
|
|
3
3
|
// https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/
|
|
4
4
|
// https://stackoverflow.com/a/43564267/4919972
|
|
5
5
|
export const catchWrapper =
|
|
6
|
-
(fn:
|
|
6
|
+
(fn: BackendRequestHandler): BackendRequestHandler =>
|
|
7
7
|
async (req, res, next) => {
|
|
8
8
|
try {
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { RequestHandler } from 'express'
|
|
2
1
|
import { SentrySharedService } from '../sentry/sentry.shared.service'
|
|
2
|
+
import { BackendRequestHandler } from './server.model'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Plain RequestHandler can be provided - then it's mounted to /
|
|
6
6
|
* Otherwise `path` can be provided to specify mounting point.
|
|
7
7
|
*/
|
|
8
|
-
export type
|
|
8
|
+
export type BackendRequestHandlerCfg = BackendRequestHandler | BackendRequestHandlerWithPath
|
|
9
9
|
|
|
10
|
-
export interface
|
|
10
|
+
export interface BackendRequestHandlerWithPath {
|
|
11
11
|
path: string
|
|
12
|
-
handler:
|
|
12
|
+
handler: BackendRequestHandler
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -21,9 +21,9 @@ export interface RequestHandlerWithPath {
|
|
|
21
21
|
* 4. postHandlers
|
|
22
22
|
*/
|
|
23
23
|
export interface DefaultAppCfg {
|
|
24
|
-
preHandlers?:
|
|
25
|
-
handlers?:
|
|
26
|
-
resources?:
|
|
27
|
-
postHandlers?:
|
|
24
|
+
preHandlers?: BackendRequestHandlerCfg[]
|
|
25
|
+
handlers?: BackendRequestHandlerCfg[]
|
|
26
|
+
resources?: BackendRequestHandlerCfg[]
|
|
27
|
+
postHandlers?: BackendRequestHandlerCfg[]
|
|
28
28
|
sentryService?: SentrySharedService
|
|
29
29
|
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import cookieParser = require('cookie-parser')
|
|
2
2
|
import cors = require('cors')
|
|
3
|
-
import type { Application } from 'express'
|
|
4
3
|
import express = require('express')
|
|
5
|
-
import { isGAE,
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
4
|
+
import { BackendApplication, isGAE, methodOverrideMiddleware } from '..'
|
|
5
|
+
import {
|
|
6
|
+
DefaultAppCfg,
|
|
7
|
+
BackendRequestHandlerCfg,
|
|
8
|
+
BackendRequestHandlerWithPath,
|
|
9
|
+
} from './createDefaultApp.model'
|
|
10
|
+
import { asyncLocalStorageMiddleware } from './asyncLocalStorageMiddleware'
|
|
11
|
+
import { appEngineLogMiddleware } from './appEngineLogMiddleware'
|
|
12
|
+
import { genericErrorMiddleware } from './genericErrorMiddleware'
|
|
13
|
+
import { notFoundMiddleware } from './notFoundMiddleware'
|
|
14
|
+
import { requestTimeoutMiddleware } from './requestTimeoutMiddleware'
|
|
15
|
+
import { simpleRequestLoggerMiddleware } from './simpleRequestLoggerMiddleware'
|
|
13
16
|
|
|
14
17
|
const isTest = process.env['APP_ENV'] === 'test'
|
|
15
18
|
|
|
16
|
-
export function createDefaultApp(cfg: DefaultAppCfg):
|
|
19
|
+
export function createDefaultApp(cfg: DefaultAppCfg): BackendApplication {
|
|
17
20
|
const { sentryService } = cfg
|
|
18
21
|
|
|
19
22
|
const app = express()
|
|
@@ -25,10 +28,10 @@ export function createDefaultApp(cfg: DefaultAppCfg): Application {
|
|
|
25
28
|
// preHandlers
|
|
26
29
|
useHandlers(app, cfg.preHandlers)
|
|
27
30
|
|
|
28
|
-
app.use(
|
|
31
|
+
app.use(appEngineLogMiddleware())
|
|
29
32
|
|
|
30
33
|
if (!isTest) {
|
|
31
|
-
app.use(
|
|
34
|
+
app.use(asyncLocalStorageMiddleware())
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
// The request handler must be the first middleware on the app
|
|
@@ -38,13 +41,13 @@ export function createDefaultApp(cfg: DefaultAppCfg): Application {
|
|
|
38
41
|
app.use(sentryService.getRequestHandler())
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
app.use(
|
|
42
|
-
app.use(
|
|
44
|
+
app.use(methodOverrideMiddleware())
|
|
45
|
+
app.use(requestTimeoutMiddleware())
|
|
43
46
|
// app.use(serverStatsMiddleware()) // disabled by default
|
|
44
47
|
// app.use(bodyParserTimeout()) // removed by default
|
|
45
48
|
|
|
46
49
|
if (!isGAE() && !isTest) {
|
|
47
|
-
app.use(
|
|
50
|
+
app.use(simpleRequestLoggerMiddleware())
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
// app.use(safeJsonMiddleware()) // optional
|
|
@@ -86,19 +89,19 @@ export function createDefaultApp(cfg: DefaultAppCfg): Application {
|
|
|
86
89
|
useHandlers(app, cfg.postHandlers)
|
|
87
90
|
|
|
88
91
|
// Generic 404 handler
|
|
89
|
-
app.use(
|
|
92
|
+
app.use(notFoundMiddleware())
|
|
90
93
|
|
|
91
94
|
// Generic error handler
|
|
92
95
|
// It handles errors, returns proper status, does sentry.captureException(),
|
|
93
96
|
// assigns err.data.errorId from sentry
|
|
94
|
-
app.use(
|
|
97
|
+
app.use(genericErrorMiddleware({ sentryService }))
|
|
95
98
|
|
|
96
99
|
return app
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
function useHandlers(app:
|
|
102
|
+
function useHandlers(app: BackendApplication, handlers: BackendRequestHandlerCfg[] = []): void {
|
|
100
103
|
handlers
|
|
101
|
-
.map<
|
|
104
|
+
.map<BackendRequestHandlerWithPath>(cfg => {
|
|
102
105
|
if (typeof cfg === 'function') {
|
|
103
106
|
return {
|
|
104
107
|
path: '/',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs'
|
|
2
2
|
import { _memoFn } from '@naturalcycles/js-lib'
|
|
3
|
-
import type { DeployInfo } from '../deploy
|
|
3
|
+
import type { DeployInfo } from '../deploy'
|
|
4
4
|
|
|
5
5
|
export const getDeployInfo = _memoFn((projectDir: string): DeployInfo => {
|
|
6
6
|
const deployInfoPath = `${projectDir}/deployInfo.json`
|
|
@@ -7,11 +7,10 @@ import {
|
|
|
7
7
|
HttpErrorResponse,
|
|
8
8
|
} from '@naturalcycles/js-lib'
|
|
9
9
|
import { inspectAnyStringifyFn } from '@naturalcycles/nodejs-lib'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { RequestWithLog } from './createGaeLogMiddleware'
|
|
10
|
+
import { SentrySharedService } from '../sentry/sentry.shared.service'
|
|
11
|
+
import { BackendErrorRequestHandler, BackendRequest, BackendResponse } from './server.model'
|
|
13
12
|
|
|
14
|
-
export interface
|
|
13
|
+
export interface GenericErrorMiddlewareCfg {
|
|
15
14
|
sentryService?: SentrySharedService
|
|
16
15
|
}
|
|
17
16
|
|
|
@@ -26,10 +25,12 @@ let sentryService: SentrySharedService | undefined
|
|
|
26
25
|
* Returns HTTP code based on err.data.httpStatusCode (default to 500).
|
|
27
26
|
* Sends json payload as ErrorResponse, transformed via errorSharedUtil.
|
|
28
27
|
*/
|
|
29
|
-
export function
|
|
28
|
+
export function genericErrorMiddleware(
|
|
29
|
+
cfg: GenericErrorMiddlewareCfg = {},
|
|
30
|
+
): BackendErrorRequestHandler {
|
|
30
31
|
sentryService ||= cfg.sentryService
|
|
31
32
|
|
|
32
|
-
return (err, req
|
|
33
|
+
return (err, req, res, _next) => {
|
|
33
34
|
// if (res.headersSent) {
|
|
34
35
|
// Here we don't even log this error
|
|
35
36
|
// It's known that it comes from sentry.requestHandler()
|
|
@@ -49,7 +50,7 @@ export function genericErrorHandler(cfg: GenericErrorHandlerCfg = {}): ErrorRequ
|
|
|
49
50
|
// export interface ResponseWithError extends Response {
|
|
50
51
|
// __err?: any
|
|
51
52
|
// }
|
|
52
|
-
export function respondWithError(req:
|
|
53
|
+
export function respondWithError(req: BackendRequest, res: BackendResponse, err: any): void {
|
|
53
54
|
const { headersSent } = res
|
|
54
55
|
|
|
55
56
|
req.error(`genericErrorHandler${headersSent ? ' after headersSent' : ''}:\n`, err)
|
|
@@ -80,10 +81,15 @@ export function respondWithError(req: RequestWithLog, res: Response, err: any):
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
function shouldReportToSentry(err: Error): boolean {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
const e = err as HttpError
|
|
85
|
+
|
|
86
|
+
// By default - report
|
|
87
|
+
if (!e?.data) return true
|
|
88
|
+
|
|
89
|
+
// If `report` is set - do as it says
|
|
90
|
+
if (e.data.report === true) return true
|
|
91
|
+
if (e.data.report === false) return false
|
|
92
|
+
|
|
93
|
+
// Report if http 5xx, otherwise not
|
|
94
|
+
return !e.data.httpStatusCode || e.data.httpStatusCode >= 500
|
|
89
95
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { RequestHandler, Router } from 'express'
|
|
2
1
|
import PromiseRouter from 'express-promise-router'
|
|
2
|
+
import { BackendRequestHandler, BackendRouter } from './server.model'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Convenience method.
|
|
6
6
|
*/
|
|
7
|
-
export function getDefaultRouter(defaultHandlers:
|
|
7
|
+
export function getDefaultRouter(defaultHandlers: BackendRequestHandler[] = []): BackendRouter {
|
|
8
8
|
const router = PromiseRouter()
|
|
9
9
|
|
|
10
10
|
// Use default handlers
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendRequestHandler } from './server.model'
|
|
2
2
|
|
|
3
|
-
export interface
|
|
3
|
+
export interface MethodOverrideMiddlewareCfg {
|
|
4
4
|
/**
|
|
5
5
|
* @default _method
|
|
6
6
|
*/
|
|
7
7
|
methodKey?: string
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export function
|
|
10
|
+
export function methodOverrideMiddleware(
|
|
11
|
+
cfg: MethodOverrideMiddlewareCfg = {},
|
|
12
|
+
): BackendRequestHandler {
|
|
11
13
|
const { methodKey } = {
|
|
12
14
|
methodKey: '_method',
|
|
13
15
|
...cfg,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { getRequestEndpoint } from './request.util'
|
|
2
|
+
import { BackendRequestHandler } from './server.model'
|
|
3
|
+
|
|
4
|
+
export function notFoundMiddleware(): BackendRequestHandler {
|
|
5
|
+
return (req, res) => {
|
|
6
|
+
res.status(404).send(`404 Not Found: ${getRequestEndpoint(req)}`)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HttpError, _get } from '@naturalcycles/js-lib'
|
|
2
2
|
import { AnySchema, getValidationResult, JoiValidationError } from '@naturalcycles/nodejs-lib'
|
|
3
|
-
import {
|
|
3
|
+
import { BackendRequestHandler } from './server.model'
|
|
4
4
|
|
|
5
5
|
const REDACTED = 'REDACTED'
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ export function reqValidation(
|
|
|
22
22
|
reqProperty: 'body' | 'params' | 'query',
|
|
23
23
|
schema: AnySchema,
|
|
24
24
|
opt: ReqValidationOptions<JoiValidationError> = {},
|
|
25
|
-
):
|
|
25
|
+
): BackendRequestHandler {
|
|
26
26
|
const reportPredicate = typeof opt.report === 'function' ? opt.report : () => !!opt.report
|
|
27
27
|
|
|
28
28
|
return (req, res, next) => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CommonLogLevel } from '@naturalcycles/js-lib'
|
|
2
2
|
import { boldGrey, green, red, yellow } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
3
|
-
import {
|
|
3
|
+
import { BackendRequest } from './server.model'
|
|
4
4
|
|
|
5
|
-
export function logRequest(req:
|
|
5
|
+
export function logRequest(req: BackendRequest, statusCode: number, ...tokens: any[]): void {
|
|
6
6
|
req[logLevel(statusCode)](
|
|
7
7
|
[coloredHttpCode(statusCode), req.method, boldGrey(req.url), ...tokens].join(' '),
|
|
8
8
|
)
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendRequest } from './server.model'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Returns e.g:
|
|
5
|
+
*
|
|
6
|
+
* GET /some/endpoint
|
|
7
|
+
*
|
|
8
|
+
* Gets the correct full path when used from sub-router-resources.
|
|
9
|
+
* Strips away the queryString.
|
|
10
|
+
*/
|
|
11
|
+
export function getRequestEndpoint(req: BackendRequest): string {
|
|
4
12
|
let path = (req.baseUrl + (req.route?.path || req.path)).toLowerCase()
|
|
5
13
|
if (path.length > 1 && path.endsWith('/')) {
|
|
6
14
|
path = path.slice(0, path.length - 1)
|