@naturalcycles/backend-lib 5.7.1 → 5.8.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.
Files changed (51) hide show
  1. package/dist/admin/adminMiddleware.js +1 -1
  2. package/dist/admin/secureHeaderMiddleware.js +2 -1
  3. package/dist/db/httpDBRequestHandler.js +2 -2
  4. package/dist/deploy/deployGae.js +2 -3
  5. package/dist/deploy/index.d.ts +2 -2
  6. package/dist/deploy/index.js +1 -1
  7. package/dist/env/env.shared.service.d.ts +9 -6
  8. package/dist/env/env.shared.service.js +6 -13
  9. package/dist/index.d.ts +14 -15
  10. package/dist/index.js +14 -15
  11. package/dist/sentry/sentry.shared.service.js +2 -1
  12. package/dist/server/appEngineLogMiddleware.js +2 -2
  13. package/dist/server/asyncLocalStorageMiddleware.js +1 -1
  14. package/dist/server/bodyParserTimeoutMiddleware.js +1 -1
  15. package/dist/server/methodOverrideMiddleware.js +1 -1
  16. package/dist/server/okMiddleware.js +1 -1
  17. package/dist/server/safeJsonMiddleware.js +1 -1
  18. package/dist/server/server.model.d.ts +1 -1
  19. package/dist/server/server.util.js +1 -1
  20. package/dist/server/serverStatusMiddleware.js +1 -1
  21. package/dist/server/simpleRequestLoggerMiddleware.js +1 -1
  22. package/dist/server/validation/validateMiddleware.js +1 -1
  23. package/dist/server/validation/zodValidateMiddleware.js +1 -1
  24. package/package.json +9 -4
  25. package/src/admin/adminMiddleware.ts +1 -1
  26. package/src/admin/base.admin.service.ts +1 -1
  27. package/src/admin/secureHeaderMiddleware.ts +2 -1
  28. package/src/db/httpDBRequestHandler.ts +2 -2
  29. package/src/deploy/backend.cfg.util.ts +1 -1
  30. package/src/deploy/deployGae.ts +2 -3
  31. package/src/deploy/deployHealthCheck.ts +2 -2
  32. package/src/deploy/index.ts +4 -4
  33. package/src/env/env.shared.service.ts +15 -19
  34. package/src/index.ts +14 -15
  35. package/src/sentry/sentry.shared.service.ts +4 -3
  36. package/src/server/appEngineLogMiddleware.ts +3 -3
  37. package/src/server/asyncLocalStorageMiddleware.ts +2 -2
  38. package/src/server/bodyParserTimeoutMiddleware.ts +1 -1
  39. package/src/server/createDefaultApp.ts +1 -1
  40. package/src/server/methodOverrideMiddleware.ts +1 -1
  41. package/src/server/okMiddleware.ts +1 -1
  42. package/src/server/safeJsonMiddleware.ts +1 -1
  43. package/src/server/server.model.ts +1 -1
  44. package/src/server/server.util.ts +1 -1
  45. package/src/server/serverStatusMiddleware.ts +1 -1
  46. package/src/server/simpleRequestLoggerMiddleware.ts +1 -1
  47. package/src/server/validation/validateMiddleware.ts +2 -2
  48. package/src/server/validation/zodValidateMiddleware.ts +1 -1
  49. package/dist/env/env.model.d.ts +0 -3
  50. package/dist/env/env.model.js +0 -2
  51. package/src/env/env.model.ts +0 -3
@@ -43,7 +43,7 @@ function requireAdminPermissions(adminService, reqPermissions = [], cfg = {}) {
43
43
  }
44
44
  function loginHtml(firebaseServiceCfg) {
45
45
  const { apiKey: firebaseApiKey, authDomain: firebaseAuthDomain, adminAuthProvider: firebaseAuthProvider = 'GoogleAuthProvider', } = firebaseServiceCfg;
46
- return (req, res) => {
46
+ return (_req, res) => {
47
47
  res.send(getLoginHtml({
48
48
  firebaseApiKey,
49
49
  firebaseAuthDomain,
@@ -21,8 +21,9 @@ function requireSecureHeaderOrAdmin(cfg, reqPermissions) {
21
21
  return next();
22
22
  // Header provided - don't check for Admin
23
23
  if (providedHeader) {
24
- if (!secureHeaderValue || (0, nodejs_lib_1.timingSafeStringEqual)(providedHeader, secureHeaderValue))
24
+ if (!secureHeaderValue || (0, nodejs_lib_1.timingSafeStringEqual)(providedHeader, secureHeaderValue)) {
25
25
  return next();
26
+ }
26
27
  return next(new js_lib_1.AppError('secureHeader or adminToken is required', {
27
28
  backendResponseStatusCode: 401,
28
29
  adminAuthRequired: true,
@@ -32,12 +32,12 @@ function httpDBRequestHandler(db) {
32
32
  res.end();
33
33
  });
34
34
  // ping
35
- router.get('/ping', async (req, res) => {
35
+ router.get('/ping', async (_req, res) => {
36
36
  await db.ping();
37
37
  res.end();
38
38
  });
39
39
  // getTables
40
- router.get('/tables', async (req, res) => {
40
+ router.get('/tables', async (_req, res) => {
41
41
  res.json(await db.getTables());
42
42
  });
43
43
  // getTableSchema
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deployGae = deployGae;
4
4
  exports.undeployGae = undeployGae;
5
- const dev_lib_1 = require("@naturalcycles/dev-lib");
6
5
  const js_lib_1 = require("@naturalcycles/js-lib");
7
6
  const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
8
7
  const backend_cfg_util_1 = require("./backend.cfg.util");
@@ -11,8 +10,8 @@ const deployHealthCheck_1 = require("./deployHealthCheck");
11
10
  const deployPrepare_1 = require("./deployPrepare");
12
11
  async function deployGae(opt = {}) {
13
12
  const { logOnFailure, logOnSuccess } = opt;
14
- // 1. build-prod
15
- (0, dev_lib_1.buildProdCommand)();
13
+ // 1. build
14
+ (0, nodejs_lib_1.execVoidCommandSync)('yarn', ['build']);
16
15
  // 2. deploy-prepare
17
16
  const deployInfo = await (0, deployPrepare_1.deployPrepare)();
18
17
  const targetDir = './tmp/deploy';
@@ -4,5 +4,5 @@ import { createAppYaml, createDeployInfo } from './deploy.util';
4
4
  import { deployGae } from './deployGae';
5
5
  import { deployHealthCheck, DeployHealthCheckOptions } from './deployHealthCheck';
6
6
  import { deployPrepare } from './deployPrepare';
7
- export type { BackendCfg, DeployInfo, DeployHealthCheckOptions };
8
- export { getBackendCfg, createDeployInfo, createAppYaml, deployGae, deployPrepare, deployHealthCheck, };
7
+ export type { BackendCfg, DeployHealthCheckOptions, DeployInfo };
8
+ export { createAppYaml, createDeployInfo, deployGae, deployHealthCheck, deployPrepare, getBackendCfg, };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deployHealthCheck = exports.deployPrepare = exports.deployGae = exports.createAppYaml = exports.createDeployInfo = exports.getBackendCfg = void 0;
3
+ exports.getBackendCfg = exports.deployPrepare = exports.deployHealthCheck = exports.deployGae = exports.createDeployInfo = exports.createAppYaml = void 0;
4
4
  const backend_cfg_util_1 = require("./backend.cfg.util");
5
5
  Object.defineProperty(exports, "getBackendCfg", { enumerable: true, get: function () { return backend_cfg_util_1.getBackendCfg; } });
6
6
  const deploy_util_1 = require("./deploy.util");
@@ -1,13 +1,16 @@
1
- import { BaseEnv } from './env.model';
2
- export interface EnvSharedServiceCfg {
1
+ import { StringMap } from '@naturalcycles/js-lib';
2
+ export interface BaseEnv {
3
+ name: string;
4
+ }
5
+ export interface EnvSharedServiceCfg<ENV> {
3
6
  /**
4
7
  * Dir with ${envName}.env.ts files
5
8
  */
6
- envDir: string;
9
+ envMap: StringMap<ENV>;
7
10
  }
8
- export declare class EnvSharedService<ENV extends BaseEnv = any> {
9
- private cfg;
10
- constructor(cfg: EnvSharedServiceCfg);
11
+ export declare class EnvSharedService<ENV extends BaseEnv> {
12
+ cfg: EnvSharedServiceCfg<ENV>;
13
+ constructor(cfg: EnvSharedServiceCfg<ENV>);
11
14
  private env?;
12
15
  init(): void;
13
16
  getEnv(): ENV;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EnvSharedService = void 0;
4
+ const js_lib_1 = require("@naturalcycles/js-lib");
4
5
  const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
5
6
  class EnvSharedService {
6
7
  constructor(cfg) {
@@ -12,25 +13,17 @@ class EnvSharedService {
12
13
  getEnv() {
13
14
  if (!this.env) {
14
15
  const { APP_ENV } = process.env;
15
- if (!APP_ENV) {
16
- throw new Error('APP_ENV should be defined!');
17
- }
18
- const { envDir } = this.cfg;
19
- const envFilePath = `${envDir}/${APP_ENV}.env`;
20
- try {
21
- const module = require(envFilePath);
22
- this.env = module.default;
23
- }
24
- catch {
25
- throw new Error(`Cannot read envFile ${envFilePath}`);
26
- }
16
+ (0, js_lib_1._assert)(APP_ENV, 'APP_ENV should be defined!');
17
+ const env = this.cfg.envMap[APP_ENV];
18
+ (0, js_lib_1._assert)(env, `Environment ${APP_ENV} is not defined`);
19
+ this.env = env;
27
20
  console.log(`APP_ENV=${(0, nodejs_lib_1.dimGrey)(APP_ENV)} loaded`);
28
21
  }
29
22
  return this.env;
30
23
  }
31
24
  setEnv(env) {
32
- console.log(`setEnv APP_ENV=${(0, nodejs_lib_1.dimGrey)(env ? env.name : 'undefined')}`);
33
25
  this.env = env;
26
+ console.log(`setEnv APP_ENV=${(0, nodejs_lib_1.dimGrey)(env?.name || 'undefined')}`);
34
27
  }
35
28
  }
36
29
  exports.EnvSharedService = EnvSharedService;
package/dist/index.d.ts CHANGED
@@ -3,34 +3,33 @@ export * from './admin/adminMiddleware';
3
3
  export * from './admin/base.admin.service';
4
4
  export * from './admin/firebase.shared.service';
5
5
  export * from './admin/secureHeaderMiddleware';
6
- export * from './env/env.model';
7
6
  export * from './env/env.shared.service';
8
7
  export * from './gae/appEngine.util';
9
8
  export * from './sentry/sentry.shared.service';
9
+ export * from './server/appEngineLogMiddleware';
10
+ export * from './server/asyncLocalStorageMiddleware';
11
+ export * from './server/basicAuthMiddleware';
12
+ export * from './server/bodyParserTimeoutMiddleware';
10
13
  export * from './server/catchWrapper';
11
14
  export * from './server/createDefaultApp';
12
15
  export * from './server/createDefaultApp.model';
13
16
  export * from './server/deployInfo.util';
14
- export * from './server/getDefaultRouter';
15
- export * from './server/bodyParserTimeoutMiddleware';
16
17
  export * from './server/genericErrorMiddleware';
17
- export * from './server/serverStatsMiddleware';
18
+ export * from './server/getDefaultRouter';
18
19
  export * from './server/methodOverrideMiddleware';
19
20
  export * from './server/notFoundMiddleware';
20
21
  export * from './server/okMiddleware';
21
- export * from './server/basicAuthMiddleware';
22
+ export * from './server/request.log.util';
23
+ export * from './server/request.util';
22
24
  export * from './server/requestTimeoutMiddleware';
23
- export * from './server/validation/validateRequest';
24
- export * from './server/simpleRequestLoggerMiddleware';
25
+ export * from './server/safeJsonMiddleware';
26
+ export * from './server/server.model';
27
+ export * from './server/serverStatsMiddleware';
25
28
  export * from './server/serverStatusMiddleware';
26
- export * from './server/validation/validateMiddleware';
27
- export * from './server/validation/zodValidateMiddleware';
28
- export * from './server/request.log.util';
29
+ export * from './server/simpleRequestLoggerMiddleware';
29
30
  export * from './server/startServer';
30
31
  export * from './server/startServer.model';
31
- export * from './server/asyncLocalStorageMiddleware';
32
- export * from './server/server.model';
33
- export * from './server/appEngineLogMiddleware';
34
- export * from './server/safeJsonMiddleware';
35
- export * from './server/request.util';
32
+ export * from './server/validation/validateMiddleware';
33
+ export * from './server/validation/validateRequest';
34
+ export * from './server/validation/zodValidateMiddleware';
36
35
  export { onFinished };
package/dist/index.js CHANGED
@@ -8,33 +8,32 @@ tslib_1.__exportStar(require("./admin/adminMiddleware"), exports);
8
8
  tslib_1.__exportStar(require("./admin/base.admin.service"), exports);
9
9
  tslib_1.__exportStar(require("./admin/firebase.shared.service"), exports);
10
10
  tslib_1.__exportStar(require("./admin/secureHeaderMiddleware"), exports);
11
- tslib_1.__exportStar(require("./env/env.model"), exports);
12
11
  tslib_1.__exportStar(require("./env/env.shared.service"), exports);
13
12
  tslib_1.__exportStar(require("./gae/appEngine.util"), exports);
14
13
  tslib_1.__exportStar(require("./sentry/sentry.shared.service"), exports);
14
+ tslib_1.__exportStar(require("./server/appEngineLogMiddleware"), exports);
15
+ tslib_1.__exportStar(require("./server/asyncLocalStorageMiddleware"), exports);
16
+ tslib_1.__exportStar(require("./server/basicAuthMiddleware"), exports);
17
+ tslib_1.__exportStar(require("./server/bodyParserTimeoutMiddleware"), exports);
15
18
  tslib_1.__exportStar(require("./server/catchWrapper"), exports);
16
19
  tslib_1.__exportStar(require("./server/createDefaultApp"), exports);
17
20
  tslib_1.__exportStar(require("./server/createDefaultApp.model"), exports);
18
21
  tslib_1.__exportStar(require("./server/deployInfo.util"), exports);
19
- tslib_1.__exportStar(require("./server/getDefaultRouter"), exports);
20
- tslib_1.__exportStar(require("./server/bodyParserTimeoutMiddleware"), exports);
21
22
  tslib_1.__exportStar(require("./server/genericErrorMiddleware"), exports);
22
- tslib_1.__exportStar(require("./server/serverStatsMiddleware"), exports);
23
+ tslib_1.__exportStar(require("./server/getDefaultRouter"), exports);
23
24
  tslib_1.__exportStar(require("./server/methodOverrideMiddleware"), exports);
24
25
  tslib_1.__exportStar(require("./server/notFoundMiddleware"), exports);
25
26
  tslib_1.__exportStar(require("./server/okMiddleware"), exports);
26
- tslib_1.__exportStar(require("./server/basicAuthMiddleware"), exports);
27
+ tslib_1.__exportStar(require("./server/request.log.util"), exports);
28
+ tslib_1.__exportStar(require("./server/request.util"), exports);
27
29
  tslib_1.__exportStar(require("./server/requestTimeoutMiddleware"), exports);
28
- tslib_1.__exportStar(require("./server/validation/validateRequest"), exports);
29
- tslib_1.__exportStar(require("./server/simpleRequestLoggerMiddleware"), exports);
30
+ tslib_1.__exportStar(require("./server/safeJsonMiddleware"), exports);
31
+ tslib_1.__exportStar(require("./server/server.model"), exports);
32
+ tslib_1.__exportStar(require("./server/serverStatsMiddleware"), exports);
30
33
  tslib_1.__exportStar(require("./server/serverStatusMiddleware"), exports);
31
- tslib_1.__exportStar(require("./server/validation/validateMiddleware"), exports);
32
- tslib_1.__exportStar(require("./server/validation/zodValidateMiddleware"), exports);
33
- tslib_1.__exportStar(require("./server/request.log.util"), exports);
34
+ tslib_1.__exportStar(require("./server/simpleRequestLoggerMiddleware"), exports);
34
35
  tslib_1.__exportStar(require("./server/startServer"), exports);
35
36
  tslib_1.__exportStar(require("./server/startServer.model"), exports);
36
- tslib_1.__exportStar(require("./server/asyncLocalStorageMiddleware"), exports);
37
- tslib_1.__exportStar(require("./server/server.model"), exports);
38
- tslib_1.__exportStar(require("./server/appEngineLogMiddleware"), exports);
39
- tslib_1.__exportStar(require("./server/safeJsonMiddleware"), exports);
40
- tslib_1.__exportStar(require("./server/request.util"), exports);
37
+ tslib_1.__exportStar(require("./server/validation/validateMiddleware"), exports);
38
+ tslib_1.__exportStar(require("./server/validation/validateRequest"), exports);
39
+ tslib_1.__exportStar(require("./server/validation/zodValidateMiddleware"), exports);
@@ -98,8 +98,9 @@ class SentrySharedService {
98
98
  return;
99
99
  }
100
100
  if (data?.reportRate && // E.g rate of 0.1 means 10% of errors are reported
101
- Math.random() > data.reportRate)
101
+ Math.random() > data.reportRate) {
102
102
  return;
103
+ }
103
104
  // This is to avoid Sentry cutting err.message to 253 characters
104
105
  // It will log additional "breadcrumb object" before the error
105
106
  // It's a Breadcrumb, not a console.log, because console.log are NOT automatically attached as Breadcrumbs in cron-job environments (outside of Express)
@@ -58,7 +58,7 @@ function logToCI(args) {
58
58
  function appEngineLogMiddleware() {
59
59
  if (!isGAE || !GOOGLE_CLOUD_PROJECT) {
60
60
  // Local machine, return "simple" logToDev middleware with request numbering
61
- return function gaeLogMiddlewareDev(req, res, next) {
61
+ return function gaeLogMiddlewareDev(req, _res, next) {
62
62
  // Local machine
63
63
  req.requestId = String(++reqCounter);
64
64
  req.log = req.warn = req.error = (...args) => logToDev(req.requestId, args);
@@ -66,7 +66,7 @@ function appEngineLogMiddleware() {
66
66
  };
67
67
  }
68
68
  // Otherwise, we're in AppEngine
69
- return function appEngineLogHandler(req, res, next) {
69
+ return function appEngineLogHandler(req, _res, next) {
70
70
  const traceHeader = req.header('x-cloud-trace-context');
71
71
  if (traceHeader) {
72
72
  const [trace] = traceHeader.split('/');
@@ -14,7 +14,7 @@ const isCI = !!CI;
14
14
  // Create it lazily (on demand)
15
15
  const storage = (0, js_lib_1._lazyValue)(() => new node_async_hooks_1.AsyncLocalStorage());
16
16
  function asyncLocalStorageMiddleware() {
17
- return (req, res, next) => {
17
+ return (req, _res, next) => {
18
18
  const store = {
19
19
  req,
20
20
  };
@@ -35,7 +35,7 @@ function bodyParserTimeoutMiddleware(cfg = {}) {
35
35
  * Should be called AFTER bodyParser
36
36
  */
37
37
  function clearBodyParserTimeout() {
38
- return (req, res, next) => {
38
+ return (req, _res, next) => {
39
39
  clearTimeout(req.bodyParserTimeout);
40
40
  next();
41
41
  };
@@ -6,7 +6,7 @@ function methodOverrideMiddleware(cfg = {}) {
6
6
  methodKey: '_method',
7
7
  ...cfg,
8
8
  };
9
- return (req, res, next) => {
9
+ return (req, _res, next) => {
10
10
  if (req.query[methodKey]) {
11
11
  req.method = req.query[methodKey];
12
12
  // delete req.query[methodKey]
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.okMiddleware = okMiddleware;
4
4
  function okMiddleware() {
5
- return (req, res) => {
5
+ return (_req, res) => {
6
6
  res.json({ ok: 1 });
7
7
  };
8
8
  }
@@ -9,7 +9,7 @@ const js_lib_1 = require("@naturalcycles/js-lib");
9
9
  * Original: https://github.com/expressjs/express/blob/master/lib/response.js
10
10
  */
11
11
  function safeJsonMiddleware() {
12
- return function safeJsonHandler(req, res, next) {
12
+ return function safeJsonHandler(_req, res, next) {
13
13
  res.json = (input) => {
14
14
  if (!res.get('Content-Type')) {
15
15
  res.set('Content-Type', 'application/json');
@@ -1,5 +1,5 @@
1
1
  import type { CommonLogFunction, Promisable } from '@naturalcycles/js-lib';
2
- import type { IRouter, Request, NextFunction, Response, Application } from 'express';
2
+ import type { Application, IRouter, NextFunction, Request, Response } from 'express';
3
3
  /**
4
4
  * Use this interface instead of express.Request in cases when TypeScript gives an error, because it haven't "included" this very file.
5
5
  *
@@ -9,7 +9,7 @@ exports.enableDestroy = enableDestroy;
9
9
  function enableDestroy(server) {
10
10
  const connections = {};
11
11
  const srv = server;
12
- srv.on('connection', function (conn) {
12
+ srv.on('connection', conn => {
13
13
  const key = conn.remoteAddress + ':' + conn.remotePort;
14
14
  connections[key] = conn;
15
15
  conn.on('close', () => delete connections[key]);
@@ -8,7 +8,7 @@ const deployInfo_util_1 = require("./deployInfo.util");
8
8
  const { versions } = process;
9
9
  const { GAE_APPLICATION, GAE_SERVICE, GAE_VERSION, APP_ENV, NODE_OPTIONS } = process.env;
10
10
  function serverStatusMiddleware(projectDir, extra) {
11
- return async (req, res) => {
11
+ return async (_req, res) => {
12
12
  res.json(getServerStatusData(projectDir, extra));
13
13
  };
14
14
  }
@@ -10,7 +10,7 @@ function simpleRequestLoggerMiddleware(_cfg = {}) {
10
10
  // Disable logger in AppEngine, as it doesn't make sense there
11
11
  // UPD: Only log in dev environment
12
12
  if (APP_ENV !== 'dev')
13
- return (req, res, next) => next();
13
+ return (_req, _res, next) => next();
14
14
  const cfg = {
15
15
  logStart: false,
16
16
  logFinish: true,
@@ -26,7 +26,7 @@ function validateObject(prop, schema, opt = {}) {
26
26
  objectName: `request ${prop}`,
27
27
  });
28
28
  const reportPredicate = typeof opt.report === 'function' ? opt.report : () => opt.report;
29
- return (req, res, next) => {
29
+ return (req, _res, next) => {
30
30
  const error = ajvSchema.getValidationError(req[prop]);
31
31
  if (error) {
32
32
  const report = reportPredicate(error);
@@ -11,7 +11,7 @@ const REDACTED = 'REDACTED';
11
11
  */
12
12
  function zodReqValidate(prop, schema, opt = {}) {
13
13
  const reportPredicate = typeof opt.report === 'function' ? opt.report : () => opt.report;
14
- return (req, res, next) => {
14
+ return (req, _res, next) => {
15
15
  const { error } = (0, js_lib_1.zSafeValidate)(req[prop], schema);
16
16
  if (!error) {
17
17
  return next();
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
- "version": "5.7.1",
3
+ "version": "5.8.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
+ "build": "dev-lib build",
7
+ "test": "dev-lib test",
8
+ "lint": "dev-lib lint",
9
+ "bt": "dev-lib bt",
10
+ "lbt": "dev-lib lbt",
6
11
  "dev": "APP_ENV=dev node -r ts-node/register --watch ./src/test/server/server.ts",
7
12
  "docs-serve": "NODE_OPTIONS=--openssl-legacy-provider vuepress dev docs",
8
13
  "docs-build": "NODE_OPTIONS=--openssl-legacy-provider vuepress build docs",
@@ -37,10 +42,10 @@
37
42
  },
38
43
  "devDependencies": {
39
44
  "@naturalcycles/bench-lib": "^3.0.0",
40
- "@naturalcycles/dev-lib": "^13.0.0",
45
+ "@naturalcycles/dev-lib": "^15.0.4",
41
46
  "@sentry/node": "^7.0.0",
42
47
  "@types/ejs": "^3.0.0",
43
- "@types/node": "^20.1.0",
48
+ "@types/node": "^22.2.0",
44
49
  "@types/yargs": "^16.0.0",
45
50
  "fastify": "^4.0.0",
46
51
  "jest": "^29.0.1"
@@ -71,7 +76,7 @@
71
76
  "url": "https://github.com/NaturalCycles/backend-lib"
72
77
  },
73
78
  "engines": {
74
- "node": ">=18.12.0"
79
+ "node": ">=20.12.0"
75
80
  },
76
81
  "type": "commonjs",
77
82
  "description": "Standard library for making Express.js / AppEngine based backend services",
@@ -88,7 +88,7 @@ export function loginHtml(firebaseServiceCfg: FirebaseSharedServiceCfg): Backend
88
88
  adminAuthProvider: firebaseAuthProvider = 'GoogleAuthProvider',
89
89
  } = firebaseServiceCfg
90
90
 
91
- return (req, res) => {
91
+ return (_req, res) => {
92
92
  res.send(
93
93
  getLoginHtml({
94
94
  firebaseApiKey,
@@ -171,7 +171,7 @@ export class BaseAdminService {
171
171
  req: BackendRequest,
172
172
  reqPermissions: string[] = [],
173
173
  meta: Record<string, any> = {},
174
- andComparison: boolean = true,
174
+ andComparison = true,
175
175
  ): Promise<AdminInfo> {
176
176
  if (!this.cfg.authEnabled) return adminInfoDisabled()
177
177
 
@@ -42,8 +42,9 @@ function requireSecureHeaderOrAdmin(
42
42
 
43
43
  // Header provided - don't check for Admin
44
44
  if (providedHeader) {
45
- if (!secureHeaderValue || timingSafeStringEqual(providedHeader, secureHeaderValue))
45
+ if (!secureHeaderValue || timingSafeStringEqual(providedHeader, secureHeaderValue)) {
46
46
  return next()
47
+ }
47
48
 
48
49
  return next(
49
50
  new AppError('secureHeader or adminToken is required', {
@@ -63,13 +63,13 @@ export function httpDBRequestHandler(db: CommonDB): BackendRouter {
63
63
  })
64
64
 
65
65
  // ping
66
- router.get('/ping', async (req, res) => {
66
+ router.get('/ping', async (_req, res) => {
67
67
  await db.ping()
68
68
  res.end()
69
69
  })
70
70
 
71
71
  // getTables
72
- router.get('/tables', async (req, res) => {
72
+ router.get('/tables', async (_req, res) => {
73
73
  res.json(await db.getTables())
74
74
  })
75
75
 
@@ -38,7 +38,7 @@ const backendCfgSchema = AjvSchema.readJsonSync<BackendCfg>(
38
38
  },
39
39
  )
40
40
 
41
- export function getBackendCfg(projectDir: string = '.'): BackendCfg {
41
+ export function getBackendCfg(projectDir = '.'): BackendCfg {
42
42
  const backendCfgYamlPath = `${projectDir}/backend.cfg.yaml`
43
43
 
44
44
  requireFileToExist(backendCfgYamlPath)
@@ -1,4 +1,3 @@
1
- import { buildProdCommand } from '@naturalcycles/dev-lib'
2
1
  import { _anyToError, _objectAssign, pRetry } from '@naturalcycles/js-lib'
3
2
  import { appendToGithubSummary, execVoidCommandSync } from '@naturalcycles/nodejs-lib'
4
3
  import { getBackendCfg } from './backend.cfg.util'
@@ -11,9 +10,9 @@ export interface DeployGaeOptions extends DeployPrepareOptions, DeployHealthChec
11
10
  export async function deployGae(opt: DeployGaeOptions = {}): Promise<void> {
12
11
  const { logOnFailure, logOnSuccess } = opt
13
12
 
14
- // 1. build-prod
13
+ // 1. build
15
14
 
16
- buildProdCommand()
15
+ execVoidCommandSync('yarn', ['build'])
17
16
 
18
17
  // 2. deploy-prepare
19
18
 
@@ -1,6 +1,6 @@
1
1
  import { inspect, InspectOptions } from 'node:util'
2
- import { pDelay, _filterFalsyValues, _ms, _since, getFetcher } from '@naturalcycles/js-lib'
3
- import { execVoidCommandSync, dimGrey, red } from '@naturalcycles/nodejs-lib'
2
+ import { _filterFalsyValues, _ms, _since, getFetcher, pDelay } from '@naturalcycles/js-lib'
3
+ import { dimGrey, execVoidCommandSync, red } from '@naturalcycles/nodejs-lib'
4
4
  import { coloredHttpCode } from '../server/request.log.util'
5
5
 
6
6
  export interface DeployHealthCheckOptions {
@@ -5,13 +5,13 @@ import { deployGae } from './deployGae'
5
5
  import { deployHealthCheck, DeployHealthCheckOptions } from './deployHealthCheck'
6
6
  import { deployPrepare } from './deployPrepare'
7
7
 
8
- export type { BackendCfg, DeployInfo, DeployHealthCheckOptions }
8
+ export type { BackendCfg, DeployHealthCheckOptions, DeployInfo }
9
9
 
10
10
  export {
11
- getBackendCfg,
12
- createDeployInfo,
13
11
  createAppYaml,
12
+ createDeployInfo,
14
13
  deployGae,
15
- deployPrepare,
16
14
  deployHealthCheck,
15
+ deployPrepare,
16
+ getBackendCfg,
17
17
  }
@@ -1,15 +1,19 @@
1
+ import { _assert, StringMap } from '@naturalcycles/js-lib'
1
2
  import { dimGrey } from '@naturalcycles/nodejs-lib'
2
- import { BaseEnv } from './env.model'
3
3
 
4
- export interface EnvSharedServiceCfg {
4
+ export interface BaseEnv {
5
+ name: string
6
+ }
7
+
8
+ export interface EnvSharedServiceCfg<ENV> {
5
9
  /**
6
10
  * Dir with ${envName}.env.ts files
7
11
  */
8
- envDir: string
12
+ envMap: StringMap<ENV>
9
13
  }
10
14
 
11
- export class EnvSharedService<ENV extends BaseEnv = any> {
12
- constructor(private cfg: EnvSharedServiceCfg) {}
15
+ export class EnvSharedService<ENV extends BaseEnv> {
16
+ constructor(public cfg: EnvSharedServiceCfg<ENV>) {}
13
17
 
14
18
  private env?: ENV
15
19
 
@@ -20,28 +24,20 @@ export class EnvSharedService<ENV extends BaseEnv = any> {
20
24
  getEnv(): ENV {
21
25
  if (!this.env) {
22
26
  const { APP_ENV } = process.env
23
- if (!APP_ENV) {
24
- throw new Error('APP_ENV should be defined!')
25
- }
26
-
27
- const { envDir } = this.cfg
28
- const envFilePath = `${envDir}/${APP_ENV}.env`
27
+ _assert(APP_ENV, 'APP_ENV should be defined!')
29
28
 
30
- try {
31
- const module = require(envFilePath)
32
- this.env = module.default
33
- } catch {
34
- throw new Error(`Cannot read envFile ${envFilePath}`)
35
- }
29
+ const env = this.cfg.envMap[APP_ENV]
30
+ _assert(env, `Environment ${APP_ENV} is not defined`)
36
31
 
32
+ this.env = env
37
33
  console.log(`APP_ENV=${dimGrey(APP_ENV)} loaded`)
38
34
  }
39
35
 
40
- return this.env!
36
+ return this.env
41
37
  }
42
38
 
43
39
  setEnv(env?: ENV): void {
44
- console.log(`setEnv APP_ENV=${dimGrey(env ? env.name : 'undefined')}`)
45
40
  this.env = env
41
+ console.log(`setEnv APP_ENV=${dimGrey(env?.name || 'undefined')}`)
46
42
  }
47
43
  }
package/src/index.ts CHANGED
@@ -3,35 +3,34 @@ export * from './admin/adminMiddleware'
3
3
  export * from './admin/base.admin.service'
4
4
  export * from './admin/firebase.shared.service'
5
5
  export * from './admin/secureHeaderMiddleware'
6
- export * from './env/env.model'
7
6
  export * from './env/env.shared.service'
8
7
  export * from './gae/appEngine.util'
9
8
  export * from './sentry/sentry.shared.service'
9
+ export * from './server/appEngineLogMiddleware'
10
+ export * from './server/asyncLocalStorageMiddleware'
11
+ export * from './server/basicAuthMiddleware'
12
+ export * from './server/bodyParserTimeoutMiddleware'
10
13
  export * from './server/catchWrapper'
11
14
  export * from './server/createDefaultApp'
12
15
  export * from './server/createDefaultApp.model'
13
16
  export * from './server/deployInfo.util'
14
- export * from './server/getDefaultRouter'
15
- export * from './server/bodyParserTimeoutMiddleware'
16
17
  export * from './server/genericErrorMiddleware'
17
- export * from './server/serverStatsMiddleware'
18
+ export * from './server/getDefaultRouter'
18
19
  export * from './server/methodOverrideMiddleware'
19
20
  export * from './server/notFoundMiddleware'
20
21
  export * from './server/okMiddleware'
21
- export * from './server/basicAuthMiddleware'
22
+ export * from './server/request.log.util'
23
+ export * from './server/request.util'
22
24
  export * from './server/requestTimeoutMiddleware'
23
- export * from './server/validation/validateRequest'
24
- export * from './server/simpleRequestLoggerMiddleware'
25
+ export * from './server/safeJsonMiddleware'
26
+ export * from './server/server.model'
27
+ export * from './server/serverStatsMiddleware'
25
28
  export * from './server/serverStatusMiddleware'
26
- export * from './server/validation/validateMiddleware'
27
- export * from './server/validation/zodValidateMiddleware'
28
- export * from './server/request.log.util'
29
+ export * from './server/simpleRequestLoggerMiddleware'
29
30
  export * from './server/startServer'
30
31
  export * from './server/startServer.model'
31
- export * from './server/asyncLocalStorageMiddleware'
32
- export * from './server/server.model'
33
- export * from './server/appEngineLogMiddleware'
34
- export * from './server/safeJsonMiddleware'
35
- export * from './server/request.util'
32
+ export * from './server/validation/validateMiddleware'
33
+ export * from './server/validation/validateRequest'
34
+ export * from './server/validation/zodValidateMiddleware'
36
35
 
37
36
  export { onFinished }
@@ -8,9 +8,9 @@ import {
8
8
  StringMap,
9
9
  } from '@naturalcycles/js-lib'
10
10
  import { _inspect, InspectAnyOptions } from '@naturalcycles/nodejs-lib'
11
- // eslint-disable-next-line import/no-duplicates
11
+ // eslint-disable-next-line import-x/no-duplicates
12
12
  import type { Breadcrumb, NodeOptions, SeverityLevel } from '@sentry/node'
13
- // eslint-disable-next-line import/no-duplicates
13
+ // eslint-disable-next-line import-x/no-duplicates
14
14
  import type * as SentryLib from '@sentry/node'
15
15
  import { BackendErrorRequestHandler, BackendRequestHandler, getRequestLogger } from '../index'
16
16
 
@@ -126,8 +126,9 @@ export class SentrySharedService {
126
126
  if (
127
127
  data?.reportRate && // E.g rate of 0.1 means 10% of errors are reported
128
128
  Math.random() > data.reportRate
129
- )
129
+ ) {
130
130
  return
131
+ }
131
132
 
132
133
  // This is to avoid Sentry cutting err.message to 253 characters
133
134
  // It will log additional "breadcrumb object" before the error
@@ -1,6 +1,6 @@
1
1
  import { inspect } from 'node:util'
2
2
  import { AnyObject, CommonLogger } from '@naturalcycles/js-lib'
3
- import { dimGrey, _inspect } from '@naturalcycles/nodejs-lib'
3
+ import { _inspect, dimGrey } from '@naturalcycles/nodejs-lib'
4
4
  import { BackendRequestHandler } from './server.model'
5
5
 
6
6
  const { GOOGLE_CLOUD_PROJECT, GAE_INSTANCE } = process.env
@@ -69,7 +69,7 @@ function logToCI(args: any[]): void {
69
69
  export function appEngineLogMiddleware(): BackendRequestHandler {
70
70
  if (!isGAE || !GOOGLE_CLOUD_PROJECT) {
71
71
  // Local machine, return "simple" logToDev middleware with request numbering
72
- return function gaeLogMiddlewareDev(req, res, next) {
72
+ return function gaeLogMiddlewareDev(req, _res, next) {
73
73
  // Local machine
74
74
  req.requestId = String(++reqCounter)
75
75
  req.log = req.warn = req.error = (...args: any[]) => logToDev(req.requestId!, args)
@@ -79,7 +79,7 @@ export function appEngineLogMiddleware(): BackendRequestHandler {
79
79
 
80
80
  // Otherwise, we're in AppEngine
81
81
 
82
- return function appEngineLogHandler(req, res, next) {
82
+ return function appEngineLogHandler(req, _res, next) {
83
83
  const traceHeader = req.header('x-cloud-trace-context')
84
84
  if (traceHeader) {
85
85
  const [trace] = traceHeader.split('/')
@@ -1,6 +1,6 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks'
2
2
  import { _lazyValue, CommonLogger } from '@naturalcycles/js-lib'
3
- import { gaeLogger, devLogger, ciLogger } from './appEngineLogMiddleware'
3
+ import { ciLogger, devLogger, gaeLogger } from './appEngineLogMiddleware'
4
4
  import { BackendRequest, BackendRequestHandler } from './server.model'
5
5
 
6
6
  const { GAE_INSTANCE, CI } = process.env
@@ -16,7 +16,7 @@ export interface RequestLocalStorage {
16
16
  const storage = _lazyValue(() => new AsyncLocalStorage<RequestLocalStorage>())
17
17
 
18
18
  export function asyncLocalStorageMiddleware(): BackendRequestHandler {
19
- return (req, res, next) => {
19
+ return (req, _res, next) => {
20
20
  const store: RequestLocalStorage = {
21
21
  req,
22
22
  }
@@ -60,7 +60,7 @@ export function bodyParserTimeoutMiddleware(
60
60
  * Should be called AFTER bodyParser
61
61
  */
62
62
  export function clearBodyParserTimeout(): BackendRequestHandler {
63
- return (req, res, next) => {
63
+ return (req, _res, next) => {
64
64
  clearTimeout(req.bodyParserTimeout)
65
65
  next()
66
66
  }
@@ -5,9 +5,9 @@ import { BackendApplication, isGAE, methodOverrideMiddleware } from '..'
5
5
  import { appEngineLogMiddleware } from './appEngineLogMiddleware'
6
6
  import { asyncLocalStorageMiddleware } from './asyncLocalStorageMiddleware'
7
7
  import {
8
- DefaultAppCfg,
9
8
  BackendRequestHandlerCfg,
10
9
  BackendRequestHandlerWithPath,
10
+ DefaultAppCfg,
11
11
  } from './createDefaultApp.model'
12
12
  import { genericErrorMiddleware } from './genericErrorMiddleware'
13
13
  import { notFoundMiddleware } from './notFoundMiddleware'
@@ -15,7 +15,7 @@ export function methodOverrideMiddleware(
15
15
  ...cfg,
16
16
  }
17
17
 
18
- return (req, res, next) => {
18
+ return (req, _res, next) => {
19
19
  if (req.query[methodKey]) {
20
20
  req.method = req.query[methodKey] as string
21
21
  // delete req.query[methodKey]
@@ -1,7 +1,7 @@
1
1
  import { BackendRequestHandler } from './server.model'
2
2
 
3
3
  export function okMiddleware(): BackendRequestHandler {
4
- return (req, res) => {
4
+ return (_req, res) => {
5
5
  res.json({ ok: 1 })
6
6
  }
7
7
  }
@@ -8,7 +8,7 @@ import { BackendRequestHandler, BackendResponse } from './server.model'
8
8
  * Original: https://github.com/expressjs/express/blob/master/lib/response.js
9
9
  */
10
10
  export function safeJsonMiddleware(): BackendRequestHandler {
11
- return function safeJsonHandler(req, res, next) {
11
+ return function safeJsonHandler(_req, res, next) {
12
12
  res.json = (input: any): BackendResponse => {
13
13
  if (!res.get('Content-Type')) {
14
14
  res.set('Content-Type', 'application/json')
@@ -1,5 +1,5 @@
1
1
  import type { CommonLogFunction, Promisable } from '@naturalcycles/js-lib'
2
- import type { IRouter, Request, NextFunction, Response, Application } from 'express'
2
+ import type { Application, IRouter, NextFunction, Request, Response } from 'express'
3
3
 
4
4
  /**
5
5
  * Use this interface instead of express.Request in cases when TypeScript gives an error, because it haven't "included" this very file.
@@ -15,7 +15,7 @@ export function enableDestroy(server: Server): DestroyableServer {
15
15
  const connections: StringMap<Socket> = {}
16
16
  const srv = server as DestroyableServer
17
17
 
18
- srv.on('connection', function (conn) {
18
+ srv.on('connection', conn => {
19
19
  const key = conn.remoteAddress + ':' + conn.remotePort
20
20
  connections[key] = conn
21
21
  conn.on('close', () => delete connections[key])
@@ -7,7 +7,7 @@ const { versions } = process
7
7
  const { GAE_APPLICATION, GAE_SERVICE, GAE_VERSION, APP_ENV, NODE_OPTIONS } = process.env
8
8
 
9
9
  export function serverStatusMiddleware(projectDir?: string, extra?: any): BackendRequestHandler {
10
- return async (req, res) => {
10
+ return async (_req, res) => {
11
11
  res.json(getServerStatusData(projectDir, extra))
12
12
  }
13
13
  }
@@ -22,7 +22,7 @@ export function simpleRequestLoggerMiddleware(
22
22
  ): BackendRequestHandler {
23
23
  // Disable logger in AppEngine, as it doesn't make sense there
24
24
  // UPD: Only log in dev environment
25
- if (APP_ENV !== 'dev') return (req, res, next) => next()
25
+ if (APP_ENV !== 'dev') return (_req, _res, next) => next()
26
26
 
27
27
  const cfg: SimpleRequestLoggerMiddlewareCfg = {
28
28
  logStart: false,
@@ -1,4 +1,4 @@
1
- import { JsonSchema, JsonSchemaBuilder, _get, AppError } from '@naturalcycles/js-lib'
1
+ import { _get, AppError, JsonSchema, JsonSchemaBuilder } from '@naturalcycles/js-lib'
2
2
  import { AjvSchema, AjvValidationError } from '@naturalcycles/nodejs-lib'
3
3
  import { BackendRequestHandler } from '../server.model'
4
4
  import { ReqValidationOptions } from './validateRequest'
@@ -44,7 +44,7 @@ function validateObject(
44
44
  const reportPredicate =
45
45
  typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined
46
46
 
47
- return (req, res, next) => {
47
+ return (req, _res, next) => {
48
48
  const error = ajvSchema.getValidationError(req[prop])
49
49
  if (error) {
50
50
  const report = reportPredicate(error)
@@ -18,7 +18,7 @@ export function zodReqValidate(
18
18
  const reportPredicate =
19
19
  typeof opt.report === 'function' ? opt.report : () => opt.report as boolean | undefined
20
20
 
21
- return (req, res, next) => {
21
+ return (req, _res, next) => {
22
22
  const { error } = zSafeValidate(req[prop], schema)
23
23
  if (!error) {
24
24
  return next()
@@ -1,3 +0,0 @@
1
- export interface BaseEnv {
2
- name: string;
3
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +0,0 @@
1
- export interface BaseEnv {
2
- name: string
3
- }