@naturalcycles/backend-lib 9.79.0 → 9.81.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 (48) hide show
  1. package/dist/deploy/deployHealthCheck.d.ts +1 -5
  2. package/dist/deploy/deployHealthCheck.js +3 -34
  3. package/dist/deploy/index.d.ts +2 -9
  4. package/dist/deploy/index.js +1 -6
  5. package/dist/express/createDefaultApp.d.ts +23 -0
  6. package/dist/express/createDefaultApp.js +5 -3
  7. package/dist/server/serverStatusMiddleware.d.ts +2 -2
  8. package/dist/server/serverStatusMiddleware.js +5 -14
  9. package/dist/util.d.ts +0 -1
  10. package/dist/util.js +1 -4
  11. package/package.json +3 -13
  12. package/src/admin/login.html +103 -76
  13. package/src/deploy/deployHealthCheck.ts +2 -48
  14. package/src/deploy/index.ts +2 -17
  15. package/src/express/createDefaultApp.ts +35 -3
  16. package/src/server/serverStatusMiddleware.ts +4 -20
  17. package/src/util.ts +1 -5
  18. package/bin/deploy-gae.js +0 -2
  19. package/bin/deploy-prepare.js +0 -2
  20. package/bin/undeploy-gae.js +0 -2
  21. package/dist/bin/deploy-gae.d.ts +0 -1
  22. package/dist/bin/deploy-gae.js +0 -12
  23. package/dist/bin/deploy-prepare.d.ts +0 -1
  24. package/dist/bin/deploy-prepare.js +0 -19
  25. package/dist/bin/undeploy-gae.d.ts +0 -1
  26. package/dist/bin/undeploy-gae.js +0 -13
  27. package/dist/deploy/backend.cfg.util.d.ts +0 -30
  28. package/dist/deploy/backend.cfg.util.js +0 -23
  29. package/dist/deploy/deploy.model.d.ts +0 -29
  30. package/dist/deploy/deploy.model.js +0 -1
  31. package/dist/deploy/deploy.util.d.ts +0 -7
  32. package/dist/deploy/deploy.util.js +0 -151
  33. package/dist/deploy/deployGae.d.ts +0 -10
  34. package/dist/deploy/deployGae.js +0 -90
  35. package/dist/deploy/deployInfo.util.d.ts +0 -1
  36. package/dist/deploy/deployInfo.util.js +0 -25
  37. package/dist/deploy/deployPrepare.d.ts +0 -13
  38. package/dist/deploy/deployPrepare.js +0 -85
  39. package/src/bin/deploy-gae.ts +0 -14
  40. package/src/bin/deploy-prepare.ts +0 -24
  41. package/src/bin/undeploy-gae.ts +0 -15
  42. package/src/deploy/backend.cfg.util.ts +0 -63
  43. package/src/deploy/deploy.model.ts +0 -32
  44. package/src/deploy/deploy.util.ts +0 -214
  45. package/src/deploy/deployGae.ts +0 -127
  46. package/src/deploy/deployInfo.util.ts +0 -27
  47. package/src/deploy/deployPrepare.ts +0 -113
  48. package/src/deploy/files-default/.gcloudignore +0 -7
@@ -4,11 +4,6 @@ export interface DeployHealthCheckOptions {
4
4
  maxTries?: number;
5
5
  timeoutSec?: number;
6
6
  intervalSec?: number;
7
- logOnFailure?: boolean;
8
- logOnSuccess?: boolean;
9
- gaeProject?: string;
10
- gaeService?: string;
11
- gaeVersion?: string;
12
7
  authHeader?: string;
13
8
  }
14
9
  export declare const deployHealthCheckCliOptions: CliOptions;
@@ -16,5 +11,6 @@ export declare const deployHealthCheckCliOptions: CliOptions;
16
11
  * Requires up to `healthyThreshold` consecutive OK responses to succeed.
17
12
  * Fails on up to `unhealthyThreshold` consecutive FAIL responses.
18
13
  * Fails after maxTries.
14
+ * Throws on failure.
19
15
  */
20
16
  export declare function deployHealthCheck(url: string, opt?: DeployHealthCheckOptions): Promise<void>;
@@ -4,7 +4,6 @@ import { getFetcher } from '@naturalcycles/js-lib/http';
4
4
  import { _filterFalsyValues, _filterUndefinedValues, } from '@naturalcycles/js-lib/object/object.util.js';
5
5
  import { pDelay } from '@naturalcycles/js-lib/promise/pDelay.js';
6
6
  import { dimGrey, red } from '@naturalcycles/nodejs-lib/colors';
7
- import { exec2 } from '@naturalcycles/nodejs-lib/exec2';
8
7
  import { coloredHttpCode } from '../server/request.log.util.js';
9
8
  export const deployHealthCheckCliOptions = {
10
9
  thresholdHealthy: {
@@ -27,25 +26,6 @@ export const deployHealthCheckCliOptions = {
27
26
  type: 'number',
28
27
  default: 1,
29
28
  },
30
- logOnFailure: {
31
- type: 'boolean',
32
- default: true,
33
- desc: 'Show server logs on health check failure (requires gaeProject, gaeService, gaeVersion)',
34
- },
35
- logOnSuccess: {
36
- type: 'boolean',
37
- default: false,
38
- desc: 'Show server logs on health check success (requires gaeProject, gaeService, gaeVersion)',
39
- },
40
- gaeProject: {
41
- type: 'string',
42
- },
43
- gaeService: {
44
- type: 'string',
45
- },
46
- gaeVersion: {
47
- type: 'string',
48
- },
49
29
  authHeader: {
50
30
  type: 'string',
51
31
  },
@@ -58,9 +38,10 @@ const inspectOpt = {
58
38
  * Requires up to `healthyThreshold` consecutive OK responses to succeed.
59
39
  * Fails on up to `unhealthyThreshold` consecutive FAIL responses.
60
40
  * Fails after maxTries.
41
+ * Throws on failure.
61
42
  */
62
43
  export async function deployHealthCheck(url, opt = {}) {
63
- const { thresholdHealthy = 5, thresholdUnhealthy = 8, maxTries = 30, timeoutSec = 30, intervalSec = 1, logOnFailure, logOnSuccess, gaeProject, gaeService, gaeVersion, authHeader, } = opt;
44
+ const { thresholdHealthy = 5, thresholdUnhealthy = 8, maxTries = 30, timeoutSec = 30, intervalSec = 1, authHeader, } = opt;
64
45
  let attempt = 0;
65
46
  let countHealthy = 0;
66
47
  let countUnhealthy = 0;
@@ -74,19 +55,7 @@ export async function deployHealthCheck(url, opt = {}) {
74
55
  }
75
56
  if (failed) {
76
57
  console.log(red(`Health check failed!`));
77
- if (logOnFailure) {
78
- try {
79
- exec2.spawn(`gcloud app logs read --project ${gaeProject} --service ${gaeService} --version ${gaeVersion}`);
80
- }
81
- catch { }
82
- }
83
- process.exit(1);
84
- }
85
- if (logOnSuccess) {
86
- try {
87
- exec2.spawn(`gcloud app logs read --project ${gaeProject} --service ${gaeService} --version ${gaeVersion}`);
88
- }
89
- catch { }
58
+ throw new Error(`Health check failed: ${doneReason}`);
90
59
  }
91
60
  async function makeAttempt() {
92
61
  attempt++;
@@ -1,11 +1,4 @@
1
- import type { BackendCfg } from './backend.cfg.util.js';
2
- import { getBackendCfg } from './backend.cfg.util.js';
3
- import type { DeployInfo } from './deploy.model.js';
4
- import { createAppYaml, createDeployInfo } from './deploy.util.js';
5
- import { deployGae } from './deployGae.js';
6
1
  import type { DeployHealthCheckOptions } from './deployHealthCheck.js';
7
2
  import { deployHealthCheck } from './deployHealthCheck.js';
8
- import { deployPrepare } from './deployPrepare.js';
9
- export type { BackendCfg, DeployHealthCheckOptions, DeployInfo };
10
- export { createAppYaml, createDeployInfo, deployGae, deployHealthCheck, deployPrepare, getBackendCfg, };
11
- export * from './deployInfo.util.js';
3
+ export type { DeployHealthCheckOptions };
4
+ export { deployHealthCheck };
@@ -1,7 +1,2 @@
1
- import { getBackendCfg } from './backend.cfg.util.js';
2
- import { createAppYaml, createDeployInfo } from './deploy.util.js';
3
- import { deployGae } from './deployGae.js';
4
1
  import { deployHealthCheck } from './deployHealthCheck.js';
5
- import { deployPrepare } from './deployPrepare.js';
6
- export { createAppYaml, createDeployInfo, deployGae, deployHealthCheck, deployPrepare, getBackendCfg, };
7
- export * from './deployInfo.util.js';
2
+ export { deployHealthCheck };
@@ -32,4 +32,27 @@ export interface DefaultAppCfg {
32
32
  bodyParserRawOptions?: Options;
33
33
  corsOptions?: CorsOptions;
34
34
  genericErrorMwCfg?: GenericErrorMiddlewareCfg;
35
+ /**
36
+ * Value for Express `trust proxy` setting, which defines how `req.ip`, `req.ips`,
37
+ * `req.protocol` and `req.hostname` are resolved from `X-Forwarded-*` headers.
38
+ *
39
+ * Defaults to `2` - trust exactly 2 hops: the socket peer (Google Front End) and the
40
+ * rightmost `X-Forwarded-For` entry (appended by the Google Cloud Load Balancer).
41
+ * This is the setup of Cloud Run behind a Load Balancer.
42
+ * Any further entries to the left could be injected by the client, so they are not trusted,
43
+ * which prevents IP address spoofing via `X-Forwarded-For` header.
44
+ *
45
+ * Do NOT set it to `true` in production - it trusts the leftmost `X-Forwarded-For` entry,
46
+ * which is fully client-controlled.
47
+ *
48
+ * Adjust it to match the hosting environment (number of proxies in front of the app).
49
+ *
50
+ * @default 2
51
+ */
52
+ trustProxy?: TrustProxy;
35
53
  }
54
+ /**
55
+ * Accepted values of Express `trust proxy` setting.
56
+ * See https://expressjs.com/en/guide/behind-proxies.html
57
+ */
58
+ export type TrustProxy = boolean | number | string | string[] | ((ip: string | undefined, hopIndex: number) => boolean);
@@ -5,9 +5,10 @@ import { logMiddleware } from '../server/logMiddleware.js';
5
5
  import { notFoundMiddleware } from '../server/notFoundMiddleware.js';
6
6
  import { requestTimeoutMiddleware } from '../server/requestTimeoutMiddleware.js';
7
7
  import { simpleRequestLoggerMiddleware } from '../server/simpleRequestLoggerMiddleware.js';
8
- import { isGAE } from '../util.js';
8
+ import { isCloudRun } from '../util.js';
9
9
  const isTest = process.env['APP_ENV'] === 'test';
10
10
  const isDev = process.env['APP_ENV'] === 'dev';
11
+ const isGAE = !!process.env['GAE_INSTANCE'];
11
12
  export async function createDefaultApp(cfg) {
12
13
  const { sentryService } = cfg;
13
14
  const { default: express } = await import('express');
@@ -16,7 +17,7 @@ export async function createDefaultApp(cfg) {
16
17
  const app = express();
17
18
  app.disable('etag');
18
19
  app.disable('x-powered-by');
19
- app.set('trust proxy', true);
20
+ app.set('trust proxy', cfg.trustProxy ?? 2);
20
21
  // preHandlers
21
22
  useHandlers(app, cfg.preHandlers);
22
23
  app.use(logMiddleware());
@@ -43,8 +44,9 @@ export async function createDefaultApp(cfg) {
43
44
  maxAge: 86400,
44
45
  ...cfg.corsOptions,
45
46
  }));
46
- if (!isGAE() && isTest) {
47
+ if (!isGAE && (isTest || isCloudRun())) {
47
48
  // compression is not used in AppEngine, because AppEngine provides it by default
49
+ // Cloud Run doesn't compress responses, so we do it ourselves
48
50
  app.use(compressionMiddleware());
49
51
  }
50
52
  // app.use(safeJsonMiddleware()) // optional
@@ -1,3 +1,3 @@
1
1
  import type { BackendRequestHandler } from './server.model.js';
2
- export declare function serverStatusMiddleware(projectDir?: string, extra?: any): BackendRequestHandler;
3
- export declare function getServerStatusData(projectDir?: string, extra?: any): Record<string, any>;
2
+ export declare function serverStatusMiddleware(extra?: any): BackendRequestHandler;
3
+ export declare function getServerStatusData(extra?: any): Record<string, any>;
@@ -2,31 +2,22 @@ import os from 'node:os';
2
2
  import { localTime } from '@naturalcycles/js-lib/datetime/localTime.js';
3
3
  import { _filterNullishValues } from '@naturalcycles/js-lib/object/object.util.js';
4
4
  import { memoryUsageFull, processSharedUtil } from '@naturalcycles/nodejs-lib';
5
- import { getDeployInfo } from '../deploy/deployInfo.util.js';
6
5
  const { versions, arch, platform } = process;
7
6
  const availableParallelismAtStart = os.availableParallelism();
8
- const { GAE_APPLICATION, GAE_SERVICE, GAE_VERSION, GOOGLE_CLOUD_PROJECT, K_SERVICE, K_REVISION, APP_ENV, NODE_ENV, NODE_OPTIONS, UV_THREADPOOL_SIZE, MALLOC_ARENA_MAX, DEPLOY_BUILD_TIME, BUILD_VERSION, } = process.env;
9
- export function serverStatusMiddleware(projectDir, extra) {
7
+ const { GOOGLE_CLOUD_PROJECT, K_SERVICE, K_REVISION, APP_ENV, NODE_ENV, NODE_OPTIONS, UV_THREADPOOL_SIZE, MALLOC_ARENA_MAX, DEPLOY_BUILD_TIME, BUILD_VERSION, } = process.env;
8
+ export function serverStatusMiddleware(extra) {
10
9
  return async (_req, res) => {
11
- res.json(getServerStatusData(projectDir, extra));
10
+ res.json(getServerStatusData(extra));
12
11
  };
13
12
  }
14
- export function getServerStatusData(projectDir = process.cwd(), extra) {
15
- let deployBuildTime = DEPLOY_BUILD_TIME;
16
- if (!deployBuildTime) {
17
- const { ts } = getDeployInfo(projectDir);
18
- deployBuildTime = localTime(ts).toPretty();
19
- }
13
+ export function getServerStatusData(extra) {
20
14
  const availableParallelism = os.availableParallelism();
21
15
  return _filterNullishValues({
22
16
  nodeProcessStarted: getStartedStr(),
23
- deployBuildTime,
17
+ DEPLOY_BUILD_TIME,
24
18
  BUILD_VERSION,
25
19
  APP_ENV,
26
20
  GOOGLE_CLOUD_PROJECT,
27
- GAE_APPLICATION,
28
- GAE_SERVICE,
29
- GAE_VERSION,
30
21
  K_SERVICE,
31
22
  K_REVISION,
32
23
  processInfo: {
package/dist/util.d.ts CHANGED
@@ -1,2 +1 @@
1
- export declare function isGAE(): boolean;
2
1
  export declare function isCloudRun(): boolean;
package/dist/util.js CHANGED
@@ -1,7 +1,4 @@
1
- const { GAE_INSTANCE, K_SERVICE } = process.env;
2
- export function isGAE() {
3
- return !!GAE_INSTANCE;
4
- }
1
+ const { K_SERVICE } = process.env;
5
2
  export function isCloudRun() {
6
3
  return !!K_SERVICE;
7
4
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
3
  "type": "module",
4
- "version": "9.79.0",
4
+ "version": "9.81.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/db-lib": "^10",
7
7
  "@naturalcycles/js-lib": "^15",
@@ -20,8 +20,7 @@
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@sentry/node-core": "^10",
23
- "firebase-admin": "^14",
24
- "simple-git": "^4"
23
+ "firebase-admin": "^14"
25
24
  },
26
25
  "peerDependenciesMeta": {
27
26
  "@sentry/node-core": {
@@ -29,9 +28,6 @@
29
28
  },
30
29
  "firebase-admin": {
31
30
  "optional": true
32
- },
33
- "simple-git": {
34
- "optional": true
35
31
  }
36
32
  },
37
33
  "devDependencies": {
@@ -68,9 +64,6 @@
68
64
  "!src/**/__exclude"
69
65
  ],
70
66
  "bin": {
71
- "deploy-gae": "bin/deploy-gae.js",
72
- "undeploy-gae": "bin/undeploy-gae.js",
73
- "deploy-prepare": "bin/deploy-prepare.js",
74
67
  "deploy-health-check": "bin/deploy-health-check.js"
75
68
  },
76
69
  "types": "dist/index.d.ts",
@@ -85,7 +78,7 @@
85
78
  "engines": {
86
79
  "node": ">=24.10.0"
87
80
  },
88
- "description": "Standard library for making Express.js / AppEngine based backend services",
81
+ "description": "Standard library for making Express.js based backend services",
89
82
  "author": "Natural Cycles Team",
90
83
  "license": "MIT",
91
84
  "scripts": {
@@ -97,9 +90,6 @@
97
90
  "check": "dev-lib check",
98
91
  "typecheck": "dev-lib typecheck",
99
92
  "dev": "APP_ENV=dev tsx watch src/test/server/server.ts",
100
- "deploy-gae": "tsx src/bin/deploy-gae.ts",
101
- "deploy-prepare": "tsx src/bin/deploy-prepare.ts",
102
- "deploy-prepare-debug": "AA=AA1 BB=BB1 tsx src/bin/deploy-prepare.ts --projectDir ./src/test/project",
103
93
  "deploy-health-check-debug1": "tsx src/bin/deploy-health-check.ts --url https://api-master.naturalcycles.com",
104
94
  "deploy-health-check-debug2": "tsx src/bin/deploy-health-check.ts --url https://api-master2.naturalcycles.com --thresholdUnhealthy 5"
105
95
  }
@@ -6,38 +6,59 @@
6
6
  <meta charset="utf-8" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
8
8
 
9
- <!-- CSS only -->
10
- <link
11
- href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.2/dist/css/bootstrap.min.css"
12
- rel="stylesheet"
13
- crossorigin="anonymous"
14
- />
9
+ <style>
10
+ body {
11
+ max-width: 45rem;
12
+ margin: 0 auto;
13
+ padding: 40px 1rem;
14
+ font-family: system-ui, sans-serif;
15
+ font-size: 1.15rem;
16
+ line-height: 1.5;
17
+ }
18
+ pre {
19
+ padding: 1rem 1.4rem;
20
+ overflow-x: auto;
21
+ background: #f5f7ff;
22
+ border: 1px solid #ccc;
23
+ border-radius: 5px;
24
+ }
25
+ button {
26
+ padding: 1rem 1.4rem;
27
+ font-size: 1.5rem;
28
+ color: #fff;
29
+ cursor: pointer;
30
+ background: #0d47a1;
31
+ border: none;
32
+ border-radius: 5px;
33
+ }
34
+ button:hover {
35
+ opacity: 0.8;
36
+ }
37
+ </style>
15
38
  </head>
16
39
  <body>
17
- <div id="app" style="padding: 40px 50px">
18
- <pre v-if="loading">Checking login...</pre>
19
- <div v-else>
20
- <div v-if="user">
21
- <p>Logged in as:</p>
22
- <pre><mark>{{ user.email }}</mark></pre>
23
- <pre><mark>{{ user.token }}</mark></pre>
24
- <button class="btn btn-primary btn-lg" @click="logout">Logout</button>
25
- </div>
26
- <div v-else>
27
- <button class="btn btn-primary btn-lg" @click="login" id="loginBtn">Login</button>
28
- </div>
29
- </div>
40
+ <pre id="loading">Checking login...</pre>
41
+
42
+ <div id="loggedIn" hidden>
43
+ <p>Logged in as:</p>
44
+ <pre><code id="email"></code></pre>
45
+ <pre><code id="token"></code></pre>
46
+ <button id="logoutButton">Logout</button>
47
+ </div>
48
+
49
+ <div id="loggedOut" hidden>
50
+ <button id="loginBtn">Login</button>
30
51
  </div>
31
52
 
32
53
  <script type="module">
33
- import { createApp } from 'https://cdn.jsdelivr.net/npm/vue@3.2.20/dist/vue.esm-browser.prod.js'
34
- import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.1.2/firebase-app.js'
54
+ import { initializeApp } from 'https://www.gstatic.com/firebasejs/13.1.0/firebase-app.js'
35
55
  import {
36
56
  getAuth,
37
57
  GoogleAuthProvider,
38
58
  onAuthStateChanged,
39
59
  signInWithRedirect,
40
- } from 'https://www.gstatic.com/firebasejs/9.1.2/firebase-auth.js'
60
+ signOut,
61
+ } from 'https://www.gstatic.com/firebasejs/13.1.0/firebase-auth.js'
41
62
 
42
63
  const apiKey = '<%= firebaseApiKey %>'
43
64
  const authDomain = '<%= firebaseAuthDomain %>'
@@ -47,84 +68,59 @@
47
68
  alert(`Error: 'apiKey' or 'authDomain' is missing!`)
48
69
  }
49
70
 
50
- // Initialize Firebase
51
- initializeApp({
52
- apiKey,
53
- authDomain,
54
- })
55
-
56
- const auth = getAuth()
57
- const provider = new GoogleAuthProvider()
58
-
59
- onAuthStateChanged(auth, user => {
60
- // console.log('onAuthStateChanged, user: ', JSON.stringify(user, null, 2))
61
- // console.log('onAuthStateChanged, user: ', user)
62
- onUser(user)
63
- })
64
-
65
71
  const qs = Object.fromEntries(new URLSearchParams(location.search))
66
- const { autoLogin, logout, adminTokenKey = 'admin_token' } = qs
72
+ const { autoLogin, adminTokenKey = 'admin_token' } = qs
67
73
  const returnUrl = toSafeReturnUrl(qs.returnUrl)
68
74
  // console.log(qs)
69
75
 
70
- const app = createApp({
71
- data() {
72
- return {
73
- loading: 'Loading...',
74
- user: undefined,
75
- }
76
- },
77
- methods: {
78
- login: async function () {
79
- try {
80
- await signInWithRedirect(auth, provider)
81
- } catch (err) {
82
- logError(err)
83
- }
84
- },
76
+ // Initialize Firebase
77
+ const auth = getAuth(
78
+ initializeApp({
79
+ apiKey,
80
+ authDomain,
81
+ }),
82
+ )
83
+ const provider = new GoogleAuthProvider()
85
84
 
86
- logout: async function () {
87
- try {
88
- await auth.signOut()
85
+ const el = {
86
+ loading: document.getElementById('loading'),
87
+ loggedIn: document.getElementById('loggedIn'),
88
+ loggedOut: document.getElementById('loggedOut'),
89
+ email: document.getElementById('email'),
90
+ token: document.getElementById('token'),
91
+ }
89
92
 
90
- await postToken('logout') // magic string
93
+ document.getElementById('loginBtn').addEventListener('click', login)
94
+ document.getElementById('logoutButton').addEventListener('click', logout)
91
95
 
92
- if (logout && returnUrl) {
93
- alert('Logged out, redurecting back...')
94
- location.href = returnUrl
95
- }
96
- } catch (err) {
97
- logError(err)
98
- }
99
- },
100
- },
101
- }).mount('#app')
96
+ onAuthStateChanged(auth, user => {
97
+ // console.log('onAuthStateChanged, user: ', JSON.stringify(user, null, 2))
98
+ // console.log('onAuthStateChanged, user: ', user)
99
+ void onUser(user)
100
+ })
102
101
 
103
- if (logout) app.logout()
102
+ if (qs.logout) void logout()
104
103
 
105
104
  ////
106
105
 
107
106
  async function onUser(user) {
108
107
  try {
109
108
  // alert('onUser')
110
- app.user = user
111
- app.loading = false
109
+ render(user)
112
110
  if (!user) {
113
- if (autoLogin) app.login()
111
+ if (autoLogin) void login()
114
112
  } else {
115
- const token = await auth.currentUser.getIdToken()
113
+ const token = await user.getIdToken()
116
114
 
117
115
  // alert('idToken')
118
116
  // console.log(idToken)
119
- app.user = Object.assign({}, app.user, {
120
- token,
121
- })
117
+ render(user, token)
122
118
 
123
119
  await postToken(token)
124
120
 
125
121
  // Redirect if needed
126
122
  if (returnUrl) {
127
- // alert(`Logged in as ${app.user.email}, redirecting back...`)
123
+ // alert(`Logged in as ${user.email}, redirecting back...`)
128
124
  location.href = returnUrl
129
125
  }
130
126
  }
@@ -133,6 +129,37 @@
133
129
  }
134
130
  }
135
131
 
132
+ function render(user, token = '') {
133
+ el.loading.hidden = true
134
+ el.loggedIn.hidden = !user
135
+ el.loggedOut.hidden = !!user
136
+ el.email.textContent = user?.email || ''
137
+ el.token.textContent = token
138
+ }
139
+
140
+ async function login() {
141
+ try {
142
+ await signInWithRedirect(auth, provider)
143
+ } catch (err) {
144
+ logError(err)
145
+ }
146
+ }
147
+
148
+ async function logout() {
149
+ try {
150
+ await signOut(auth)
151
+
152
+ await postToken('logout') // magic string
153
+
154
+ if (qs.logout && returnUrl) {
155
+ alert('Logged out, redirecting back...')
156
+ location.href = returnUrl
157
+ }
158
+ } catch (err) {
159
+ logError(err)
160
+ }
161
+ }
162
+
136
163
  function logError(err) {
137
164
  console.error(err)
138
165
  alert('Error\n ' + JSON.stringify(err, null, 2))
@@ -10,7 +10,6 @@ import { pDelay } from '@naturalcycles/js-lib/promise/pDelay.js'
10
10
  import type { UnixTimestampMillis } from '@naturalcycles/js-lib/types'
11
11
  import type { CliOptions } from '@naturalcycles/nodejs-lib/args'
12
12
  import { dimGrey, red } from '@naturalcycles/nodejs-lib/colors'
13
- import { exec2 } from '@naturalcycles/nodejs-lib/exec2'
14
13
  import { coloredHttpCode } from '../server/request.log.util.js'
15
14
 
16
15
  export interface DeployHealthCheckOptions {
@@ -19,11 +18,6 @@ export interface DeployHealthCheckOptions {
19
18
  maxTries?: number
20
19
  timeoutSec?: number
21
20
  intervalSec?: number
22
- logOnFailure?: boolean
23
- logOnSuccess?: boolean
24
- gaeProject?: string
25
- gaeService?: string
26
- gaeVersion?: string
27
21
  authHeader?: string
28
22
  }
29
23
 
@@ -48,25 +42,6 @@ export const deployHealthCheckCliOptions = {
48
42
  type: 'number',
49
43
  default: 1,
50
44
  },
51
- logOnFailure: {
52
- type: 'boolean',
53
- default: true,
54
- desc: 'Show server logs on health check failure (requires gaeProject, gaeService, gaeVersion)',
55
- },
56
- logOnSuccess: {
57
- type: 'boolean',
58
- default: false,
59
- desc: 'Show server logs on health check success (requires gaeProject, gaeService, gaeVersion)',
60
- },
61
- gaeProject: {
62
- type: 'string',
63
- },
64
- gaeService: {
65
- type: 'string',
66
- },
67
- gaeVersion: {
68
- type: 'string',
69
- },
70
45
  authHeader: {
71
46
  type: 'string',
72
47
  },
@@ -81,6 +56,7 @@ const inspectOpt: InspectOptions = {
81
56
  * Requires up to `healthyThreshold` consecutive OK responses to succeed.
82
57
  * Fails on up to `unhealthyThreshold` consecutive FAIL responses.
83
58
  * Fails after maxTries.
59
+ * Throws on failure.
84
60
  */
85
61
  export async function deployHealthCheck(
86
62
  url: string,
@@ -92,11 +68,6 @@ export async function deployHealthCheck(
92
68
  maxTries = 30,
93
69
  timeoutSec = 30,
94
70
  intervalSec = 1,
95
- logOnFailure,
96
- logOnSuccess,
97
- gaeProject,
98
- gaeService,
99
- gaeVersion,
100
71
  authHeader,
101
72
  } = opt
102
73
 
@@ -116,24 +87,7 @@ export async function deployHealthCheck(
116
87
 
117
88
  if (failed) {
118
89
  console.log(red(`Health check failed!`))
119
-
120
- if (logOnFailure) {
121
- try {
122
- exec2.spawn(
123
- `gcloud app logs read --project ${gaeProject} --service ${gaeService} --version ${gaeVersion}`,
124
- )
125
- } catch {}
126
- }
127
-
128
- process.exit(1)
129
- }
130
-
131
- if (logOnSuccess) {
132
- try {
133
- exec2.spawn(
134
- `gcloud app logs read --project ${gaeProject} --service ${gaeService} --version ${gaeVersion}`,
135
- )
136
- } catch {}
90
+ throw new Error(`Health check failed: ${doneReason}`)
137
91
  }
138
92
 
139
93
  async function makeAttempt(): Promise<void> {
@@ -1,21 +1,6 @@
1
- import type { BackendCfg } from './backend.cfg.util.js'
2
- import { getBackendCfg } from './backend.cfg.util.js'
3
- import type { DeployInfo } from './deploy.model.js'
4
- import { createAppYaml, createDeployInfo } from './deploy.util.js'
5
- import { deployGae } from './deployGae.js'
6
1
  import type { DeployHealthCheckOptions } from './deployHealthCheck.js'
7
2
  import { deployHealthCheck } from './deployHealthCheck.js'
8
- import { deployPrepare } from './deployPrepare.js'
9
3
 
10
- export type { BackendCfg, DeployHealthCheckOptions, DeployInfo }
4
+ export type { DeployHealthCheckOptions }
11
5
 
12
- export {
13
- createAppYaml,
14
- createDeployInfo,
15
- deployGae,
16
- deployHealthCheck,
17
- deployPrepare,
18
- getBackendCfg,
19
- }
20
-
21
- export * from './deployInfo.util.js'
6
+ export { deployHealthCheck }