@naturalcycles/backend-lib 9.42.3 → 9.43.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.
@@ -33,6 +33,10 @@ export async function createDefaultApp(cfg) {
33
33
  // accepts application/json
34
34
  app.use(express.json({
35
35
  limit: '1mb',
36
+ verify(req, _res, buf) {
37
+ // Store the raw Buffer body
38
+ req.rawBody = buf;
39
+ },
36
40
  ...cfg.bodyParserJsonOptions,
37
41
  }));
38
42
  app.use(express.urlencoded({
@@ -44,6 +48,10 @@ export async function createDefaultApp(cfg) {
44
48
  app.use(express.raw({
45
49
  // inflate: true, // default is `true`
46
50
  limit: '1mb',
51
+ verify(req, _res, buf) {
52
+ // Store the raw Buffer body
53
+ req.rawBody = buf;
54
+ },
47
55
  ...cfg.bodyParserRawOptions,
48
56
  }));
49
57
  app.use(cookieParser());
@@ -18,6 +18,15 @@ export interface BackendRequest extends Request {
18
18
  * Only used for request logging purposes.
19
19
  */
20
20
  userId?: string;
21
+ /**
22
+ * Raw Buffer of the `req.body`, before it's stringified and json-parsed.
23
+ * Useful for when something mutates `req.body` json (e.g j validation), and you
24
+ * want access to the original input.
25
+ *
26
+ * For `req.rawBody` to exist - you need to use `createDefaultApp`, or use the
27
+ * `verify` option of the json parser (copy-paste it from `createDefaultApp`).
28
+ */
29
+ rawBody?: Buffer;
21
30
  /**
22
31
  * Set by requestTimeoutMiddleware.
23
32
  * Can be used to cancel/override the timeout.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
3
  "type": "module",
4
- "version": "9.42.3",
4
+ "version": "9.43.0",
5
5
  "peerDependencies": {
6
6
  "@sentry/node": "^10"
7
7
  },
@@ -29,13 +29,12 @@
29
29
  "@sentry/node": "^10",
30
30
  "@types/ejs": "^3",
31
31
  "fastify": "^5",
32
- "@naturalcycles/dev-lib": "20.11.1"
32
+ "@naturalcycles/dev-lib": "18.4.2"
33
33
  },
34
34
  "exports": {
35
35
  ".": "./dist/index.js",
36
36
  "./admin": "./dist/admin/index.js",
37
37
  "./admin/*.js": "./dist/admin/*.js",
38
- "./cloudrun": "./dist/cloudrun/cloudRun.js",
39
38
  "./db": "./dist/db/index.js",
40
39
  "./deploy": "./dist/deploy/index.js",
41
40
  "./deploy/*.js": "./dist/deploy/*.js",
@@ -10,7 +10,11 @@ import { logMiddleware } from '../server/logMiddleware.js'
10
10
  import { methodOverrideMiddleware } from '../server/methodOverrideMiddleware.js'
11
11
  import { notFoundMiddleware } from '../server/notFoundMiddleware.js'
12
12
  import { requestTimeoutMiddleware } from '../server/requestTimeoutMiddleware.js'
13
- import type { BackendApplication, BackendRequestHandler } from '../server/server.model.js'
13
+ import type {
14
+ BackendApplication,
15
+ BackendRequest,
16
+ BackendRequestHandler,
17
+ } from '../server/server.model.js'
14
18
  import { simpleRequestLoggerMiddleware } from '../server/simpleRequestLoggerMiddleware.js'
15
19
 
16
20
  const isTest = process.env['APP_ENV'] === 'test'
@@ -53,6 +57,10 @@ export async function createDefaultApp(cfg: DefaultAppCfg): Promise<BackendAppli
53
57
  app.use(
54
58
  express.json({
55
59
  limit: '1mb',
60
+ verify(req: BackendRequest, _res, buf) {
61
+ // Store the raw Buffer body
62
+ req.rawBody = buf
63
+ },
56
64
  ...cfg.bodyParserJsonOptions,
57
65
  }),
58
66
  )
@@ -70,6 +78,10 @@ export async function createDefaultApp(cfg: DefaultAppCfg): Promise<BackendAppli
70
78
  express.raw({
71
79
  // inflate: true, // default is `true`
72
80
  limit: '1mb',
81
+ verify(req: BackendRequest, _res, buf) {
82
+ // Store the raw Buffer body
83
+ req.rawBody = buf
84
+ },
73
85
  ...cfg.bodyParserRawOptions,
74
86
  }),
75
87
  )
@@ -20,6 +20,15 @@ export interface BackendRequest extends Request {
20
20
  * Only used for request logging purposes.
21
21
  */
22
22
  userId?: string
23
+ /**
24
+ * Raw Buffer of the `req.body`, before it's stringified and json-parsed.
25
+ * Useful for when something mutates `req.body` json (e.g j validation), and you
26
+ * want access to the original input.
27
+ *
28
+ * For `req.rawBody` to exist - you need to use `createDefaultApp`, or use the
29
+ * `verify` option of the json parser (copy-paste it from `createDefaultApp`).
30
+ */
31
+ rawBody?: Buffer
23
32
 
24
33
  /**
25
34
  * Set by requestTimeoutMiddleware.
@@ -1,114 +0,0 @@
1
- import type { AnyObject, NonNegativeInteger, NumberOfMilliseconds, NumberOfSeconds, PositiveInteger, UnixTimestamp } from '@naturalcycles/js-lib/types';
2
- export interface CloudRunConfig {
3
- gcpProject: string;
4
- /**
5
- * Name of the Cloud Run service.
6
- */
7
- cloudRunService: string;
8
- cloudRunServiceBase?: string;
9
- runtimeServiceAccount: string;
10
- /**
11
- * GCP region where the Cloud Run service is deployed. Example: 'europe-west1'
12
- */
13
- cloudRunRegion: string;
14
- sqlInstance?: string;
15
- vpcConnector?: string;
16
- serviceUrl?: string;
17
- /**
18
- * Service URL that is used to access the service externally (through load balancer)
19
- * todo: overlaps with env.K_EXTERNAL_URL
20
- */
21
- externalUrl?: string;
22
- buildVersion: string;
23
- /**
24
- * Unix timestamp of the build/deployment time.
25
- */
26
- tsUnix: UnixTimestamp;
27
- targetDockerImageId: string;
28
- dockerImageTag: string;
29
- /**
30
- * Short SHA of the commit used for this deployment.
31
- */
32
- gitRev: string;
33
- gitBranch: string;
34
- /**
35
- * Example: 'APP_ENV=prod,BUILD_VERSION=abcd,a=b'
36
- */
37
- envString: string;
38
- /**
39
- * Example: httpGet.path='/',httpGet.port=8080,initialDelaySeconds=3,failureThreshold=50,timeoutSeconds=1,periodSeconds=2
40
- */
41
- startupProbeConfigString: string;
42
- livenessProbeConfigString?: string;
43
- minInstances: NonNegativeInteger;
44
- maxInstances: PositiveInteger;
45
- /**
46
- * CloudRun concurrency setting.
47
- * Example: 80
48
- */
49
- concurrency: PositiveInteger;
50
- /**
51
- * Example: '512Mi'
52
- */
53
- memoryPerInstance: string;
54
- }
55
- export interface CloudRunProbeConfig {
56
- /**
57
- * Example: '/'
58
- */
59
- 'httpGet.path': string;
60
- 'httpGet.port': PositiveInteger;
61
- initialDelaySeconds: NumberOfSeconds;
62
- failureThreshold: PositiveInteger;
63
- timeoutSeconds: NumberOfSeconds;
64
- periodSeconds: NumberOfSeconds;
65
- }
66
- export interface CloudRunEnv {
67
- APP_ENV: string;
68
- /**
69
- * Example: '--max-old-space-size=864'
70
- */
71
- NODE_OPTIONS?: string;
72
- /**
73
- * Example: '2025-09-01T15:23:20.769Z'
74
- * The result of running `new Date().toISOString()`
75
- */
76
- DEPLOY_BUILD_TIME: string;
77
- /**
78
- * Example: 'abcd'
79
- * Should match the name of the GCP project.
80
- */
81
- GOOGLE_CLOUD_PROJECT: string;
82
- /**
83
- * Anything (a string) that would identify the build.
84
- */
85
- BUILD_VERSION: string;
86
- /**
87
- * External url of the deployed service.
88
- */
89
- K_EXTERNAL_URL?: string;
90
- OTEL_SERVICE_NAME?: string;
91
- OTEL_METRICS_EXPORTER?: 'console' | 'otlp' | string;
92
- OTEL_METRIC_EXPORT_INTERVAL?: NumberOfMilliseconds;
93
- OTEL_METRIC_EXPORT_TIMEOUT?: NumberOfMilliseconds;
94
- OTEL_EXPORTER_OTLP_PROTOCOL?: 'http/protobuf' | string;
95
- /**
96
- * Example: 'http://localhost:4317'
97
- */
98
- OTEL_EXPORTER_OTLP_ENDPOINT?: string;
99
- OTEL_LOG_LEVEL?: 'INFO' | 'DEBUG';
100
- }
101
- /**
102
- * @experimental
103
- */
104
- declare class CloudRunUtil {
105
- /**
106
- * Turns an object into a string representation where each
107
- * key-value pair is represented as `key1=value1,key2=value2,...`.
108
- */
109
- stringifyObject(obj: AnyObject): string;
110
- readonly defaultStartupProbeConfig: CloudRunProbeConfig;
111
- readonly defaultLivenessProbeConfig: CloudRunProbeConfig;
112
- }
113
- export declare const cloudRunUtil: CloudRunUtil;
114
- export {};
@@ -1,37 +0,0 @@
1
- import { _filterUndefinedValues } from '@naturalcycles/js-lib/object';
2
- /**
3
- * @experimental
4
- */
5
- class CloudRunUtil {
6
- /**
7
- * Turns an object into a string representation where each
8
- * key-value pair is represented as `key1=value1,key2=value2,...`.
9
- */
10
- stringifyObject(obj) {
11
- const filteredObj = _filterUndefinedValues(obj);
12
- return Object.entries(filteredObj)
13
- .map(([key, value]) => `${key}=${value}`)
14
- .join(',');
15
- }
16
- defaultStartupProbeConfig = {
17
- 'httpGet.path': '/',
18
- 'httpGet.port': 8080,
19
- initialDelaySeconds: 3,
20
- failureThreshold: 50,
21
- timeoutSeconds: 1,
22
- periodSeconds: 2,
23
- };
24
- defaultLivenessProbeConfig = {
25
- 'httpGet.path': '/',
26
- 'httpGet.port': 8080,
27
- // how long to wait before doing the first check, AFTER the startup probe has succeeded
28
- initialDelaySeconds: 60,
29
- // after how many failure it should kill/restart the container
30
- failureThreshold: 5,
31
- // how long to wait until liveness probe considers the endpoint unhealthy
32
- timeoutSeconds: 30,
33
- // check every periodSeconds
34
- periodSeconds: 60,
35
- };
36
- }
37
- export const cloudRunUtil = new CloudRunUtil();
@@ -1,171 +0,0 @@
1
- import { _filterUndefinedValues } from '@naturalcycles/js-lib/object'
2
- import type {
3
- AnyObject,
4
- NonNegativeInteger,
5
- NumberOfMilliseconds,
6
- NumberOfSeconds,
7
- PositiveInteger,
8
- UnixTimestamp,
9
- } from '@naturalcycles/js-lib/types'
10
-
11
- export interface CloudRunConfig {
12
- //
13
- // GCP settings
14
- //
15
- gcpProject: string
16
- /**
17
- * Name of the Cloud Run service.
18
- */
19
- cloudRunService: string
20
- cloudRunServiceBase?: string // todo: review
21
- runtimeServiceAccount: string
22
- /**
23
- * GCP region where the Cloud Run service is deployed. Example: 'europe-west1'
24
- */
25
- cloudRunRegion: string
26
- sqlInstance?: string
27
- vpcConnector?: string
28
- //
29
- // Urls
30
- //
31
- serviceUrl?: string
32
- /**
33
- * Service URL that is used to access the service externally (through load balancer)
34
- * todo: overlaps with env.K_EXTERNAL_URL
35
- */
36
- externalUrl?: string
37
- //
38
- // Versioning
39
- //
40
- buildVersion: string // todo: overlaps with env.BUILD_VERSION
41
- /**
42
- * Unix timestamp of the build/deployment time.
43
- */
44
- tsUnix: UnixTimestamp
45
- //
46
- // Docker
47
- //
48
- targetDockerImageId: string
49
- dockerImageTag: string
50
- //
51
- // Git
52
- //
53
- /**
54
- * Short SHA of the commit used for this deployment.
55
- */
56
- gitRev: string
57
- gitBranch: string
58
- //
59
- // Cloud Run environment settings
60
- //
61
- /**
62
- * Example: 'APP_ENV=prod,BUILD_VERSION=abcd,a=b'
63
- */
64
- envString: string
65
- /**
66
- * Example: httpGet.path='/',httpGet.port=8080,initialDelaySeconds=3,failureThreshold=50,timeoutSeconds=1,periodSeconds=2
67
- */
68
- startupProbeConfigString: string
69
- livenessProbeConfigString?: string
70
- minInstances: NonNegativeInteger
71
- maxInstances: PositiveInteger
72
- /**
73
- * CloudRun concurrency setting.
74
- * Example: 80
75
- */
76
- concurrency: PositiveInteger
77
- /**
78
- * Example: '512Mi'
79
- */
80
- memoryPerInstance: string
81
- }
82
-
83
- export interface CloudRunProbeConfig {
84
- /**
85
- * Example: '/'
86
- */
87
- 'httpGet.path': string
88
- 'httpGet.port': PositiveInteger
89
- initialDelaySeconds: NumberOfSeconds
90
- failureThreshold: PositiveInteger
91
- timeoutSeconds: NumberOfSeconds
92
- periodSeconds: NumberOfSeconds
93
- }
94
-
95
- export interface CloudRunEnv {
96
- APP_ENV: string
97
- /**
98
- * Example: '--max-old-space-size=864'
99
- */
100
- NODE_OPTIONS?: string
101
- /**
102
- * Example: '2025-09-01T15:23:20.769Z'
103
- * The result of running `new Date().toISOString()`
104
- */
105
- DEPLOY_BUILD_TIME: string
106
- /**
107
- * Example: 'abcd'
108
- * Should match the name of the GCP project.
109
- */
110
- GOOGLE_CLOUD_PROJECT: string
111
- /**
112
- * Anything (a string) that would identify the build.
113
- */
114
- BUILD_VERSION: string
115
- /**
116
- * External url of the deployed service.
117
- */
118
- K_EXTERNAL_URL?: string
119
- // UV_THREADPOOL_SIZE?: number
120
-
121
- OTEL_SERVICE_NAME?: string
122
- OTEL_METRICS_EXPORTER?: 'console' | 'otlp' | string
123
- OTEL_METRIC_EXPORT_INTERVAL?: NumberOfMilliseconds
124
- OTEL_METRIC_EXPORT_TIMEOUT?: NumberOfMilliseconds
125
- OTEL_EXPORTER_OTLP_PROTOCOL?: 'http/protobuf' | string
126
- /**
127
- * Example: 'http://localhost:4317'
128
- */
129
- OTEL_EXPORTER_OTLP_ENDPOINT?: string
130
- OTEL_LOG_LEVEL?: 'INFO' | 'DEBUG'
131
- }
132
-
133
- /**
134
- * @experimental
135
- */
136
- class CloudRunUtil {
137
- /**
138
- * Turns an object into a string representation where each
139
- * key-value pair is represented as `key1=value1,key2=value2,...`.
140
- */
141
- stringifyObject(obj: AnyObject): string {
142
- const filteredObj = _filterUndefinedValues(obj)
143
- return Object.entries(filteredObj)
144
- .map(([key, value]) => `${key}=${value}`)
145
- .join(',')
146
- }
147
-
148
- readonly defaultStartupProbeConfig: CloudRunProbeConfig = {
149
- 'httpGet.path': '/',
150
- 'httpGet.port': 8080,
151
- initialDelaySeconds: 3,
152
- failureThreshold: 50,
153
- timeoutSeconds: 1,
154
- periodSeconds: 2,
155
- }
156
-
157
- readonly defaultLivenessProbeConfig: CloudRunProbeConfig = {
158
- 'httpGet.path': '/',
159
- 'httpGet.port': 8080,
160
- // how long to wait before doing the first check, AFTER the startup probe has succeeded
161
- initialDelaySeconds: 60,
162
- // after how many failure it should kill/restart the container
163
- failureThreshold: 5,
164
- // how long to wait until liveness probe considers the endpoint unhealthy
165
- timeoutSeconds: 30,
166
- // check every periodSeconds
167
- periodSeconds: 60,
168
- }
169
- }
170
-
171
- export const cloudRunUtil = new CloudRunUtil()