@naturalcycles/backend-lib 4.10.1 → 4.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/base.admin.service.js +2 -1
- package/dist/db/httpDB.d.ts +1 -1
- package/dist/db/httpDBRequestHandler.js +4 -4
- package/dist/deploy/deployHealthCheck.js +12 -13
- package/dist/sentry/sentry.shared.service.js +2 -2
- package/dist/server/genericErrorMiddleware.js +1 -1
- package/dist/server/server.util.d.ts +1 -1
- package/dist/testing/express.test.service.d.ts +1 -1
- package/package.json +4 -4
- package/src/admin/base.admin.service.ts +2 -1
- package/src/db/httpDB.ts +2 -2
- package/src/db/httpDBRequestHandler.ts +4 -4
- package/src/deploy/deployHealthCheck.ts +15 -15
- package/src/sentry/sentry.shared.service.ts +16 -6
- package/src/server/genericErrorMiddleware.ts +8 -3
- package/src/server/server.util.ts +1 -1
- package/src/testing/express.test.service.ts +1 -1
|
@@ -41,6 +41,7 @@ class BaseAdminService {
|
|
|
41
41
|
/**
|
|
42
42
|
* To be extended.
|
|
43
43
|
*/
|
|
44
|
+
// eslint-disable-next-line max-params
|
|
44
45
|
async onPermissionCheck(req, email, reqPermissions, required, granted, meta = {}) {
|
|
45
46
|
req.log(`${(0, colors_1.dimGrey)(email)} ${required ? 'required' : 'optional'} permissions check [${(0, colors_1.dimGrey)(reqPermissions.join(', '))}]: ${granted ? (0, colors_1.green)('GRANTED') : (0, colors_1.red)('DENIED')}`, meta);
|
|
46
47
|
}
|
|
@@ -70,7 +71,7 @@ class BaseAdminService {
|
|
|
70
71
|
* Override if needed.
|
|
71
72
|
*/
|
|
72
73
|
async getAdminToken(req) {
|
|
73
|
-
return (
|
|
74
|
+
return (req.cookies?.[this.cfg.adminTokenKey] ||
|
|
74
75
|
req.header(this.cfg.adminTokenKey) ||
|
|
75
76
|
req.header('x-admin-token'));
|
|
76
77
|
}
|
package/dist/db/httpDB.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare class HttpDB extends BaseCommonDB implements CommonDB {
|
|
|
16
16
|
getTables(): Promise<string[]>;
|
|
17
17
|
getTableSchema<ROW extends ObjectWithId>(table: string): Promise<JsonSchemaRootObject<ROW>>;
|
|
18
18
|
resetCache(table?: string): Promise<void>;
|
|
19
|
-
getByIds<ROW extends ObjectWithId>(table: string, ids:
|
|
19
|
+
getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], opt?: CommonDBOptions): Promise<ROW[]>;
|
|
20
20
|
runQuery<ROW extends ObjectWithId>(query: DBQuery<ROW>, opt?: CommonDBOptions): Promise<RunQueryResult<ROW>>;
|
|
21
21
|
runQueryCount<ROW extends ObjectWithId>(query: DBQuery<ROW>, opt?: CommonDBOptions): Promise<number>;
|
|
22
22
|
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
|
|
@@ -72,10 +72,10 @@ function httpDBRequestHandler(db) {
|
|
|
72
72
|
res.end();
|
|
73
73
|
});
|
|
74
74
|
// deleteByIds
|
|
75
|
-
router.put('/deleteByIds',
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
})
|
|
75
|
+
// router.put('/deleteByIds', reqValidation('body', getByIdsInputSchema), async (req, res) => {
|
|
76
|
+
// const { table, ids, opt } = req.body as GetByIdsInput
|
|
77
|
+
// res.json(await db.deleteByIds(table, ids, opt))
|
|
78
|
+
// })
|
|
79
79
|
// deleteByQuery
|
|
80
80
|
router.put('/deleteByQuery', (0, __1.reqValidation)('body', runQueryInputSchema), async (req, res) => {
|
|
81
81
|
const { query, opt } = req.body;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.deployHealthCheck = exports.deployHealthCheckYargsOptions = void 0;
|
|
4
4
|
const node_util_1 = require("node:util");
|
|
5
5
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
6
|
-
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
7
6
|
const colors_1 = require("@naturalcycles/nodejs-lib/dist/colors");
|
|
8
7
|
const exec_1 = require("@naturalcycles/nodejs-lib/dist/exec");
|
|
9
8
|
const request_log_util_1 = require("../server/request.log.util");
|
|
@@ -66,7 +65,7 @@ async function deployHealthCheck(url, opt = {}) {
|
|
|
66
65
|
let doneReason;
|
|
67
66
|
let failed = false;
|
|
68
67
|
let currentInterval = intervalSec * 1000;
|
|
69
|
-
const
|
|
68
|
+
const fetcher = (0, js_lib_1.getFetcher)();
|
|
70
69
|
while (!done) {
|
|
71
70
|
// eslint-disable-next-line no-await-in-loop
|
|
72
71
|
await makeAttempt();
|
|
@@ -85,18 +84,18 @@ async function deployHealthCheck(url, opt = {}) {
|
|
|
85
84
|
attempt++;
|
|
86
85
|
console.log([`>>`, (0, colors_1.dimGrey)(url), (0, node_util_1.inspect)({ attempt }, inspectOpt)].join(' '));
|
|
87
86
|
const started = Date.now();
|
|
88
|
-
const {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
retry:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
console.log(err.message);
|
|
96
|
-
return {
|
|
97
|
-
statusCode: 0,
|
|
98
|
-
};
|
|
87
|
+
const { err, fetchResponse } = await fetcher.rawFetch(url, {
|
|
88
|
+
mode: 'json',
|
|
89
|
+
timeoutSeconds: timeoutSec,
|
|
90
|
+
retry: {
|
|
91
|
+
count: 0,
|
|
92
|
+
},
|
|
93
|
+
followRedirects: false,
|
|
99
94
|
});
|
|
95
|
+
if (err) {
|
|
96
|
+
console.log(err);
|
|
97
|
+
}
|
|
98
|
+
const statusCode = fetchResponse?.status || 0;
|
|
100
99
|
if (statusCode === 200) {
|
|
101
100
|
countHealthy++;
|
|
102
101
|
countUnhealthy = 0;
|
|
@@ -86,7 +86,7 @@ class SentrySharedService {
|
|
|
86
86
|
}),
|
|
87
87
|
// data: (err as AppError).data, // included in message
|
|
88
88
|
});
|
|
89
|
-
return this.sentry().captureException((0, js_lib_1._anyToError)(err, Error, {
|
|
89
|
+
return this.sentry().captureException((0, js_lib_1._anyToError)(err, Error, {}, {
|
|
90
90
|
stringifyFn: nodejs_lib_1.inspectAnyStringifyFn,
|
|
91
91
|
}));
|
|
92
92
|
}
|
|
@@ -121,7 +121,7 @@ class SentrySharedService {
|
|
|
121
121
|
this.sentry().addBreadcrumb({
|
|
122
122
|
message,
|
|
123
123
|
});
|
|
124
|
-
this.sentry().captureException((0, js_lib_1._anyToError)(args.length === 1 ? args[0] : args, Error, {
|
|
124
|
+
this.sentry().captureException((0, js_lib_1._anyToError)(args.length === 1 ? args[0] : args, Error, {}, {
|
|
125
125
|
stringifyFn: nodejs_lib_1.inspectAnyStringifyFn,
|
|
126
126
|
}));
|
|
127
127
|
},
|
|
@@ -42,7 +42,7 @@ function respondWithError(req, res, err) {
|
|
|
42
42
|
else {
|
|
43
43
|
req.error(err);
|
|
44
44
|
}
|
|
45
|
-
const originalError = (0, js_lib_1._anyToError)(err, Error, {
|
|
45
|
+
const originalError = (0, js_lib_1._anyToError)(err, Error, {}, {
|
|
46
46
|
stringifyFn: nodejs_lib_1.inspectAnyStringifyFn,
|
|
47
47
|
});
|
|
48
48
|
let errorId;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Server } from 'node:http';
|
|
3
3
|
export interface DestroyableServer extends Server {
|
|
4
|
-
destroy()
|
|
4
|
+
destroy: () => Promise<void>;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Based on: https://github.com/isaacs/server-destroy/blob/master/index.js
|
|
@@ -2,7 +2,7 @@ import { GetGotOptions, Got } from '@naturalcycles/nodejs-lib';
|
|
|
2
2
|
import { BackendApplication, DefaultAppCfg } from '../index';
|
|
3
3
|
import { BackendRequestHandlerCfg } from '../server/createDefaultApp.model';
|
|
4
4
|
export interface ExpressApp extends Got {
|
|
5
|
-
close()
|
|
5
|
+
close: () => Promise<void>;
|
|
6
6
|
}
|
|
7
7
|
declare class ExpressTestService {
|
|
8
8
|
createAppFromResource(resource: BackendRequestHandlerCfg, opt?: GetGotOptions, defaultAppCfg?: DefaultAppCfg): ExpressApp;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/backend-lib",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"prepare": "husky install && patch-package",
|
|
6
6
|
"serve": "APP_ENV=dev nodemon",
|
|
7
|
-
"docs-serve": "vuepress dev docs",
|
|
8
|
-
"docs-build": "vuepress build docs",
|
|
7
|
+
"docs-serve": "NODE_OPTIONS=--openssl-legacy-provider vuepress dev docs",
|
|
8
|
+
"docs-build": "NODE_OPTIONS=--openssl-legacy-provider vuepress build docs",
|
|
9
9
|
"deploy-gae": "yarn tsn ./src/bin/deploy-gae.ts",
|
|
10
10
|
"deploy-prepare": "yarn tsn ./src/bin/deploy-prepare.ts",
|
|
11
11
|
"deploy-prepare-debug": "AA=AA1 BB=BB1 yarn tsn ./src/bin/deploy-prepare.ts --projectDir ./src/test/project",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"url": "https://github.com/NaturalCycles/backend-lib"
|
|
79
79
|
},
|
|
80
80
|
"engines": {
|
|
81
|
-
"node": ">=16.
|
|
81
|
+
"node": ">=16.15.0"
|
|
82
82
|
},
|
|
83
83
|
"type": "commonjs",
|
|
84
84
|
"description": "Standard library for making Express.js / AppEngine based backend services",
|
|
@@ -68,6 +68,7 @@ export class BaseAdminService {
|
|
|
68
68
|
/**
|
|
69
69
|
* To be extended.
|
|
70
70
|
*/
|
|
71
|
+
// eslint-disable-next-line max-params
|
|
71
72
|
protected async onPermissionCheck(
|
|
72
73
|
req: BackendRequest,
|
|
73
74
|
email: string,
|
|
@@ -113,7 +114,7 @@ export class BaseAdminService {
|
|
|
113
114
|
*/
|
|
114
115
|
async getAdminToken(req: BackendRequest): Promise<string | undefined> {
|
|
115
116
|
return (
|
|
116
|
-
|
|
117
|
+
req.cookies?.[this.cfg.adminTokenKey] ||
|
|
117
118
|
req.header(this.cfg.adminTokenKey) ||
|
|
118
119
|
req.header('x-admin-token')
|
|
119
120
|
)
|
package/src/db/httpDB.ts
CHANGED
|
@@ -50,7 +50,7 @@ export class HttpDB extends BaseCommonDB implements CommonDB {
|
|
|
50
50
|
|
|
51
51
|
override async getByIds<ROW extends ObjectWithId>(
|
|
52
52
|
table: string,
|
|
53
|
-
ids:
|
|
53
|
+
ids: ROW['id'][],
|
|
54
54
|
opt?: CommonDBOptions,
|
|
55
55
|
): Promise<ROW[]> {
|
|
56
56
|
return await this.got
|
|
@@ -106,7 +106,7 @@ export class HttpDB extends BaseCommonDB implements CommonDB {
|
|
|
106
106
|
})
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
async deleteByIds(table: string, ids: string[], opt?: CommonDBOptions): Promise<number> {
|
|
110
110
|
return await this.got
|
|
111
111
|
.put(`deleteByIds`, {
|
|
112
112
|
json: {
|
|
@@ -111,10 +111,10 @@ export function httpDBRequestHandler(db: CommonDB): BackendRouter {
|
|
|
111
111
|
})
|
|
112
112
|
|
|
113
113
|
// deleteByIds
|
|
114
|
-
router.put('/deleteByIds', reqValidation('body', getByIdsInputSchema), async (req, res) => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
})
|
|
114
|
+
// router.put('/deleteByIds', reqValidation('body', getByIdsInputSchema), async (req, res) => {
|
|
115
|
+
// const { table, ids, opt } = req.body as GetByIdsInput
|
|
116
|
+
// res.json(await db.deleteByIds(table, ids, opt))
|
|
117
|
+
// })
|
|
118
118
|
|
|
119
119
|
// deleteByQuery
|
|
120
120
|
router.put('/deleteByQuery', reqValidation('body', runQueryInputSchema), async (req, res) => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { inspect, InspectOptions } from 'node:util'
|
|
2
|
-
import { pDelay, _filterFalsyValues, _ms, _since } from '@naturalcycles/js-lib'
|
|
3
|
-
import { getGot } from '@naturalcycles/nodejs-lib'
|
|
2
|
+
import { pDelay, _filterFalsyValues, _ms, _since, getFetcher } from '@naturalcycles/js-lib'
|
|
4
3
|
import { dimGrey, red } from '@naturalcycles/nodejs-lib/dist/colors'
|
|
5
4
|
import { execCommand } from '@naturalcycles/nodejs-lib/dist/exec'
|
|
6
5
|
import { coloredHttpCode } from '../server/request.log.util'
|
|
@@ -95,7 +94,7 @@ export async function deployHealthCheck(
|
|
|
95
94
|
let failed = false
|
|
96
95
|
let currentInterval = intervalSec * 1000
|
|
97
96
|
|
|
98
|
-
const
|
|
97
|
+
const fetcher = getFetcher()
|
|
99
98
|
|
|
100
99
|
while (!done) {
|
|
101
100
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -127,20 +126,21 @@ export async function deployHealthCheck(
|
|
|
127
126
|
|
|
128
127
|
const started = Date.now()
|
|
129
128
|
|
|
130
|
-
const {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
retry:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
console.log(err.message)
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
statusCode: 0,
|
|
141
|
-
}
|
|
129
|
+
const { err, fetchResponse } = await fetcher.rawFetch(url, {
|
|
130
|
+
mode: 'json',
|
|
131
|
+
timeoutSeconds: timeoutSec,
|
|
132
|
+
retry: {
|
|
133
|
+
count: 0,
|
|
134
|
+
},
|
|
135
|
+
followRedirects: false,
|
|
142
136
|
})
|
|
143
137
|
|
|
138
|
+
if (err) {
|
|
139
|
+
console.log(err)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const statusCode = fetchResponse?.status || 0
|
|
143
|
+
|
|
144
144
|
if (statusCode === 200) {
|
|
145
145
|
countHealthy++
|
|
146
146
|
countUnhealthy = 0
|
|
@@ -100,9 +100,14 @@ export class SentrySharedService {
|
|
|
100
100
|
})
|
|
101
101
|
|
|
102
102
|
return this.sentry().captureException(
|
|
103
|
-
_anyToError(
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
_anyToError(
|
|
104
|
+
err,
|
|
105
|
+
Error,
|
|
106
|
+
{},
|
|
107
|
+
{
|
|
108
|
+
stringifyFn: inspectAnyStringifyFn,
|
|
109
|
+
},
|
|
110
|
+
),
|
|
106
111
|
)
|
|
107
112
|
}
|
|
108
113
|
|
|
@@ -144,9 +149,14 @@ export class SentrySharedService {
|
|
|
144
149
|
})
|
|
145
150
|
|
|
146
151
|
this.sentry().captureException(
|
|
147
|
-
_anyToError(
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
_anyToError(
|
|
153
|
+
args.length === 1 ? args[0] : args,
|
|
154
|
+
Error,
|
|
155
|
+
{},
|
|
156
|
+
{
|
|
157
|
+
stringifyFn: inspectAnyStringifyFn,
|
|
158
|
+
},
|
|
159
|
+
),
|
|
150
160
|
)
|
|
151
161
|
},
|
|
152
162
|
}
|
|
@@ -73,9 +73,14 @@ export function respondWithError(req: BackendRequest, res: BackendResponse, err:
|
|
|
73
73
|
req.error(err)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
const originalError = _anyToError(
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
const originalError = _anyToError(
|
|
77
|
+
err,
|
|
78
|
+
Error,
|
|
79
|
+
{},
|
|
80
|
+
{
|
|
81
|
+
stringifyFn: inspectAnyStringifyFn,
|
|
82
|
+
},
|
|
83
|
+
)
|
|
79
84
|
|
|
80
85
|
let errorId: string | undefined
|
|
81
86
|
|
|
@@ -5,7 +5,7 @@ import { BackendApplication, createDefaultApp, DefaultAppCfg } from '../index'
|
|
|
5
5
|
import { BackendRequestHandlerCfg } from '../server/createDefaultApp.model'
|
|
6
6
|
|
|
7
7
|
export interface ExpressApp extends Got {
|
|
8
|
-
close()
|
|
8
|
+
close: () => Promise<void>
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
// Example:
|