anote-server-libs 0.12.1 → 0.12.2

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.
@@ -1,65 +1,65 @@
1
- import {Request, Response} from 'express';
2
- import Ajv, {_} from 'ajv';
3
-
4
- export const ajv = new Ajv();
5
- ajv.addKeyword({
6
- keyword: 'maxDigits',
7
- type: 'number',
8
- schemaType: 'number',
9
- validate: (schema: number, data: any) => typeof data === 'number' && Math.round(data * 10 ** schema) / (10 ** schema) === data
10
- });
11
-
12
- export function WithBody(schema: any, collapseTopLevelNulls = true) {
13
- if(schema.type === 'object') {
14
- const required: string[] = [];
15
- const keys = Object.getOwnPropertyNames(schema.properties);
16
- keys.forEach(key => {
17
- if(schema.properties[key].required === true) {
18
- required.push(key);
19
- }
20
- if(schema.properties[key].required === true || schema.properties[key].required === false) {
21
- delete schema.properties[key].required;
22
- }
23
- });
24
- schema.required = required;
25
- }
26
- const validate = ajv.compile(schema);
27
- return function(_: any, __: string, descriptor: PropertyDescriptor) {
28
- if(typeof descriptor.value === 'function') {
29
- const previousMethod = descriptor.value;
30
- descriptor.value = function(this: any, req: Request, res: Response) {
31
- if(req.method.toUpperCase() !== 'POST' && req.method.toUpperCase() !== 'PUT') {
32
- return previousMethod.call(this, req, res);
33
- }
34
- if(!req.body) {
35
- res.status(400).json({
36
- error: {
37
- errorKey: 'client.body.missing',
38
- additionalInfo: 'client.extended.badPayload'
39
- }
40
- });
41
- } else {
42
- if(collapseTopLevelNulls) {
43
- Object.keys(req.body).forEach(k => {
44
- if(req.body[k] === null) delete req.body[k];
45
- });
46
- }
47
- const valid = validate(req.body);
48
- if(valid) {
49
- return previousMethod.call(this, req, res);
50
- } else {
51
- res.status(400).json({
52
- error: {
53
- errorKey: 'client.body.missing',
54
- additionalInfo: 'client.extended.badPayload',
55
- detailedInfo: validate.errors
56
- }
57
- });
58
- }
59
- }
60
- };
61
- return descriptor;
62
- }
63
- return undefined;
64
- };
65
- }
1
+ import {Request, Response} from 'express';
2
+ import Ajv, {_} from 'ajv';
3
+
4
+ export const ajv = new Ajv();
5
+ ajv.addKeyword({
6
+ keyword: 'maxDigits',
7
+ type: 'number',
8
+ schemaType: 'number',
9
+ validate: (schema: number, data: any) => typeof data === 'number' && Math.round(data * 10 ** schema) / (10 ** schema) === data
10
+ });
11
+
12
+ export function WithBody(schema: any, collapseTopLevelNulls = true) {
13
+ if(schema.type === 'object') {
14
+ const required: string[] = [];
15
+ const keys = Object.getOwnPropertyNames(schema.properties);
16
+ keys.forEach(key => {
17
+ if(schema.properties[key].required === true) {
18
+ required.push(key);
19
+ }
20
+ if(schema.properties[key].required === true || schema.properties[key].required === false) {
21
+ delete schema.properties[key].required;
22
+ }
23
+ });
24
+ schema.required = required;
25
+ }
26
+ const validate = ajv.compile(schema);
27
+ return function(_: any, __: string, descriptor: PropertyDescriptor) {
28
+ if(typeof descriptor.value === 'function') {
29
+ const previousMethod = descriptor.value;
30
+ descriptor.value = function(this: any, req: Request, res: Response) {
31
+ if(req.method.toUpperCase() !== 'POST' && req.method.toUpperCase() !== 'PUT') {
32
+ return previousMethod.call(this, req, res);
33
+ }
34
+ if(!req.body) {
35
+ res.status(400).json({
36
+ error: {
37
+ errorKey: 'client.body.missing',
38
+ additionalInfo: 'client.extended.badPayload'
39
+ }
40
+ });
41
+ } else {
42
+ if(collapseTopLevelNulls) {
43
+ Object.keys(req.body).forEach(k => {
44
+ if(req.body[k] === null) delete req.body[k];
45
+ });
46
+ }
47
+ const valid = validate(req.body);
48
+ if(valid) {
49
+ return previousMethod.call(this, req, res);
50
+ } else {
51
+ res.status(400).json({
52
+ error: {
53
+ errorKey: 'client.body.missing',
54
+ additionalInfo: 'client.extended.badPayload',
55
+ detailedInfo: validate.errors
56
+ }
57
+ });
58
+ }
59
+ }
60
+ };
61
+ return descriptor;
62
+ }
63
+ return undefined;
64
+ };
65
+ }
@@ -45,7 +45,11 @@ function releaseAndDecrement(repo, dbClient) {
45
45
  try {
46
46
  dbClient.release();
47
47
  }
48
- catch (_) { }
48
+ catch (err) {
49
+ const log = utils_1.utils.logger;
50
+ if (log)
51
+ log.error('Error releasing dbClient: %j', { err, stack: new Error().stack });
52
+ }
49
53
  }
50
54
  exports.withTransactionConfig.activeCount = Math.max(0, exports.withTransactionConfig.activeCount - 1);
51
55
  }
@@ -73,7 +77,7 @@ function withTransaction(repo, logger, previousMethod, lock, commitIfLost = true
73
77
  };
74
78
  exports.withTransactionConfig.activeCount++;
75
79
  const connectTimeoutHandler = setTimeout(() => {
76
- logger.error('Error timed out getting a client, exiting...');
80
+ logger.error('Error timed out getting a client, exiting... stack: %s', new Error().stack);
77
81
  process.exit(22);
78
82
  }, exports.withTransactionConfig.timeoutMillis);
79
83
  Promise.all([
@@ -92,7 +96,14 @@ function withTransaction(repo, logger, previousMethod, lock, commitIfLost = true
92
96
  dbClient.queryPatched = true;
93
97
  }
94
98
  dbClient.removeAllListeners('error');
95
- dbClient.on('error', (err) => utils_1.utils.clientErrorHandler(err, dbClient));
99
+ dbClient.on('error', (err) => {
100
+ if (utils_1.utils.clientErrorHandler) {
101
+ utils_1.utils.clientErrorHandler(err, dbClient);
102
+ }
103
+ else {
104
+ logger.error('SQL [Client %d] ERROR (no handler): %j', dbClient?.processID, { err, stack: new Error().stack });
105
+ }
106
+ });
96
107
  res.locals.dbClient = dbClient;
97
108
  res.locals.dbClientCommited = false;
98
109
  res.locals.dbClientCommit = (cb) => {
@@ -130,10 +141,10 @@ function withTransaction(repo, logger, previousMethod, lock, commitIfLost = true
130
141
  if (res.statusCode > 303 && res.statusCode !== 412) {
131
142
  if (logger) {
132
143
  if (res.statusCode > 499) {
133
- logger.error('Uncaught 500: %j', obj?.error?.additionalInfo);
144
+ logger.error('Uncaught 500 at %s %s: %j', req.method, req.originalUrl, { body: obj, stack: new Error().stack });
134
145
  }
135
146
  else {
136
- logger.warn('Client error 4XX: %j', obj?.error);
147
+ logger.warn('Client error 4XX at %s %s: %j', req.method, req.originalUrl, { body: obj, stack: new Error().stack });
137
148
  }
138
149
  }
139
150
  (repo.db ? dbClient.query('ROLLBACK') : dbClient.rollback()).catch((err) => obj && obj.error && (obj.error.additionalInfo2 = { message: err.message })).then(() => {
@@ -161,7 +172,7 @@ function withTransaction(repo, logger, previousMethod, lock, commitIfLost = true
161
172
  res.end = () => {
162
173
  if (res.statusCode > 303 && res.statusCode !== 412) {
163
174
  if (logger && res.statusCode > 499) {
164
- logger.error('Uncaught 500 with no details...');
175
+ logger.error('Uncaught 500 with no details at %s %s: %j', req.method, req.originalUrl, { stack: new Error().stack });
165
176
  }
166
177
  (repo.db ? dbClient.query('ROLLBACK') : dbClient.rollback()).catch(() => undefined).then(() => {
167
178
  releaseAndDecrement(repo, dbClient);
@@ -189,6 +200,7 @@ function withTransaction(repo, logger, previousMethod, lock, commitIfLost = true
189
200
  };
190
201
  if (lock) {
191
202
  dbClient.query('SELECT pg_advisory_xact_lock(' + lock + ')').then(() => finish()).catch((err) => {
203
+ logger.error('Error acquiring advisory lock %d at %s %s: %j', lock, req.method, req.originalUrl, { err, stack: new Error().stack });
192
204
  res.status(500).json({
193
205
  error: {
194
206
  errorKey: 'internal.db',
@@ -203,7 +215,7 @@ function withTransaction(repo, logger, previousMethod, lock, commitIfLost = true
203
215
  }
204
216
  }).catch((err) => {
205
217
  releaseAndDecrement(repo, dbClient);
206
- logger.error('Error beginning transaction: %j', err);
218
+ logger.error('Error beginning transaction at %s %s: %j', req.method, req.originalUrl, { err, stack: new Error().stack });
207
219
  res.status(500).json({
208
220
  error: {
209
221
  errorKey: 'internal.db',
@@ -213,6 +225,7 @@ function withTransaction(repo, logger, previousMethod, lock, commitIfLost = true
213
225
  });
214
226
  }).catch(err => {
215
227
  clearTimeout(connectTimeoutHandler);
228
+ logger.error('Error connecting to database at %s %s: %j', req.method, req.originalUrl, { err, stack: new Error().stack });
216
229
  exports.withTransactionConfig.activeCount = Math.max(0, exports.withTransactionConfig.activeCount - 1);
217
230
  res.status(500).json({
218
231
  error: {