@naturalcycles/backend-lib 9.51.0 → 9.52.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/express/createDefaultApp.d.ts +1 -1
- package/dist/express/createDefaultApp.js +1 -1
- package/dist/express/startServer.d.ts +1 -1
- package/dist/testing/express.test.service.d.ts +1 -1
- package/dist/testing/express.test.service.js +1 -1
- package/dist/validation/ajv/validateRequest.d.ts +6 -6
- package/dist/validation/ajv/validateRequest.js +2 -2
- package/dist/validation/zod/zodValidateRequest.d.ts +2 -2
- package/dist/validation/zod/zodValidateRequest.js +3 -1
- package/package.json +3 -3
- package/readme.md +4 -0
- package/src/deploy/backend.cfg.util.ts +2 -1
- package/src/express/createDefaultApp.ts +2 -4
- package/src/express/startServer.ts +2 -1
- package/src/server/logMiddleware.ts +2 -1
- package/src/server/serverStatsMiddleware.ts +2 -1
- package/src/testing/express.test.service.ts +2 -5
- package/src/validation/ajv/validateRequest.ts +16 -19
- package/src/validation/zod/zodValidateRequest.ts +4 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Options, OptionsJson, OptionsUrlencoded } from 'body-parser';
|
|
2
2
|
import type { CorsOptions } from 'cors';
|
|
3
3
|
import type { SentrySharedService } from '../sentry/sentry.shared.service.js';
|
|
4
|
-
import {
|
|
4
|
+
import type { GenericErrorMiddlewareCfg } from '../server/genericErrorMiddleware.js';
|
|
5
5
|
import type { BackendApplication, BackendRequestHandler } from '../server/server.model.js';
|
|
6
6
|
export declare function createDefaultApp(cfg: DefaultAppCfg): Promise<BackendApplication>;
|
|
7
7
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { asyncLocalStorageMiddleware } from '../server/asyncLocalStorageMiddleware.js';
|
|
2
2
|
import { compressionMiddleware } from '../server/compressionMiddleware.js';
|
|
3
|
-
import { genericErrorMiddleware
|
|
3
|
+
import { genericErrorMiddleware } from '../server/genericErrorMiddleware.js';
|
|
4
4
|
import { logMiddleware } from '../server/logMiddleware.js';
|
|
5
5
|
import { methodOverrideMiddleware } from '../server/methodOverrideMiddleware.js';
|
|
6
6
|
import { notFoundMiddleware } from '../server/notFoundMiddleware.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Server } from 'node:http';
|
|
2
2
|
import type { SentrySharedService } from '../sentry/sentry.shared.service.js';
|
|
3
3
|
import type { BackendApplication } from '../server/server.model.js';
|
|
4
|
-
import {
|
|
4
|
+
import type { DefaultAppCfg } from './createDefaultApp.js';
|
|
5
5
|
export declare class BackendServer {
|
|
6
6
|
private cfg;
|
|
7
7
|
constructor(cfg: StartServerCfg);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Fetcher, FetcherOptions } from '@naturalcycles/js-lib/http';
|
|
2
|
-
import {
|
|
2
|
+
import type { BackendRequestHandlerCfg, DefaultAppCfg } from '../express/createDefaultApp.js';
|
|
3
3
|
import type { BackendApplication } from '../server/server.model.js';
|
|
4
4
|
export interface ExpressApp extends Fetcher, AsyncDisposable {
|
|
5
5
|
close: () => Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getFetcher } from '@naturalcycles/js-lib/http';
|
|
2
2
|
import { pDelay } from '@naturalcycles/js-lib/promise/pDelay.js';
|
|
3
|
-
import { createDefaultApp
|
|
3
|
+
import { createDefaultApp } from '../express/createDefaultApp.js';
|
|
4
4
|
const nativeFetchFn = async (url, init) => await globalThis.fetch(url, init);
|
|
5
5
|
// Example:
|
|
6
6
|
// const app = expressTestService.createApp([ debugResource ])
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AjvValidationError, SchemaHandledByAjv } from '@naturalcycles/nodejs-lib/ajv';
|
|
2
2
|
import type { BackendRequest } from '../../server/server.model.js';
|
|
3
|
-
import {
|
|
3
|
+
import type { ReqValidationOptions } from '../validateRequest.util.js';
|
|
4
4
|
declare class AjvValidateRequest {
|
|
5
|
-
body<
|
|
5
|
+
body<OUT>(req: BackendRequest, schema: SchemaHandledByAjv<OUT>, opt?: ReqValidationOptions<AjvValidationError>): OUT;
|
|
6
6
|
/**
|
|
7
7
|
* Query validation uses type coercion (unlike body validation),
|
|
8
8
|
* so the passed in schemas do not need to specify only string values.
|
|
9
9
|
*
|
|
10
10
|
* Coercion mutates the input, even if the end result is that the input failed the validation.
|
|
11
11
|
*/
|
|
12
|
-
query<
|
|
12
|
+
query<OUT>(req: BackendRequest, schema: SchemaHandledByAjv<OUT>, opt?: ReqValidationOptions<AjvValidationError>): OUT;
|
|
13
13
|
/**
|
|
14
14
|
* Params validation uses type coercion (unlike body validation),
|
|
15
15
|
* so the passed in schemas do not need to specify only string values.
|
|
16
16
|
*
|
|
17
17
|
* Coercion mutates the input, even if the end result is that the input failed the validation.
|
|
18
18
|
*/
|
|
19
|
-
params<
|
|
19
|
+
params<OUT>(req: BackendRequest, schema: SchemaHandledByAjv<OUT>, opt?: ReqValidationOptions<AjvValidationError>): OUT;
|
|
20
20
|
/**
|
|
21
21
|
* Does NOT mutate `req.headers`,
|
|
22
22
|
* but returns validated/transformed headers.
|
|
@@ -25,7 +25,7 @@ declare class AjvValidateRequest {
|
|
|
25
25
|
* We want to non-mutate the `req.headers`, because we anticipate that
|
|
26
26
|
* there may be additional consumers for `req.headers` (e.g middlewares, etc).
|
|
27
27
|
*/
|
|
28
|
-
headers<
|
|
28
|
+
headers<OUT>(req: BackendRequest, schema: SchemaHandledByAjv<OUT>, opt?: ReqValidationOptions<AjvValidationError>): OUT;
|
|
29
29
|
private validate;
|
|
30
30
|
}
|
|
31
31
|
export declare const validateRequest: AjvValidateRequest;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AjvSchema, getCoercingAjv
|
|
1
|
+
import { AjvSchema, getCoercingAjv } from '@naturalcycles/nodejs-lib/ajv';
|
|
2
2
|
import { handleValidationError } from '../validateRequest.util.js';
|
|
3
3
|
class AjvValidateRequest {
|
|
4
4
|
body(req, schema, opt = {}) {
|
|
@@ -45,7 +45,7 @@ class AjvValidateRequest {
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
validate(req, reqProperty, schema, getOriginalInput, opt = {}) {
|
|
48
|
-
const input =
|
|
48
|
+
const input = req[reqProperty] || {};
|
|
49
49
|
const { coerceTypes, mutateInput } = opt;
|
|
50
50
|
const ajv = coerceTypes ? getCoercingAjv() : undefined;
|
|
51
51
|
const ajvSchema = AjvSchema.create(schema, { ajv });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ZodType, ZodValidationError } from '@naturalcycles/js-lib/zod';
|
|
2
2
|
import type { BackendRequest } from '../../server/server.model.js';
|
|
3
|
-
import {
|
|
3
|
+
import type { ReqValidationOptions } from '../validateRequest.util.js';
|
|
4
4
|
declare class ZodValidateRequest {
|
|
5
5
|
body<T>(req: BackendRequest, schema: ZodType<T>, opt?: ReqValidationOptions<ZodValidationError>): T;
|
|
6
6
|
query<T>(req: BackendRequest, schema: ZodType<T>, opt?: ReqValidationOptions<ZodValidationError>): T;
|
|
@@ -25,7 +25,9 @@ class ZodValidateRequest {
|
|
|
25
25
|
validate(req, reqProperty, schema, opt = {}) {
|
|
26
26
|
const originalProperty = (req[reqProperty] || {});
|
|
27
27
|
// Zod does not mutate the input
|
|
28
|
-
const [error, data] = zSafeValidate(originalProperty, schema
|
|
28
|
+
const [error, data] = zSafeValidate(originalProperty, schema
|
|
29
|
+
// opt2?.itemName,
|
|
30
|
+
);
|
|
29
31
|
if (error) {
|
|
30
32
|
handleValidationError(error, originalProperty, opt);
|
|
31
33
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/backend-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.52.0",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@sentry/node": "^10"
|
|
7
7
|
},
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@sentry/node": "^10",
|
|
36
|
-
"@
|
|
36
|
+
"@typescript/native-preview": "7.0.0-dev.20260201.1",
|
|
37
37
|
"fastify": "^5",
|
|
38
38
|
"@naturalcycles/dev-lib": "18.4.2"
|
|
39
39
|
},
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"./deploy": "./dist/deploy/index.js",
|
|
46
46
|
"./deploy/*.js": "./dist/deploy/*.js",
|
|
47
47
|
"./express/*.js": "./dist/express/*.js",
|
|
48
|
-
"./
|
|
48
|
+
"./validateRequest": "./dist/validation/ajv/validateRequest.js",
|
|
49
49
|
"./zodValidateRequest": "./dist/validation/zod/zodValidateRequest.js",
|
|
50
50
|
"./onFinished": "./dist/onFinished.js",
|
|
51
51
|
"./testing": "./dist/testing/index.js"
|
package/readme.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { _lazyValue } from '@naturalcycles/js-lib'
|
|
2
2
|
import type { StringMap } from '@naturalcycles/js-lib/types'
|
|
3
|
-
import { AjvSchema
|
|
3
|
+
import { AjvSchema } from '@naturalcycles/nodejs-lib/ajv'
|
|
4
|
+
import type { JsonSchema } from '@naturalcycles/nodejs-lib/ajv'
|
|
4
5
|
import { fs2 } from '@naturalcycles/nodejs-lib/fs2'
|
|
5
6
|
import { yaml2 } from '@naturalcycles/nodejs-lib/yaml2'
|
|
6
7
|
import { resourcesDir } from '../paths.cnst.js'
|
|
@@ -3,10 +3,8 @@ import type { CorsOptions } from 'cors'
|
|
|
3
3
|
import type { SentrySharedService } from '../sentry/sentry.shared.service.js'
|
|
4
4
|
import { asyncLocalStorageMiddleware } from '../server/asyncLocalStorageMiddleware.js'
|
|
5
5
|
import { compressionMiddleware } from '../server/compressionMiddleware.js'
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
type GenericErrorMiddlewareCfg,
|
|
9
|
-
} from '../server/genericErrorMiddleware.js'
|
|
6
|
+
import { genericErrorMiddleware } from '../server/genericErrorMiddleware.js'
|
|
7
|
+
import type { GenericErrorMiddlewareCfg } from '../server/genericErrorMiddleware.js'
|
|
10
8
|
import { logMiddleware } from '../server/logMiddleware.js'
|
|
11
9
|
import { methodOverrideMiddleware } from '../server/methodOverrideMiddleware.js'
|
|
12
10
|
import { notFoundMiddleware } from '../server/notFoundMiddleware.js'
|
|
@@ -5,7 +5,8 @@ import { _Memo } from '@naturalcycles/js-lib/decorators/memo.decorator.js'
|
|
|
5
5
|
import { boldGrey, dimGrey, white } from '@naturalcycles/nodejs-lib/colors'
|
|
6
6
|
import type { SentrySharedService } from '../sentry/sentry.shared.service.js'
|
|
7
7
|
import type { BackendApplication } from '../server/server.model.js'
|
|
8
|
-
import { createDefaultApp
|
|
8
|
+
import { createDefaultApp } from './createDefaultApp.js'
|
|
9
|
+
import type { DefaultAppCfg } from './createDefaultApp.js'
|
|
9
10
|
|
|
10
11
|
const { NODE_OPTIONS, APP_ENV } = process.env
|
|
11
12
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { inspect } from 'node:util'
|
|
2
2
|
import type { CommonLogger } from '@naturalcycles/js-lib/log'
|
|
3
|
-
import { _objectAssign
|
|
3
|
+
import { _objectAssign } from '@naturalcycles/js-lib/types'
|
|
4
|
+
import type { AnyObject } from '@naturalcycles/js-lib/types'
|
|
4
5
|
import { _inspect } from '@naturalcycles/nodejs-lib'
|
|
5
6
|
import { dimGrey } from '@naturalcycles/nodejs-lib/colors'
|
|
6
7
|
import type { BackendRequestHandler } from './server.model.js'
|
|
@@ -5,7 +5,8 @@ import { _ms } from '@naturalcycles/js-lib/datetime/time.util.js'
|
|
|
5
5
|
import { _percentile } from '@naturalcycles/js-lib/math/math.util.js'
|
|
6
6
|
import { NumberStack } from '@naturalcycles/js-lib/math/stack.util.js'
|
|
7
7
|
import { _get, _mapValues } from '@naturalcycles/js-lib/object/object.util.js'
|
|
8
|
-
import { _stringMapEntries, _stringMapValues
|
|
8
|
+
import { _stringMapEntries, _stringMapValues } from '@naturalcycles/js-lib/types'
|
|
9
|
+
import type { StringMap } from '@naturalcycles/js-lib/types'
|
|
9
10
|
import { onFinished } from '../onFinished.js'
|
|
10
11
|
import { getRequestEndpoint } from './request.util.js'
|
|
11
12
|
import type { BackendRequestHandler } from './server.model.js'
|
|
@@ -3,11 +3,8 @@ import type { AddressInfo } from 'node:net'
|
|
|
3
3
|
import type { Fetcher, FetcherOptions, FetchFunction } from '@naturalcycles/js-lib/http'
|
|
4
4
|
import { getFetcher } from '@naturalcycles/js-lib/http'
|
|
5
5
|
import { pDelay } from '@naturalcycles/js-lib/promise/pDelay.js'
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
createDefaultApp,
|
|
9
|
-
type DefaultAppCfg,
|
|
10
|
-
} from '../express/createDefaultApp.js'
|
|
6
|
+
import { createDefaultApp } from '../express/createDefaultApp.js'
|
|
7
|
+
import type { BackendRequestHandlerCfg, DefaultAppCfg } from '../express/createDefaultApp.js'
|
|
11
8
|
import type { BackendApplication } from '../server/server.model.js'
|
|
12
9
|
|
|
13
10
|
const nativeFetchFn: FetchFunction = async (url, init) => await globalThis.fetch(url, init)
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type AjvValidationError,
|
|
4
|
-
getCoercingAjv,
|
|
5
|
-
type SchemaHandledByAjv,
|
|
6
|
-
} from '@naturalcycles/nodejs-lib/ajv'
|
|
1
|
+
import { AjvSchema, getCoercingAjv } from '@naturalcycles/nodejs-lib/ajv'
|
|
2
|
+
import type { AjvValidationError, SchemaHandledByAjv } from '@naturalcycles/nodejs-lib/ajv'
|
|
7
3
|
import type { BackendRequest } from '../../server/server.model.js'
|
|
8
|
-
import { handleValidationError
|
|
4
|
+
import { handleValidationError } from '../validateRequest.util.js'
|
|
5
|
+
import type { ReqValidationOptions } from '../validateRequest.util.js'
|
|
9
6
|
|
|
10
7
|
class AjvValidateRequest {
|
|
11
|
-
body<
|
|
8
|
+
body<OUT>(
|
|
12
9
|
req: BackendRequest,
|
|
13
|
-
schema: SchemaHandledByAjv<
|
|
10
|
+
schema: SchemaHandledByAjv<OUT>,
|
|
14
11
|
opt: ReqValidationOptions<AjvValidationError> = {},
|
|
15
12
|
): OUT {
|
|
16
13
|
return this.validate(
|
|
@@ -28,9 +25,9 @@ class AjvValidateRequest {
|
|
|
28
25
|
*
|
|
29
26
|
* Coercion mutates the input, even if the end result is that the input failed the validation.
|
|
30
27
|
*/
|
|
31
|
-
query<
|
|
28
|
+
query<OUT>(
|
|
32
29
|
req: BackendRequest,
|
|
33
|
-
schema: SchemaHandledByAjv<
|
|
30
|
+
schema: SchemaHandledByAjv<OUT>,
|
|
34
31
|
opt: ReqValidationOptions<AjvValidationError> = {},
|
|
35
32
|
): OUT {
|
|
36
33
|
const originalQuery = JSON.stringify(req.query)
|
|
@@ -46,9 +43,9 @@ class AjvValidateRequest {
|
|
|
46
43
|
*
|
|
47
44
|
* Coercion mutates the input, even if the end result is that the input failed the validation.
|
|
48
45
|
*/
|
|
49
|
-
params<
|
|
46
|
+
params<OUT>(
|
|
50
47
|
req: BackendRequest,
|
|
51
|
-
schema: SchemaHandledByAjv<
|
|
48
|
+
schema: SchemaHandledByAjv<OUT>,
|
|
52
49
|
opt: ReqValidationOptions<AjvValidationError> = {},
|
|
53
50
|
): OUT {
|
|
54
51
|
const originalParams = JSON.stringify(req.params)
|
|
@@ -66,9 +63,9 @@ class AjvValidateRequest {
|
|
|
66
63
|
* We want to non-mutate the `req.headers`, because we anticipate that
|
|
67
64
|
* there may be additional consumers for `req.headers` (e.g middlewares, etc).
|
|
68
65
|
*/
|
|
69
|
-
headers<
|
|
66
|
+
headers<OUT>(
|
|
70
67
|
req: BackendRequest,
|
|
71
|
-
schema: SchemaHandledByAjv<
|
|
68
|
+
schema: SchemaHandledByAjv<OUT>,
|
|
72
69
|
opt: ReqValidationOptions<AjvValidationError> = {},
|
|
73
70
|
): OUT {
|
|
74
71
|
return this.validate(req, 'headers', schema, undefined, {
|
|
@@ -77,14 +74,14 @@ class AjvValidateRequest {
|
|
|
77
74
|
})
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
private validate<
|
|
77
|
+
private validate<OUT>(
|
|
81
78
|
req: BackendRequest,
|
|
82
79
|
reqProperty: 'body' | 'params' | 'query' | 'headers',
|
|
83
|
-
schema: SchemaHandledByAjv<
|
|
84
|
-
getOriginalInput?: () =>
|
|
80
|
+
schema: SchemaHandledByAjv<OUT>,
|
|
81
|
+
getOriginalInput?: () => unknown,
|
|
85
82
|
opt: ReqValidationOptions<AjvValidationError> = {},
|
|
86
83
|
): OUT {
|
|
87
|
-
const input =
|
|
84
|
+
const input = req[reqProperty] || {}
|
|
88
85
|
|
|
89
86
|
const { coerceTypes, mutateInput } = opt
|
|
90
87
|
const ajv = coerceTypes ? getCoercingAjv() : undefined
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { zSafeValidate } from '@naturalcycles/js-lib/zod'
|
|
2
|
+
import type { ZodType, ZodValidationError } from '@naturalcycles/js-lib/zod'
|
|
2
3
|
import type { BackendRequest } from '../../server/server.model.js'
|
|
3
|
-
import { handleValidationError
|
|
4
|
+
import { handleValidationError } from '../validateRequest.util.js'
|
|
5
|
+
import type { ReqValidationOptions } from '../validateRequest.util.js'
|
|
4
6
|
|
|
5
7
|
class ZodValidateRequest {
|
|
6
8
|
body<T>(
|