@naturalcycles/backend-lib 5.1.0 → 5.2.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/index.d.ts CHANGED
@@ -20,11 +20,11 @@ export * from './server/notFoundMiddleware';
20
20
  export * from './server/okMiddleware';
21
21
  export * from './server/basicAuthMiddleware';
22
22
  export * from './server/requestTimeoutMiddleware';
23
- export * from './server/reqValidationMiddleware';
23
+ export * from './server/validation/reqValidationMiddleware';
24
24
  export * from './server/simpleRequestLoggerMiddleware';
25
25
  export * from './server/serverStatusMiddleware';
26
- export * from './server/validateMiddleware';
27
- export * from './server/zodValidateMiddleware';
26
+ export * from './server/validation/validateMiddleware';
27
+ export * from './server/validation/zodValidateMiddleware';
28
28
  export * from './server/request.log.util';
29
29
  export * from './server/startServer';
30
30
  export * from './server/startServer.model';
package/dist/index.js CHANGED
@@ -25,11 +25,11 @@ tslib_1.__exportStar(require("./server/notFoundMiddleware"), exports);
25
25
  tslib_1.__exportStar(require("./server/okMiddleware"), exports);
26
26
  tslib_1.__exportStar(require("./server/basicAuthMiddleware"), exports);
27
27
  tslib_1.__exportStar(require("./server/requestTimeoutMiddleware"), exports);
28
- tslib_1.__exportStar(require("./server/reqValidationMiddleware"), exports);
28
+ tslib_1.__exportStar(require("./server/validation/reqValidationMiddleware"), exports);
29
29
  tslib_1.__exportStar(require("./server/simpleRequestLoggerMiddleware"), exports);
30
30
  tslib_1.__exportStar(require("./server/serverStatusMiddleware"), exports);
31
- tslib_1.__exportStar(require("./server/validateMiddleware"), exports);
32
- tslib_1.__exportStar(require("./server/zodValidateMiddleware"), exports);
31
+ tslib_1.__exportStar(require("./server/validation/validateMiddleware"), exports);
32
+ tslib_1.__exportStar(require("./server/validation/zodValidateMiddleware"), exports);
33
33
  tslib_1.__exportStar(require("./server/request.log.util"), exports);
34
34
  tslib_1.__exportStar(require("./server/startServer"), exports);
35
35
  tslib_1.__exportStar(require("./server/startServer.model"), exports);
@@ -57,7 +57,6 @@ function respondWithError(req, res, err) {
57
57
  // Otherwise, it breaks the _isHttpErrorResponse function check, and error get formatted/detected wrongly
58
58
  httpError.data['httpStatusCode'] = httpError.data.backendResponseStatusCode;
59
59
  httpError.data.headersSent = headersSent || undefined;
60
- httpError.data.report ||= undefined; // set to undefined if false
61
60
  (0, js_lib_1._filterUndefinedValues)(httpError.data, true);
62
61
  formatError?.(httpError); // Mutates
63
62
  res.status(httpError.data.backendResponseStatusCode).json({
@@ -1,3 +1,4 @@
1
+ /// <reference types="cookie-parser" />
1
2
  /// <reference types="node" />
2
3
  import type { CommonLogFunction, Promisable } from '@naturalcycles/js-lib';
3
4
  import type { IRouter, Request, NextFunction, Response, Application } from 'express';
@@ -1,5 +1,5 @@
1
1
  import { AnySchema, JoiValidationError } from '@naturalcycles/nodejs-lib';
2
- import { BackendRequestHandler } from './server.model';
2
+ import { BackendRequest, BackendRequestHandler } from '../server.model';
3
3
  export interface ReqValidationOptions<ERR extends Error> {
4
4
  /**
5
5
  * Pass a 'dot-paths' (e.g `pw`, or `input.pw`) that needs to be redacted from the output, in case of error.
@@ -13,3 +13,11 @@ export interface ReqValidationOptions<ERR extends Error> {
13
13
  report?: boolean | ((err: ERR) => boolean);
14
14
  }
15
15
  export declare function reqValidation(reqProperty: 'body' | 'params' | 'query', schema: AnySchema, opt?: ReqValidationOptions<JoiValidationError>): BackendRequestHandler;
16
+ declare class ValidateRequest {
17
+ body<T>(req: BackendRequest, schema: AnySchema<T>, opt?: ReqValidationOptions<JoiValidationError>): T;
18
+ query<T>(req: BackendRequest, schema: AnySchema<T>, opt?: ReqValidationOptions<JoiValidationError>): T;
19
+ params<T>(req: BackendRequest, schema: AnySchema<T>, opt?: ReqValidationOptions<JoiValidationError>): T;
20
+ private validate;
21
+ }
22
+ export declare const validateRequest: ValidateRequest;
23
+ export {};
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateRequest = exports.reqValidation = void 0;
4
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
+ const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
6
+ const REDACTED = 'REDACTED';
7
+ function reqValidation(reqProperty, schema, opt = {}) {
8
+ const reportPredicate = typeof opt.report === 'function' ? opt.report : () => opt.report;
9
+ return (req, res, next) => {
10
+ const { value, error } = (0, nodejs_lib_1.getValidationResult)(req[reqProperty], schema, `request ${reqProperty}`);
11
+ if (error) {
12
+ const report = reportPredicate(error);
13
+ if (opt.redactPaths) {
14
+ redact(opt.redactPaths, req[reqProperty], error);
15
+ error.data.joiValidationErrorItems.length = 0; // clears the array
16
+ delete error.data.annotation;
17
+ }
18
+ return next(new js_lib_1.AppError(error.message, {
19
+ backendResponseStatusCode: 400,
20
+ report,
21
+ ...error.data,
22
+ }));
23
+ }
24
+ // mutate req to replace the property with the value, converted by Joi
25
+ req[reqProperty] = value;
26
+ next();
27
+ };
28
+ }
29
+ exports.reqValidation = reqValidation;
30
+ /**
31
+ * Mutates error
32
+ */
33
+ function redact(redactPaths, obj, error) {
34
+ redactPaths
35
+ .map(path => (0, js_lib_1._get)(obj, path))
36
+ .filter(Boolean)
37
+ .forEach(secret => {
38
+ error.message = error.message.replace(secret, REDACTED);
39
+ });
40
+ }
41
+ class ValidateRequest {
42
+ body(req, schema, opt = {}) {
43
+ return this.validate(req, 'body', schema, opt);
44
+ }
45
+ query(req, schema, opt = {}) {
46
+ return this.validate(req, 'query', schema, opt);
47
+ }
48
+ params(req, schema, opt = {}) {
49
+ return this.validate(req, 'params', schema, opt);
50
+ }
51
+ validate(req, reqProperty, schema, opt = {}) {
52
+ const { value, error } = (0, nodejs_lib_1.getValidationResult)(req[reqProperty], schema, `request ${reqProperty}`);
53
+ if (error) {
54
+ let report;
55
+ if (typeof opt.report === 'boolean') {
56
+ report = opt.report;
57
+ }
58
+ else if (typeof opt.report === 'function') {
59
+ report = opt.report(error);
60
+ }
61
+ if (opt.redactPaths) {
62
+ redact(opt.redactPaths, req[reqProperty], error);
63
+ error.data.joiValidationErrorItems.length = 0; // clears the array
64
+ delete error.data.annotation;
65
+ }
66
+ throw new js_lib_1.AppError(error.message, {
67
+ backendResponseStatusCode: 400,
68
+ report,
69
+ ...error.data,
70
+ });
71
+ }
72
+ // mutate req to replace the property with the value, converted by Joi
73
+ req[reqProperty] = value;
74
+ return value;
75
+ }
76
+ }
77
+ exports.validateRequest = new ValidateRequest();
@@ -1,7 +1,7 @@
1
1
  import { JsonSchema, JsonSchemaBuilder } from '@naturalcycles/js-lib';
2
2
  import { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib';
3
+ import { BackendRequestHandler } from '../server.model';
3
4
  import { ReqValidationOptions } from './reqValidationMiddleware';
4
- import { BackendRequestHandler } from './server.model';
5
5
  export declare function validateBody(schema: JsonSchema | JsonSchemaBuilder | AjvSchema, opt?: ReqValidationOptions<AjvValidationError>): BackendRequestHandler;
6
6
  export declare function validateParams(schema: JsonSchema | JsonSchemaBuilder | AjvSchema, opt?: ReqValidationOptions<AjvValidationError>): BackendRequestHandler;
7
7
  export declare function validateQuery(schema: JsonSchema | JsonSchemaBuilder | AjvSchema, opt?: ReqValidationOptions<AjvValidationError>): BackendRequestHandler;
@@ -26,7 +26,7 @@ function validateObject(prop, schema, opt = {}) {
26
26
  const ajvSchema = nodejs_lib_1.AjvSchema.create(schema, {
27
27
  objectName: `request ${prop}`,
28
28
  });
29
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => !!opt.report;
29
+ const reportPredicate = typeof opt.report === 'function' ? opt.report : () => opt.report;
30
30
  return (req, res, next) => {
31
31
  const error = ajvSchema.getValidationError(req[prop]);
32
32
  if (error) {
@@ -1,6 +1,6 @@
1
1
  import { ZodSchema, ZodValidationError } from '@naturalcycles/js-lib';
2
+ import { BackendRequestHandler } from '../server.model';
2
3
  import { ReqValidationOptions } from './reqValidationMiddleware';
3
- import { BackendRequestHandler } from './server.model';
4
4
  /**
5
5
  * Validates req property (body, params or query).
6
6
  * Supports Joi schema or AjvSchema (from nodejs-lib).
@@ -10,7 +10,7 @@ const REDACTED = 'REDACTED';
10
10
  * Throws http 400 on error.
11
11
  */
12
12
  function zodReqValidate(prop, schema, opt = {}) {
13
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => !!opt.report;
13
+ const reportPredicate = typeof opt.report === 'function' ? opt.report : () => opt.report;
14
14
  return (req, res, next) => {
15
15
  const { error } = (0, js_lib_1.zSafeValidate)(req[prop], schema);
16
16
  if (!error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "dev": "APP_ENV=dev nodemon",
package/src/index.ts CHANGED
@@ -20,11 +20,11 @@ export * from './server/notFoundMiddleware'
20
20
  export * from './server/okMiddleware'
21
21
  export * from './server/basicAuthMiddleware'
22
22
  export * from './server/requestTimeoutMiddleware'
23
- export * from './server/reqValidationMiddleware'
23
+ export * from './server/validation/reqValidationMiddleware'
24
24
  export * from './server/simpleRequestLoggerMiddleware'
25
25
  export * from './server/serverStatusMiddleware'
26
- export * from './server/validateMiddleware'
27
- export * from './server/zodValidateMiddleware'
26
+ export * from './server/validation/validateMiddleware'
27
+ export * from './server/validation/zodValidateMiddleware'
28
28
  export * from './server/request.log.util'
29
29
  export * from './server/startServer'
30
30
  export * from './server/startServer.model'
@@ -90,7 +90,6 @@ export function respondWithError(req: BackendRequest, res: BackendResponse, err:
90
90
  // Otherwise, it breaks the _isHttpErrorResponse function check, and error get formatted/detected wrongly
91
91
  httpError.data['httpStatusCode'] = httpError.data.backendResponseStatusCode
92
92
  httpError.data.headersSent = headersSent || undefined
93
- httpError.data.report ||= undefined // set to undefined if false
94
93
  _filterUndefinedValues(httpError.data, true)
95
94
 
96
95
  formatError?.(httpError) // Mutates
@@ -1,6 +1,6 @@
1
1
  import { _get, AppError } from '@naturalcycles/js-lib'
2
2
  import { AnySchema, getValidationResult, JoiValidationError } from '@naturalcycles/nodejs-lib'
3
- import { BackendRequestHandler } from './server.model'
3
+ import { BackendRequest, BackendRequestHandler } from '../server.model'
4
4
 
5
5
  const REDACTED = 'REDACTED'
6
6
 
@@ -23,7 +23,8 @@ export function reqValidation(
23
23
  schema: AnySchema,
24
24
  opt: ReqValidationOptions<JoiValidationError> = {},
25
25
  ): BackendRequestHandler {
26
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => !!opt.report
26
+ const reportPredicate =
27
+ typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined
27
28
 
28
29
  return (req, res, next) => {
29
30
  const { value, error } = getValidationResult(req[reqProperty], schema, `request ${reqProperty}`)
@@ -62,3 +63,64 @@ function redact(redactPaths: string[], obj: any, error: Error): void {
62
63
  error.message = error.message.replace(secret, REDACTED)
63
64
  })
64
65
  }
66
+
67
+ class ValidateRequest {
68
+ body<T>(
69
+ req: BackendRequest,
70
+ schema: AnySchema<T>,
71
+ opt: ReqValidationOptions<JoiValidationError> = {},
72
+ ): T {
73
+ return this.validate(req, 'body', schema, opt)
74
+ }
75
+
76
+ query<T>(
77
+ req: BackendRequest,
78
+ schema: AnySchema<T>,
79
+ opt: ReqValidationOptions<JoiValidationError> = {},
80
+ ): T {
81
+ return this.validate(req, 'query', schema, opt)
82
+ }
83
+
84
+ params<T>(
85
+ req: BackendRequest,
86
+ schema: AnySchema<T>,
87
+ opt: ReqValidationOptions<JoiValidationError> = {},
88
+ ): T {
89
+ return this.validate(req, 'params', schema, opt)
90
+ }
91
+
92
+ private validate<T>(
93
+ req: BackendRequest,
94
+ reqProperty: 'body' | 'params' | 'query',
95
+ schema: AnySchema<T>,
96
+ opt: ReqValidationOptions<JoiValidationError> = {},
97
+ ): T {
98
+ const { value, error } = getValidationResult(req[reqProperty], schema, `request ${reqProperty}`)
99
+ if (error) {
100
+ let report: boolean | undefined
101
+ if (typeof opt.report === 'boolean') {
102
+ report = opt.report
103
+ } else if (typeof opt.report === 'function') {
104
+ report = opt.report(error)
105
+ }
106
+
107
+ if (opt.redactPaths) {
108
+ redact(opt.redactPaths, req[reqProperty], error)
109
+ error.data.joiValidationErrorItems.length = 0 // clears the array
110
+ delete error.data.annotation
111
+ }
112
+
113
+ throw new AppError(error.message, {
114
+ backendResponseStatusCode: 400,
115
+ report,
116
+ ...error.data,
117
+ })
118
+ }
119
+
120
+ // mutate req to replace the property with the value, converted by Joi
121
+ req[reqProperty] = value
122
+ return value
123
+ }
124
+ }
125
+
126
+ export const validateRequest = new ValidateRequest()
@@ -1,7 +1,7 @@
1
1
  import { JsonSchema, JsonSchemaBuilder, _get, AppError } from '@naturalcycles/js-lib'
2
2
  import { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib'
3
+ import { BackendRequestHandler } from '../server.model'
3
4
  import { ReqValidationOptions } from './reqValidationMiddleware'
4
- import { BackendRequestHandler } from './server.model'
5
5
 
6
6
  const REDACTED = 'REDACTED'
7
7
 
@@ -41,7 +41,8 @@ function validateObject(
41
41
  objectName: `request ${prop}`,
42
42
  })
43
43
 
44
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => !!opt.report
44
+ const reportPredicate =
45
+ typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined
45
46
 
46
47
  return (req, res, next) => {
47
48
  const error = ajvSchema.getValidationError(req[prop])
@@ -1,6 +1,6 @@
1
1
  import { _get, AppError, ZodSchema, ZodValidationError, zSafeValidate } from '@naturalcycles/js-lib'
2
+ import { BackendRequestHandler } from '../server.model'
2
3
  import { ReqValidationOptions } from './reqValidationMiddleware'
3
- import { BackendRequestHandler } from './server.model'
4
4
 
5
5
  const REDACTED = 'REDACTED'
6
6
 
@@ -15,7 +15,8 @@ export function zodReqValidate(
15
15
  schema: ZodSchema,
16
16
  opt: ReqValidationOptions<ZodValidationError<any>> = {},
17
17
  ): BackendRequestHandler {
18
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => !!opt.report
18
+ const reportPredicate =
19
+ typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined
19
20
 
20
21
  return (req, res, next) => {
21
22
  const { error } = zSafeValidate(req[prop], schema)
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.reqValidation = void 0;
4
- const js_lib_1 = require("@naturalcycles/js-lib");
5
- const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
6
- const REDACTED = 'REDACTED';
7
- function reqValidation(reqProperty, schema, opt = {}) {
8
- const reportPredicate = typeof opt.report === 'function' ? opt.report : () => !!opt.report;
9
- return (req, res, next) => {
10
- const { value, error } = (0, nodejs_lib_1.getValidationResult)(req[reqProperty], schema, `request ${reqProperty}`);
11
- if (error) {
12
- const report = reportPredicate(error);
13
- if (opt.redactPaths) {
14
- redact(opt.redactPaths, req[reqProperty], error);
15
- error.data.joiValidationErrorItems.length = 0; // clears the array
16
- delete error.data.annotation;
17
- }
18
- return next(new js_lib_1.AppError(error.message, {
19
- backendResponseStatusCode: 400,
20
- report,
21
- ...error.data,
22
- }));
23
- }
24
- // mutate req to replace the property with the value, converted by Joi
25
- req[reqProperty] = value;
26
- next();
27
- };
28
- }
29
- exports.reqValidation = reqValidation;
30
- /**
31
- * Mutates error
32
- */
33
- function redact(redactPaths, obj, error) {
34
- redactPaths
35
- .map(path => (0, js_lib_1._get)(obj, path))
36
- .filter(Boolean)
37
- .forEach(secret => {
38
- error.message = error.message.replace(secret, REDACTED);
39
- });
40
- }