@naturalcycles/backend-lib 4.23.4 → 5.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.
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getLoginHtmlRedirect = exports.loginHtml = exports.requireAdminPermissions = exports.createAdminMiddleware = void 0;
4
4
  const tslib_1 = require("tslib");
5
- const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
6
5
  const js_lib_1 = require("@naturalcycles/js-lib");
6
+ const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
7
7
  const ejs_1 = tslib_1.__importDefault(require("ejs"));
8
8
  function createAdminMiddleware(adminService, cfgDefaults = {}) {
9
9
  return (reqPermissions, cfg) => requireAdminPermissions(adminService, reqPermissions, {
@@ -53,7 +53,7 @@ function loginHtml(firebaseServiceCfg) {
53
53
  exports.loginHtml = loginHtml;
54
54
  const getLoginHtml = (0, js_lib_1._memoFn)((cfg) => {
55
55
  console.log(`reading login.html`);
56
- const tmpl = node_fs_1.default.readFileSync(`${__dirname}/login.html`, 'utf8');
56
+ const tmpl = nodejs_lib_1.fs2.readText(`${__dirname}/login.html`);
57
57
  return ejs_1.default.render(tmpl, cfg);
58
58
  });
59
59
  function getLoginHtmlRedirect(href) {
@@ -7,19 +7,6 @@ export interface BackendCfg {
7
7
  */
8
8
  gaeService: string;
9
9
  gaeServiceByBranch?: StringMap;
10
- /**
11
- * @default true
12
- *
13
- * If true - service name will look like ${branchName}--${gaeService}, similar to Netlify.
14
- * If false - ${gaeService}.
15
- *
16
- * Prod branch NEVER includes branchName in service name.
17
- */
18
- serviceWithBranchName?: boolean;
19
- /**
20
- * @example prod
21
- */
22
- prodBranch: string;
23
10
  /**
24
11
  * List of file patterns to include in deployment.
25
12
  */
@@ -10,7 +10,6 @@ function getBackendCfg(projectDir = '.') {
10
10
  const backendCfgYamlPath = `${projectDir}/backend.cfg.yaml`;
11
11
  (0, nodejs_lib_1.requireFileToExist)(backendCfgYamlPath);
12
12
  const backendCfg = {
13
- serviceWithBranchName: true,
14
13
  ...nodejs_lib_1.fs2.readYaml(backendCfgYamlPath),
15
14
  };
16
15
  backendCfgSchema.validate(backendCfg);
@@ -7,7 +7,6 @@ export interface DeployInfo {
7
7
  serviceUrl: string;
8
8
  gitRev: string;
9
9
  gitBranch: string;
10
- prod: boolean;
11
10
  /**
12
11
  * Unix timestamp of deployInfo.json being generated.
13
12
  */
@@ -1,11 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateGAEServiceName = exports.createAppYaml = exports.createAndSaveAppYaml = exports.createDeployInfo = exports.createAndSaveDeployInfo = void 0;
4
- const tslib_1 = require("tslib");
5
- const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
6
4
  const js_lib_1 = require("@naturalcycles/js-lib");
7
5
  const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
8
- const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
9
6
  const APP_YAML_DEFAULT = () => ({
10
7
  runtime: 'nodejs20',
11
8
  service: 'default',
@@ -27,7 +24,7 @@ const APP_YAML_DEFAULT = () => ({
27
24
  async function createAndSaveDeployInfo(backendCfg, targetDir) {
28
25
  const deployInfo = await createDeployInfo(backendCfg);
29
26
  const deployInfoPath = `${targetDir}/deployInfo.json`;
30
- node_fs_1.default.writeFileSync(deployInfoPath, JSON.stringify(deployInfo, null, 2));
27
+ nodejs_lib_1.fs2.writeJson(deployInfoPath, deployInfo, { spaces: 2 });
31
28
  console.log(`saved ${(0, nodejs_lib_1.dimGrey)(deployInfoPath)}`);
32
29
  return deployInfo;
33
30
  }
@@ -38,11 +35,12 @@ async function createDeployInfo(backendCfg, overrideBranch) {
38
35
  const now = (0, js_lib_1.localTimeNow)();
39
36
  const gitBranch = overrideBranch || (await git.status()).current;
40
37
  const gitRev = (await git.revparse(['HEAD'])).slice(0, 7);
41
- let { gaeProject, gaeProjectByBranch = {}, gaeService, gaeServiceByBranch = {}, serviceWithBranchName, prodBranch, branchesWithTimestampVersions = [], } = backendCfg;
38
+ let { gaeProject, gaeProjectByBranch = {}, gaeService, gaeServiceByBranch = {}, branchesWithTimestampVersions = [], } = backendCfg;
42
39
  gaeProject = gaeProjectByBranch[gitBranch] || gaeProject;
43
- gaeService = validateGAEServiceName(gaeServiceByBranch[gitBranch] || gaeService);
44
- const prod = gitBranch === prodBranch;
45
- if (!prod && serviceWithBranchName && !gaeServiceByBranch[gitBranch]) {
40
+ if (gaeServiceByBranch[gitBranch]) {
41
+ gaeService = validateGAEServiceName(gaeServiceByBranch[gitBranch]);
42
+ }
43
+ else {
46
44
  gaeService = validateGAEServiceName([gitBranch, gaeService].join('--'));
47
45
  }
48
46
  let gaeVersion = '1';
@@ -67,7 +65,6 @@ async function createDeployInfo(backendCfg, overrideBranch) {
67
65
  serviceUrl,
68
66
  gitBranch,
69
67
  gitRev,
70
- prod,
71
68
  ts: now.unix(),
72
69
  };
73
70
  console.log({ deployInfo });
@@ -77,7 +74,7 @@ exports.createDeployInfo = createDeployInfo;
77
74
  function createAndSaveAppYaml(backendCfg, deployInfo, projectDir, targetDir, appYamlPassEnv = '') {
78
75
  const appYaml = createAppYaml(backendCfg, deployInfo, projectDir, appYamlPassEnv);
79
76
  const appYamlPath = `${targetDir}/app.yaml`;
80
- node_fs_1.default.writeFileSync(appYamlPath, js_yaml_1.default.dump(appYaml));
77
+ nodejs_lib_1.fs2.writeYaml(appYamlPath, appYaml);
81
78
  console.log(`saved ${(0, nodejs_lib_1.dimGrey)(appYamlPath)}`);
82
79
  return appYaml;
83
80
  }
@@ -93,14 +90,14 @@ function createAppYaml(backendCfg, deployInfo, projectDir, appYamlPassEnv = '')
93
90
  const appYaml = APP_YAML_DEFAULT();
94
91
  // Check existing app.yaml
95
92
  const appYamlPath = `${projectDir}/app.yaml`;
96
- if (node_fs_1.default.existsSync(appYamlPath)) {
93
+ if (nodejs_lib_1.fs2.pathExists(appYamlPath)) {
97
94
  console.log(`merging-in ${(0, nodejs_lib_1.dimGrey)(appYamlPath)}`);
98
- (0, js_lib_1._merge)(appYaml, js_yaml_1.default.load(node_fs_1.default.readFileSync(appYamlPath, 'utf8')));
95
+ (0, js_lib_1._merge)(appYaml, nodejs_lib_1.fs2.readYaml(appYamlPath));
99
96
  }
100
97
  const appEnvYamlPath = `${projectDir}/app.${APP_ENV}.yaml`;
101
- if (node_fs_1.default.existsSync(appEnvYamlPath)) {
98
+ if (nodejs_lib_1.fs2.pathExists(appEnvYamlPath)) {
102
99
  console.log(`merging-in ${(0, nodejs_lib_1.dimGrey)(appEnvYamlPath)}`);
103
- (0, js_lib_1._merge)(appYaml, js_yaml_1.default.load(node_fs_1.default.readFileSync(appEnvYamlPath, 'utf8')));
100
+ (0, js_lib_1._merge)(appYaml, nodejs_lib_1.fs2.readYaml(appEnvYamlPath));
104
101
  }
105
102
  // appYamlPassEnv
106
103
  require('dotenv').config(); // ensure .env is read
@@ -66,11 +66,11 @@ exports.deployGae = deployGae;
66
66
  async function undeployGae(branch) {
67
67
  const projectDir = '.';
68
68
  const backendCfg = (0, backend_cfg_util_1.getBackendCfg)(projectDir);
69
- const { gaeProject, gaeService, gaeVersion, prod } = await (0, deploy_util_1.createDeployInfo)(backendCfg, branch);
70
- if (prod) {
71
- console.log(`undeployGae (branch: ${branch}): not removing prod version (safety check)`);
72
- return;
73
- }
69
+ const { gaeProject, gaeService, gaeVersion } = await (0, deploy_util_1.createDeployInfo)(backendCfg, branch);
70
+ // if (prod) {
71
+ // console.log(`undeployGae (branch: ${branch}): not removing prod version (safety check)`)
72
+ // return
73
+ // }
74
74
  console.log(`undeployGae (branch: ${branch}): going to remove ${gaeProject}/${gaeService}/${gaeVersion}`);
75
75
  (0, nodejs_lib_1.execVoidCommandSync)(`gcloud app versions delete --project ${gaeProject} --service ${gaeService} ${gaeVersion} --quiet`, [], { shell: true });
76
76
  }
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDeployInfo = void 0;
4
- const tslib_1 = require("tslib");
5
- const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
6
4
  const js_lib_1 = require("@naturalcycles/js-lib");
5
+ const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
7
6
  exports.getDeployInfo = (0, js_lib_1._memoFn)((projectDir) => {
8
7
  const deployInfoPath = `${projectDir}/deployInfo.json`;
9
8
  try {
10
- return JSON.parse(node_fs_1.default.readFileSync(deployInfoPath, 'utf8'));
9
+ return nodejs_lib_1.fs2.readJson(deployInfoPath);
11
10
  }
12
11
  catch {
13
12
  // console.error(`cannot read ${deployInfoPath}, returning empty version`)
@@ -23,7 +22,6 @@ function getDeployInfoStub(stub = '') {
23
22
  versionUrl: stub,
24
23
  gitBranch: stub,
25
24
  gitRev: stub,
26
- prod: false,
27
25
  ts: Math.floor(Date.now() / 1000),
28
26
  };
29
27
  }
@@ -13,7 +13,7 @@ function serverStatusMiddleware(projectDir, extra) {
13
13
  }
14
14
  exports.serverStatusMiddleware = serverStatusMiddleware;
15
15
  function getServerStatusData(projectDir = process.cwd(), extra) {
16
- const { gitRev, gitBranch, prod, ts } = (0, deployInfo_util_1.getDeployInfo)(projectDir);
16
+ const { gitRev, gitBranch, ts } = (0, deployInfo_util_1.getDeployInfo)(projectDir);
17
17
  const t = (0, js_lib_1.localTime)(ts);
18
18
  const deployBuildTime = t.toPretty();
19
19
  const buildInfo = [t.toStringCompact(), gitBranch, gitRev].filter(Boolean).join('_');
@@ -21,7 +21,6 @@ function getServerStatusData(projectDir = process.cwd(), extra) {
21
21
  started: getStartedStr(),
22
22
  deployBuildTime,
23
23
  APP_ENV,
24
- prod,
25
24
  buildInfo,
26
25
  GAE_APPLICATION,
27
26
  GAE_SERVICE,
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
- "version": "4.23.4",
3
+ "version": "5.0.0",
4
4
  "scripts": {
5
- "prepare": "husky install",
6
- "serve": "APP_ENV=dev nodemon",
5
+ "prepare": "husky",
6
+ "dev": "APP_ENV=dev nodemon",
7
7
  "docs-serve": "NODE_OPTIONS=--openssl-legacy-provider vuepress dev docs",
8
8
  "docs-build": "NODE_OPTIONS=--openssl-legacy-provider vuepress build docs",
9
9
  "deploy-gae": "yarn tsn ./src/bin/deploy-gae.ts",
@@ -17,8 +17,6 @@
17
17
  ".*": { "type": "string" }
18
18
  }
19
19
  },
20
- "serviceWithBranchName": { "type": "boolean", "default": true },
21
- "prodBranch": { "type": "string" },
22
20
  "files": {
23
21
  "type": "array",
24
22
  "items": { "type": "string" }
@@ -1,5 +1,5 @@
1
- import fs from 'node:fs'
2
1
  import { _memoFn, AppError } from '@naturalcycles/js-lib'
2
+ import { fs2 } from '@naturalcycles/nodejs-lib'
3
3
  import ejs from 'ejs'
4
4
  import { BackendRequestHandler } from '../server/server.model'
5
5
  import { BaseAdminService } from './base.admin.service'
@@ -101,7 +101,7 @@ export function loginHtml(firebaseServiceCfg: FirebaseSharedServiceCfg): Backend
101
101
 
102
102
  const getLoginHtml = _memoFn((cfg: LoginHtmlCfg) => {
103
103
  console.log(`reading login.html`)
104
- const tmpl = fs.readFileSync(`${__dirname}/login.html`, 'utf8')
104
+ const tmpl = fs2.readText(`${__dirname}/login.html`)
105
105
  return ejs.render(tmpl, cfg)
106
106
  })
107
107
 
@@ -4,31 +4,14 @@ import { resourcesDir } from '../paths.cnst'
4
4
 
5
5
  export interface BackendCfg {
6
6
  gaeProject: string
7
-
8
7
  gaeProjectByBranch?: StringMap
9
8
 
10
9
  /**
11
10
  * @example default
12
11
  */
13
12
  gaeService: string
14
-
15
13
  gaeServiceByBranch?: StringMap
16
14
 
17
- /**
18
- * @default true
19
- *
20
- * If true - service name will look like ${branchName}--${gaeService}, similar to Netlify.
21
- * If false - ${gaeService}.
22
- *
23
- * Prod branch NEVER includes branchName in service name.
24
- */
25
- serviceWithBranchName?: boolean
26
-
27
- /**
28
- * @example prod
29
- */
30
- prodBranch: string
31
-
32
15
  /**
33
16
  * List of file patterns to include in deployment.
34
17
  */
@@ -61,7 +44,6 @@ export function getBackendCfg(projectDir: string = '.'): BackendCfg {
61
44
  requireFileToExist(backendCfgYamlPath)
62
45
 
63
46
  const backendCfg: BackendCfg = {
64
- serviceWithBranchName: true,
65
47
  ...fs2.readYaml(backendCfgYamlPath),
66
48
  }
67
49
 
@@ -8,7 +8,6 @@ export interface DeployInfo {
8
8
  serviceUrl: string
9
9
  gitRev: string
10
10
  gitBranch: string
11
- prod: boolean
12
11
 
13
12
  /**
14
13
  * Unix timestamp of deployInfo.json being generated.
@@ -1,7 +1,5 @@
1
- import fs from 'node:fs'
2
1
  import { _assert, _mapValues, _merge, _truncate, localTimeNow } from '@naturalcycles/js-lib'
3
- import { dimGrey, white } from '@naturalcycles/nodejs-lib'
4
- import yaml from 'js-yaml'
2
+ import { dimGrey, fs2, white } from '@naturalcycles/nodejs-lib'
5
3
  import { BackendCfg } from './backend.cfg.util'
6
4
  import { AppYaml, DeployInfo } from './deploy.model'
7
5
 
@@ -29,12 +27,9 @@ export async function createAndSaveDeployInfo(
29
27
  targetDir: string,
30
28
  ): Promise<DeployInfo> {
31
29
  const deployInfo = await createDeployInfo(backendCfg)
32
-
33
30
  const deployInfoPath = `${targetDir}/deployInfo.json`
34
-
35
- fs.writeFileSync(deployInfoPath, JSON.stringify(deployInfo, null, 2))
31
+ fs2.writeJson(deployInfoPath, deployInfo, { spaces: 2 })
36
32
  console.log(`saved ${dimGrey(deployInfoPath)}`)
37
-
38
33
  return deployInfo
39
34
  }
40
35
 
@@ -54,18 +49,14 @@ export async function createDeployInfo(
54
49
  gaeProjectByBranch = {},
55
50
  gaeService,
56
51
  gaeServiceByBranch = {},
57
- serviceWithBranchName,
58
- prodBranch,
59
52
  branchesWithTimestampVersions = [],
60
53
  } = backendCfg
61
54
 
62
55
  gaeProject = gaeProjectByBranch[gitBranch] || gaeProject
63
56
 
64
- gaeService = validateGAEServiceName(gaeServiceByBranch[gitBranch] || gaeService)
65
-
66
- const prod = gitBranch === prodBranch
67
-
68
- if (!prod && serviceWithBranchName && !gaeServiceByBranch[gitBranch]) {
57
+ if (gaeServiceByBranch[gitBranch]) {
58
+ gaeService = validateGAEServiceName(gaeServiceByBranch[gitBranch]!)
59
+ } else {
69
60
  gaeService = validateGAEServiceName([gitBranch, gaeService].join('--'))
70
61
  }
71
62
 
@@ -99,7 +90,6 @@ export async function createDeployInfo(
99
90
  serviceUrl,
100
91
  gitBranch,
101
92
  gitRev,
102
- prod,
103
93
  ts: now.unix(),
104
94
  }
105
95
 
@@ -116,12 +106,9 @@ export function createAndSaveAppYaml(
116
106
  appYamlPassEnv = '',
117
107
  ): AppYaml {
118
108
  const appYaml = createAppYaml(backendCfg, deployInfo, projectDir, appYamlPassEnv)
119
-
120
109
  const appYamlPath = `${targetDir}/app.yaml`
121
-
122
- fs.writeFileSync(appYamlPath, yaml.dump(appYaml))
110
+ fs2.writeYaml(appYamlPath, appYaml)
123
111
  console.log(`saved ${dimGrey(appYamlPath)}`)
124
-
125
112
  return appYaml
126
113
  }
127
114
 
@@ -144,15 +131,15 @@ export function createAppYaml(
144
131
 
145
132
  // Check existing app.yaml
146
133
  const appYamlPath = `${projectDir}/app.yaml`
147
- if (fs.existsSync(appYamlPath)) {
134
+ if (fs2.pathExists(appYamlPath)) {
148
135
  console.log(`merging-in ${dimGrey(appYamlPath)}`)
149
- _merge(appYaml, yaml.load(fs.readFileSync(appYamlPath, 'utf8')))
136
+ _merge(appYaml, fs2.readYaml(appYamlPath))
150
137
  }
151
138
 
152
139
  const appEnvYamlPath = `${projectDir}/app.${APP_ENV}.yaml`
153
- if (fs.existsSync(appEnvYamlPath)) {
140
+ if (fs2.pathExists(appEnvYamlPath)) {
154
141
  console.log(`merging-in ${dimGrey(appEnvYamlPath)}`)
155
- _merge(appYaml, yaml.load(fs.readFileSync(appEnvYamlPath, 'utf8')))
142
+ _merge(appYaml, fs2.readYaml(appEnvYamlPath))
156
143
  }
157
144
 
158
145
  // appYamlPassEnv
@@ -89,12 +89,12 @@ export async function undeployGae(branch: string): Promise<void> {
89
89
  const projectDir = '.'
90
90
  const backendCfg = getBackendCfg(projectDir)
91
91
 
92
- const { gaeProject, gaeService, gaeVersion, prod } = await createDeployInfo(backendCfg, branch)
92
+ const { gaeProject, gaeService, gaeVersion } = await createDeployInfo(backendCfg, branch)
93
93
 
94
- if (prod) {
95
- console.log(`undeployGae (branch: ${branch}): not removing prod version (safety check)`)
96
- return
97
- }
94
+ // if (prod) {
95
+ // console.log(`undeployGae (branch: ${branch}): not removing prod version (safety check)`)
96
+ // return
97
+ // }
98
98
 
99
99
  console.log(
100
100
  `undeployGae (branch: ${branch}): going to remove ${gaeProject}/${gaeService}/${gaeVersion}`,
@@ -1,11 +1,11 @@
1
- import fs from 'node:fs'
2
1
  import { _memoFn } from '@naturalcycles/js-lib'
2
+ import { fs2 } from '@naturalcycles/nodejs-lib'
3
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
7
  try {
8
- return JSON.parse(fs.readFileSync(deployInfoPath, 'utf8'))
8
+ return fs2.readJson(deployInfoPath)
9
9
  } catch {
10
10
  // console.error(`cannot read ${deployInfoPath}, returning empty version`)
11
11
  return getDeployInfoStub()
@@ -21,7 +21,6 @@ function getDeployInfoStub(stub = ''): DeployInfo {
21
21
  versionUrl: stub,
22
22
  gitBranch: stub,
23
23
  gitRev: stub,
24
- prod: false,
25
24
  ts: Math.floor(Date.now() / 1000),
26
25
  }
27
26
  }
@@ -16,7 +16,7 @@ export function getServerStatusData(
16
16
  projectDir: string = process.cwd(),
17
17
  extra?: any,
18
18
  ): Record<string, any> {
19
- const { gitRev, gitBranch, prod, ts } = getDeployInfo(projectDir)
19
+ const { gitRev, gitBranch, ts } = getDeployInfo(projectDir)
20
20
  const t = localTime(ts)
21
21
  const deployBuildTime = t.toPretty()
22
22
  const buildInfo = [t.toStringCompact(), gitBranch, gitRev].filter(Boolean).join('_')
@@ -25,7 +25,6 @@ export function getServerStatusData(
25
25
  started: getStartedStr(),
26
26
  deployBuildTime,
27
27
  APP_ENV,
28
- prod,
29
28
  buildInfo,
30
29
  GAE_APPLICATION,
31
30
  GAE_SERVICE,