@sera4/essentia 1.0.41 → 1.1.4

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.
@@ -77,4 +77,5 @@ class S4Formatter {
77
77
  }
78
78
  }
79
79
 
80
- module.exports = new S4Formatter();
80
+ const formatter = new S4Formatter();
81
+ export default formatter;
package/hal/README.md CHANGED
@@ -7,7 +7,7 @@ A module to add HAL decoration to JSON responses in Sequelize ORM based projects
7
7
  In your model definition, set decoration on your model
8
8
 
9
9
  ```
10
- const decorator = require("@sera4/essentia").halDecorator;
10
+ import { halDecorator as decorator } from "@sera4/essentia"
11
11
  ...
12
12
 
13
13
  module.exports = (sequelize, DataTypes) => {
@@ -51,4 +51,4 @@ The above configuration (which is optional) should produce the following JSON fo
51
51
  }
52
52
  }
53
53
  ```
54
- The links use a similar pattern for parameters interpolation like the express route. For example `/posts/:id/by_user/:user_id` becomes `/posts/20/by_user/123`. If no matching attribute is found on the record, the variable is not replaced.
54
+ The links use a similar pattern for parameters interpolation like the express route. For example `/posts/:id/by_user/:user_id` becomes `/posts/20/by_user/123`. If no matching attribute is found on the record, the variable is not replaced.
package/hal/index.js CHANGED
@@ -70,4 +70,6 @@ class HalDecorator {
70
70
  }
71
71
  }
72
72
 
73
- module.exports = new HalDecorator()
73
+
74
+ const halDecorator = new HalDecorator();
75
+ export default halDecorator;
package/health/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  "use strict"
2
2
 
3
- const pathHelper = require("path");
4
- const logger = require("./health-logger");
3
+ import pathHelper from "path";
5
4
 
6
5
  class HealthCheckError extends Error {
7
6
  constructor(m) {
@@ -12,20 +11,16 @@ class HealthCheckError extends Error {
12
11
  /* Health Checking router + controller for use in all of our modules
13
12
  * Example use: Place the following code in your routes file
14
13
  *
15
- * const hc = require("@sera4/essentia").healthCheck;
14
+ * import { healthCheck } from "@sera4/essentia";
16
15
  * const router = require('express').Router();
17
16
  *
18
17
  * ....
19
- *
20
- * const checkRedis = async () => { await cache.ping(); }
21
- * hc.setupCheck({ name: "redis", checkResult: false, critical: true, healthFunction: checkRedis });
22
18
  * app.use(hc.defaultPath(serverConfigs.api_prefix), hc.routes(router));
23
19
  *
24
20
  */
25
- class HealthCheck {
26
- constructor(appendData = {}, enableLogging = true) {
27
- logger.setEnabled(enableLogging);
28
21
 
22
+ class HealthCheck {
23
+ constructor(appendData = {}) {
29
24
  this.defaultResponse = {
30
25
  ...
31
26
  appendData,
@@ -34,13 +29,11 @@ class HealthCheck {
34
29
  };
35
30
 
36
31
  this.defaultPathRoute = `health_check\(.*\)?`
37
- this.suppressLogs = false;
38
32
  this.lastCallId = 0; // default start point/integer
39
33
  this.healthChecks = [];
40
34
  }
41
35
 
42
- /* Deprecated and replaced by setupCheck
43
- * call this with an async function, must support wait capability
36
+ /* call this with an async function, must support wait capability
44
37
  *
45
38
  * const dbCheck = async () => {
46
39
  * return { name: "db", "result": "success", critical: false };
@@ -67,40 +60,15 @@ class HealthCheck {
67
60
  return router
68
61
  }
69
62
 
70
- // v2 version of health check, replaced addCheck
71
- // example:
72
- // const checkRedisFcn = async () => { await cache.ping().then(() => true) }
73
- // setupCheck({ name: "redis", checkResult: false, critical: false, healthFunction: checkRedisFcn });
74
- setupCheck(config) {
75
- this.healthChecks.push(config);
76
- }
77
-
78
- /* performs health checks and returns 200 if true and 500 if not */
63
+ /* performs health checks and returns 200 if true and 500 if not */
79
64
  async checkHealth(req, res) {
80
65
  const checkFormat = pathHelper.extname(req.baseUrl);
81
66
 
82
- const result = await Promise.all(this.healthChecks.map(async hc => {
83
- if (typeof(hc) === "function") {
84
- try {
85
- return await hc();
86
- return { "result": "success", critical: false };
87
- } catch(e) {
88
- return { name: "unknown", result: 'fail', status: e.status }
89
- }
90
- } else {
91
- let res = { name: hc.name, critical: hc.critical }
92
- try {
93
- await hc.healthFunction();
94
- return { ...res, "result": "success" };
95
- } catch(e) {
96
- const appendStatus = e.status ? ` (${e.status})` : ""
97
- logger.warn(`${hc.name} service failed${appendStatus}` )
98
- return { ...res, "result": "fail", status: e.status }
99
- }
100
- }
101
- }));
102
-
103
67
  try {
68
+ const result = await Promise.all(this.healthChecks.map(async healthCallback => {
69
+ return await healthCallback();
70
+ }));
71
+
104
72
  let callId = ++this.lastCallId;
105
73
 
106
74
  // start the counter over
@@ -110,18 +78,10 @@ class HealthCheck {
110
78
 
111
79
  let status = this.defaultResponse.status;
112
80
 
113
- let nonCriticalFail = false;
114
- let criticalFail = false;
115
-
116
81
  result.some(e => {
117
82
  if (e.result.match(/fail/)) {
118
- if (e.critical == false) {
119
- nonCriticalFail = true;
120
- } else {
121
- criticalFail = true;
122
- status = 500;
123
- return true; // break
124
- }
83
+ status = 500;
84
+ return true; // break
125
85
  }
126
86
  })
127
87
 
@@ -129,39 +89,37 @@ class HealthCheck {
129
89
  res.setHeader('check', callId)
130
90
 
131
91
  if (checkFormat === ".json") {
132
- const payload = { "check": callId, healthy: "true", message: "success" }
92
+ const payload = { "check": callId }
133
93
 
134
- if (criticalFail) {
94
+ if (status === 200) {
135
95
  res.status(status).json({
136
96
  ... payload,
137
- "healthy": false,
138
- "message": "fail",
139
- "services": result
97
+ "healthy":true,
98
+ "message":"success"
140
99
  });
141
- } else if (nonCriticalFail) {
100
+ } else {
142
101
  res.status(status).json({
143
102
  ... payload,
103
+ "healthy": false,
144
104
  "message": "fail",
145
- "services": result
105
+ "services": [result]
146
106
  });
147
- } else if (status === 200) {
148
- res.status(status).json(payload);
149
107
  }
150
108
  } else {
151
109
  let status_message;
152
- if (criticalFail) {
153
- status_message = "fail"
154
- } else if ((status === 200) || nonCriticalFail) {
110
+ if (status === 200) {
155
111
  status_message = "success"
156
- }
112
+ } else {
113
+ status_message = "fail"
114
+ }
157
115
 
158
116
  res.status(status).send(status_message);
159
117
  }
160
118
  } catch(error) {
161
- console.debug("error: ", error)
162
119
  res.status(500).send();
163
120
  }
164
121
  }
165
122
  }
166
123
 
167
- module.exports = HealthCheck;
124
+
125
+ export { HealthCheck };
package/index.js CHANGED
@@ -1,14 +1,23 @@
1
1
  'use strict';
2
2
 
3
- module.exports = {
4
- paginator : require("./paginator/s4-pagination"),
5
- sqlPaginator : require("./paginator/sql-pagination"),
6
- logger : require("./logger/s4-logger"),
7
- lastCommit : require("./last_commit"),
8
- halDecorator : require("./hal"),
9
- formatter : require("./formatter"),
10
- healthCheck : require("./health"),
11
- queue : require("./queue"),
12
- utils : require("./utils"),
13
- safeProxy : require("./safe_proxy")
14
- }
3
+ export { default as paginator } from "./paginator/s4-pagination.js";
4
+ export { default as sqlPaginator } from "./paginator/sql-pagination.js";
5
+ export { default as logger } from "./logger/s4-logger.js";
6
+ export { default as lastCommit } from "./last_commit/index.js";
7
+ export { default as halDecorator } from "./hal/index.js";
8
+ export { default as formatter } from "./formatter/index.js";
9
+ export { HealthCheck as healthCheck } from "./health/index.js";
10
+ export { default as queue } from "./queue/index.js";
11
+ export { default as utils } from "./utils/index.js";
12
+
13
+ //export default {
14
+ // paginator : require("./paginator/s4-pagination"),
15
+ // sqlPaginator : require("./paginator/sql-pagination"),
16
+ // logger : require("./logger/s4-logger"),
17
+ // lastCommit : require("./last_commit"),
18
+ // halDecorator : require("./hal"),
19
+ // formatter : require("./formatter"),
20
+ // healthCheck : require("./health"),
21
+ // queue : require("./queue"),
22
+ // utils : require("./utils")
23
+ //}
package/last-commit.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
- const lastCommit = require("./last_commit");
2
+ import lastCommit from "./last_commit/index.js"
3
+
3
4
  lastCommit.writeLastCommit()
4
5
  .then(c => {
5
6
  console.debug("Last commit written");
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
 
3
- const git = require('git-rev');
4
- const fs = require('fs');
5
- const async = require('async');
6
- const path = require('path');
7
- const appDir = path.dirname(require.main.filename);
3
+ import git from "git-rev";
4
+ import fs from "fs";
5
+ import async from "async";
6
+ import { dirname } from 'path';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ const appDir = dirname(fileURLToPath(import.meta.url));
8
10
  const commitFile = `${appDir}/last-commit.json`;
9
11
 
10
- module.exports = {
12
+ const lastCommit = {
11
13
  parseLastCommit() {
12
14
  return new Promise((resolve, reject) => {
13
15
  async.waterfall([
@@ -75,4 +77,6 @@ module.exports = {
75
77
  })
76
78
  });
77
79
  }
78
- }
80
+ }
81
+
82
+ export default lastCommit;
@@ -1,25 +1,8 @@
1
- const winston = require('winston');
2
- const util = require('util');
3
- const jsonStringify = require('fast-safe-stringify');
1
+ import winston from "winston";
2
+ import util from "util";
3
+ import jsonStringify from "fast-safe-stringify";
4
4
  const colorizer = winston.format.colorize();
5
-
6
- require('winston-logstash');
7
-
8
- // IETF RFC5424:
9
- // Severity of all levels is assumed to be numerically ascending from most important to least important.
10
- const levels = {
11
- error: 0,
12
- warn: 1,
13
- info: 2,
14
- debug: 3,
15
- trace: 4,
16
- }
17
-
18
- // These colors are not used, however if colors are not defined for custom levels
19
- // then winston will throw an exception.
20
- winston.addColors({
21
- trace: 'white'
22
- })
5
+ import "winston-logstash";
23
6
 
24
7
  const devFormat = {
25
8
  transform(info) {
@@ -33,12 +16,10 @@ const devFormat = {
33
16
  };
34
17
 
35
18
  const defaultTransport = new winston.transports.Console({
36
- format: devFormat,
37
- level: 'trace'
19
+ format: devFormat
38
20
  });
39
21
 
40
22
  const logger = winston.createLogger({
41
- levels: levels,
42
23
  level: 'debug',
43
24
  defaultMeta: { },
44
25
  transports: [defaultTransport]
@@ -50,7 +31,9 @@ class S4Logger {
50
31
  return;
51
32
  }
52
33
 
53
- this.setLevel(options.level)
34
+ if (options.level && ["debug", "info", "error", "warn"].indexOf(options.level.toLowerCase())) {
35
+ logger.level = options.level;
36
+ }
54
37
 
55
38
  logger.defaultMeta.service = options.service;
56
39
  switch(options.format.toLowerCase()) {
@@ -67,7 +50,7 @@ class S4Logger {
67
50
  }
68
51
 
69
52
  setLevel(level) {
70
- if (level && ["trace", "debug", "info", "error", "warn"].indexOf(level.toLowerCase())) {
53
+ if (level && ["debug", "info", "error", "warn"].indexOf(level.toLowerCase())) {
71
54
  logger.level = level;
72
55
  }
73
56
  }
@@ -84,10 +67,6 @@ class S4Logger {
84
67
  });
85
68
  }
86
69
 
87
- trace(...args) {
88
- logger.trace(util.format(...args));
89
- }
90
-
91
70
  debug(...args) {
92
71
  logger.debug(util.format(...args));
93
72
  }
@@ -117,4 +96,5 @@ class S4Logger {
117
96
  }
118
97
  }
119
98
 
120
- module.exports = new S4Logger();
99
+ const s4logger = new S4Logger();
100
+ export default s4logger;
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@sera4/essentia",
3
- "version": "1.0.41",
3
+ "version": "1.1.4",
4
4
  "description": "A library of utilities for Teleporte Web Services",
5
5
  "main": "index.js",
6
+ "type": "module",
6
7
  "scripts": {
7
8
  "test": "NODE_ENV=test ./node_modules/.bin/mocha --forbid-only --reporter mocha-junit-reporter --reporter-options mochaFile=./test-results/result.xml --exit",
8
9
  "test:dev": "NODE_ENV=test ./node_modules/.bin/mocha --watch --forbid-only",
@@ -17,25 +18,23 @@
17
18
  },
18
19
  "license": "UNLICENSED",
19
20
  "devDependencies": {
20
- "chai": "^4.1.2",
21
- "express": "^4.16.4",
22
- "mocha": "^5.1.1",
23
- "mocha-junit-reporter": "^1.17.0",
24
- "node-mocks-http": "^1.5.8",
25
- "nodemon": "^1.17.3",
26
- "should": "^13.2.1",
27
- "sinon": "^5.0.1"
21
+ "chai": "^4.3.4",
22
+ "express": "^4.17.1",
23
+ "mocha": "^8.3.2",
24
+ "mocha-junit-reporter": "^1.23.3",
25
+ "node-mocks-http": "^1.10.1",
26
+ "nodemon": "^2.0.7",
27
+ "should": "^13.2.3",
28
+ "sinon": "^5.1.1"
28
29
  },
29
30
  "dependencies": {
30
- "amqplib": "^0.8.0",
31
- "async": "^2.6.1",
32
- "axios": "^0.21.1",
33
- "fast-safe-stringify": "^2.0.6",
31
+ "amqplib": "^0.5.6",
32
+ "async": "^2.6.3",
33
+ "fast-safe-stringify": "^2.0.7",
34
34
  "git-rev": "^0.2.1",
35
- "lodash": "^4.17.21",
36
35
  "url-parse": "^1.5.1",
37
- "uuid": "^3.3.3",
38
- "winston": "^3.2.1",
36
+ "uuid": "^3.4.0",
37
+ "winston": "^3.3.3",
39
38
  "winston-logstash": "^0.4.0"
40
39
  }
41
40
  }
package/package.tar.gz CHANGED
Binary file
@@ -7,7 +7,7 @@ This is a module to add pagination to Sequelize ORM based projects.
7
7
  In your model definition, set pagination on your model
8
8
 
9
9
  ```
10
- const paginator = require("@sera4/essentia").sqlPaginator;
10
+ import { paginator } from "@sera4/essentia";
11
11
  ...
12
12
 
13
13
  module.exports = (sequelize, DataTypes) => {
@@ -155,7 +155,7 @@ You may notice that the links in the pagination only have query parameters. If y
155
155
 
156
156
  For example:
157
157
  ```
158
- const paginator = require("@sera4/essentia).sqlPaginator;
158
+ import { paginator } from "@sera4/essentia"
159
159
  ...
160
160
 
161
161
  module.exports = (sequelize, DataTypes) => {
@@ -47,4 +47,5 @@ class S4Pagination {
47
47
  }
48
48
  }
49
49
 
50
- module.exports = new S4Pagination();
50
+ const paginator = new S4Pagination();
51
+ export default paginator;
@@ -166,4 +166,5 @@ class SequelizePaginator {
166
166
  }
167
167
  }
168
168
 
169
- module.exports = new SequelizePaginator();
169
+ const sqlPaginator = new SequelizePaginator();
170
+ export default sqlPaginator;
package/queue/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
- const amqp = require("amqplib/callback_api");
3
- const logger = require("./queue-logger");
4
- const urlParse = require("url-parse");
5
- const { Publisher } = require("./publisher");
6
- const { Subscriber } = require("./subscriber");
2
+ import amqp from "amqplib/callback_api.js";
3
+ import logger from "./queue-logger.js";
4
+ import urlParse from "url-parse";
5
+ import { Publisher } from "./publisher.js";
6
+ import { Subscriber } from "./subscriber.js";
7
7
 
8
8
  /**
9
9
  * An interface to AMQP service
@@ -29,7 +29,6 @@ class S4Queue {
29
29
  */
30
30
  async testConnection() {
31
31
  if (!this.isConnected()) {
32
- this.connectionTestChannel = null;
33
32
  throw("queue service not connected")
34
33
  }
35
34
 
@@ -73,16 +72,12 @@ class S4Queue {
73
72
  amqp.connect(options.connectionUrl, socketOptions, (err, conn) => {
74
73
 
75
74
  if (err) {
76
- logger.error("Error while connecting", err)
77
- logger.error("Attempting again in", this.retry, "seconds");
78
- return setTimeout(() => this.openConnection(options), this.retry * 1000);
75
+ return reject(err);
79
76
  }
80
77
 
81
78
  this.connection = conn;
82
79
  if (!this.connection) {
83
80
  return reject(new Error("Failed to obtain connection"));
84
- } else {
85
- this.updatePubsAndSubsConnectionRef(conn);
86
81
  }
87
82
 
88
83
  this.connection.on("error", (err) => {
@@ -96,8 +91,8 @@ class S4Queue {
96
91
  logger.error("connection closed");
97
92
  this.connection = null;
98
93
  if (err) {
99
- logger.error("connection closed due to error:", err);
100
- logger.error("Reconnecting in", this.retry, "seconds");
94
+ logger.debug("connection closed due to error:", err);
95
+ logger.debug("Reconnecting in", this.retry, "seconds");
101
96
  setTimeout(() => this.openConnection(options), this.retry * 1000);
102
97
  } else {
103
98
  // If there was no error, it is us who closed
@@ -176,22 +171,6 @@ class S4Queue {
176
171
  this.pubs[name] = p;
177
172
  }
178
173
 
179
- /**
180
- * Registers a new fanout publisher on the given exchange.
181
- * If exchange doesn't exist, one will be created.
182
- * @param {String} exchange the name of the exchange on AMQP service.
183
- */
184
- async registerFanoutPublisher(exchange) {
185
- const name = exchange;
186
- if (Object.keys(this.pubs).includes(name)) {
187
- throw new Error(`Publisher ${name} already registered`);
188
- }
189
-
190
- const p = new Publisher(exchange, 'fanout', true, name);
191
- await p.init(this.connection);
192
- this.pubs[name] = p;
193
- }
194
-
195
174
  /**
196
175
  * Registers a new direct subscriber on a given exchange and queue.
197
176
  * If exchange and queue don't exists, they'll be created
@@ -294,28 +273,6 @@ class S4Queue {
294
273
  return await p.publish({key: topic, content});
295
274
  }
296
275
 
297
- /**
298
- * Binds an exchange to a queue
299
- * @param {String} exchange the name of the exchange.
300
- * @param {String} queue the name of the queue.
301
- * @param {pattern} (optional) pattern for routing key
302
- */
303
- async bindQueueToExchange(exchange, queue, pattern) {
304
- const p = this.pubs[exchange];
305
-
306
- if (!p) {
307
- throw(new Error(`No PUB for ${exchange} found`));
308
- }
309
-
310
- if (!queue) {
311
- throw(new Error(`Binding a queue requires a queue name`));
312
- }
313
-
314
- return await p.bindQueue(queue, pattern)
315
- }
316
-
317
-
318
-
319
276
  /**
320
277
  * Adds a listener for a specific key.
321
278
  * If a subscriber that was regitered was found
@@ -332,29 +289,7 @@ class S4Queue {
332
289
  }
333
290
  });
334
291
  }
335
-
336
- /**
337
- * Updates the connection reference to all the previously
338
- * registered publishers and subscribers.
339
- * After we successfully establish a connection and register pubs/subs,
340
- * it's possible for the connection to break. This object will try
341
- * to re-establish a new connection every 3 seconds (or whatever configuration is set)
342
- * and if a new connection is established, we need to pass that connection to
343
- * all our pubs/subs, otherwise they'll be operating with old/stale references
344
- * @param {Object} connRef a new connection reference to the AMQP service
345
- */
346
- updatePubsAndSubsConnectionRef(connRef) {
347
- Object.keys(this.pubs).forEach(k => {
348
- logger.debug(`Updating publisher ${k} with a new connection object`);
349
- const p = this.pubs[k];
350
- p.init(connRef);
351
- });
352
- Object.keys(this.subs).forEach(k => {
353
- logger.debug(`Updating subscriber ${k} with a new connection object`);
354
- const s = this.subs[k];
355
- s.init(connRef);
356
- });
357
- }
358
292
  }
359
293
 
360
- module.exports = new S4Queue();
294
+ const queue = new S4Queue();
295
+ export default queue;
@@ -1,10 +1,10 @@
1
- const logger = require("./queue-logger");
2
- const uuidv4 = require("uuid/v4");
1
+ import logger from "./queue-logger.js";
2
+ import uuidv4 from "uuid/v4.js";
3
3
 
4
4
  /**
5
5
  * A publisher for AMQP service
6
6
  */
7
- class Publisher {
7
+ export class Publisher {
8
8
 
9
9
  /**
10
10
  *
@@ -80,12 +80,4 @@ class Publisher {
80
80
 
81
81
  return parcel.tracking_id;
82
82
  }
83
-
84
- async bindQueue(queue, pattern, args) {
85
- await this.channel.bindQueue(queue, this.exchange, pattern, args)
86
- }
87
- }
88
-
89
- module.exports = {
90
- Publisher
91
83
  }
@@ -1,7 +1,7 @@
1
- const logger = require("../logger/s4-logger");
1
+ import logger from "../logger/s4-logger.js";
2
2
  let enabled = false;
3
3
 
4
- module.exports = {
4
+ const helpers = {
5
5
  debug(...args) {
6
6
  if (enabled) {
7
7
  logger.debug(":: AMQP ::", args);
@@ -35,4 +35,6 @@ module.exports = {
35
35
  setEnabled(e) {
36
36
  enabled = e;
37
37
  }
38
- }
38
+ }
39
+
40
+ export default helpers;
@@ -1,9 +1,9 @@
1
- const logger = require("./queue-logger");
1
+ import logger from "./queue-logger.js";
2
2
 
3
3
  /**
4
4
  * A subscriber for AMQP service
5
5
  */
6
- class Subscriber {
6
+ export class Subscriber {
7
7
 
8
8
  /**
9
9
  * Builds a subscriber
@@ -89,7 +89,3 @@ class Subscriber {
89
89
  this.callbacks.push(cb);
90
90
  }
91
91
  }
92
-
93
- module.exports = {
94
- Subscriber
95
- }
package/utils/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- module.exports = {
3
+ const utils = {
4
4
  isValidUuidV4 : (input) => {
5
5
  if (!input) {
6
6
  return false
@@ -10,8 +10,8 @@ module.exports = {
10
10
  },
11
11
  // convert a regular string or Array to array (ie, "[1,2,3]", "1,2,3")
12
12
  // useful for controller inputs
13
- convertToIntegerArray: (input) => {
14
- return module.exports.convertToArray(input)
13
+ convertToIntegerArray(input) {
14
+ return this.convertToArray(input)
15
15
  .filter((el) => /^[0-9]+/.test(el))
16
16
  .map((el) => parseInt(el));
17
17
  },
@@ -36,3 +36,5 @@ module.exports = {
36
36
  }
37
37
  }
38
38
  }
39
+
40
+ export default utils;
package/cache/index.js DELETED
@@ -1,188 +0,0 @@
1
- "use strict"
2
-
3
- import { promisify } from "util";
4
-
5
- const isEmpty = obj => [Object, Array].includes((obj || {}).constructor) && !Object.entries((obj || {})).length;
6
-
7
- class CacheConfigError extends Error {
8
- constructor(m) {
9
- super(m);
10
- }
11
- }
12
-
13
- /* Redis cache helper
14
- * Example use: Place the following code in your project to setup redis use
15
- *
16
- * import { cache } from "@sera4/essentia";
17
- * const cacheHelper = cache({ password: .., database: .., host: .., port: .. }, "service:"));
18
- *
19
- */
20
-
21
- const convertRedisKeyValueToJson = (v) => {
22
- return (v && v.length > 0 && v[0] !== null) ? JSON.parse(v) : null;
23
- }
24
-
25
- const convertRedisHashToJson = (v) => {
26
- if (v) {
27
- var result = {};
28
- for(var k in v) {
29
- if (v.hasOwnProperty(k)) {
30
- result[k] = JSON.parse(v[k]);
31
- }
32
- }
33
- return result;
34
- } else {
35
- return null;
36
- }
37
- }
38
-
39
- function convertJsonToRedisValue(j) {
40
- var result = {};
41
- for (var key in j) {
42
- if (j.hasOwnProperty(key)) {
43
- result[key] = JSON.stringify(j[key]);
44
- }
45
- }
46
- return result;
47
- }
48
-
49
- class Cache {
50
- constructor(config, servicePrefix) {
51
- if ((config == undefined) || isEmpty(config)) {
52
- throw new CacheConfigError("Invalid cache configuration");
53
- }
54
-
55
- if (servicePrefix == null) {
56
- throw new CacheConfigError("Invalid service prefix");
57
- }
58
-
59
- if (config.fake) {
60
- // used in testing
61
- this.redisClient = require("fakeredis").createClient("fake backend")
62
- } else {
63
- this.redisClient = require("redis").createClient(config);
64
- }
65
-
66
- this.redisClient.on("error", (err) => {
67
- logger.error("Cache/Redis error: ", err);
68
- });
69
-
70
- this.servicePrefix = servicePrefix;
71
- }
72
-
73
- ping() {
74
- return this.redisClient.ping();
75
- }
76
-
77
- properKey(key, path) {
78
- let p = this.servicePrefix + key
79
- if (path)
80
- p += path
81
- return p
82
- }
83
-
84
- writeHash(path, key, value) {
85
- return this.redisClient.hsetAsync(properKey(key), key, value);
86
- }
87
-
88
- writeHashBlocking(path, key, value) {
89
- return this.redisClient.hset(properKey(key), key, value);
90
- }
91
-
92
- // write multiple hash keys and stringify every value
93
- writeMultiHash(path, j) {
94
- return this.redisClient.hmsetAsync(properKey(key), convertJsonToRedisValue(j));
95
- }
96
-
97
- readHashKey(obj, key, autoConvert=true) {
98
- var k = autoConvert;
99
-
100
- return new Promise((resolve, reject) => {
101
- this.redisClient.hget(properKey(key, obj), key, (e, r) => {
102
- if (e) {
103
- logger.error("Redis hmget error:", e);
104
- reject(e);
105
- } else {
106
- resolve(k ? convertRedisKeyValueToJson(r) : r);
107
- }
108
- });
109
- });
110
- }
111
-
112
- readHash(path) {
113
- return new Promise((resolve, reject) => {
114
- this.redisClient.hgetall(properKey(key, path), (e, r) => {
115
- if (e) {
116
- console.log("Redis hget error:", e);
117
- reject(e);
118
- } else {
119
- resolve(convertRedisHashToJson(r));
120
- }
121
- });
122
- });
123
- }
124
-
125
- deleteHashKey(hash, key) {
126
- return new Promise((resolve, reject) => {
127
- this.redisClient.hdel(properKey(key, hash), key, (err) => {
128
- if (err) {
129
- logger.error("Redis hdel error:", err);
130
- reject(err);
131
- } else {
132
- resolve();
133
- }
134
- });
135
- });
136
- }
137
-
138
- get(key) {
139
- return this.redisClient.getAsync(properKey(key));
140
- }
141
-
142
- getAsync(key) {
143
- return promisify(this.redisClient.get(key)).bind(this.redisClient)
144
- }
145
-
146
-
147
- /* a single key write with optional expiry */
148
- // returns bluebird promise
149
- writeKey(key, value, expiry) {
150
- key = this.servicePrefix + key;
151
- if (expiry) {
152
- return this.redisClient.setAsync(key, value, "EX", expiry);
153
- } else {
154
- return this.redisClient.setAsync(key, value);
155
- }
156
- }
157
-
158
- deleteKey(key) {
159
- return redisClient.delAsync(properKey(key));
160
- }
161
-
162
- expire(path, expiry) {
163
- return this.redisClient.expire(path, expiry);
164
- }
165
-
166
- exists(path) {
167
- return this.redisClient.exists(path);
168
- }
169
-
170
- deleteAllKeys() {
171
- return new Promise((resolve, reject) => {
172
- if(process.env.NODE_ENV === "production") {
173
- throw new Error("Clearing system cache is not permitted in production");
174
- }
175
- this.redisClient.flushdb((err, res) => {
176
- if (err) {
177
- reject(err);
178
- } else {
179
- resolve(res);
180
- }
181
- });
182
- });
183
- }
184
- }
185
-
186
- export default function(config, servicePrefix) {
187
- return new Cache(config, servicePrefix)
188
- }
@@ -1,38 +0,0 @@
1
- const logger = require("../logger/s4-logger");
2
- let enabled = false;
3
-
4
- module.exports = {
5
- debug(...args) {
6
- if (enabled) {
7
- logger.debug(":: HealthCheck ::", args);
8
- }
9
- },
10
-
11
- log(...args) {
12
- if (enabled) {
13
- logger.debug(":: HealthCheck ::", args);
14
- }
15
- },
16
-
17
- warn(...args) {
18
- if (enabled) {
19
- logger.warn(":: HealthCheck ::", args);
20
- }
21
- },
22
-
23
- info(...args) {
24
- if (enabled) {
25
- logger.info(":: HealthCheck ::", args);
26
- }
27
- },
28
-
29
- error(...args) {
30
- if (enabled) {
31
- logger.error(":: HealthCheck ::", args);
32
- }
33
- },
34
-
35
- setEnabled(e) {
36
- enabled = e;
37
- }
38
- }
@@ -1,59 +0,0 @@
1
- "use strict";
2
-
3
- const axios = require("axios"); // required only until migration is complete
4
- const { omitBy, isNil } = require("lodash");
5
-
6
- /* A class which safely wraps an axios connection in order to pass the current user through to
7
- * the next service. Useful when one of our microservices requires auth as either an admin (sera4tal)
8
- * or as the end user (example: DELETE /auth/sessions/:id
9
- *
10
- * each method requires a res.locals from a pre-authd session
11
- */
12
- class SafeProxy {
13
- constructor() {
14
- }
15
-
16
- // a safe post request
17
- // locals = res.locals - your authentication details
18
- post(locals, url, options = { headers: {}, data: {}}) {
19
- let { account, tenant, membership } = locals;
20
- return this._proxyRequest({ account, tenant, membership }, url, "post", options);
21
- }
22
- delete(locals, url, options = { headers: {}, data: {}}) {
23
- let { account, tenant, membership } = locals;
24
- return this._proxyRequest({ account, tenant, membership }, url, "delete", options);
25
- }
26
-
27
- /* private methods */
28
- // supports get, delete, post
29
- // options includes { headers, data } for post / delete payloads
30
- async _proxyRequest(locals, url, method = "get", options) {
31
- let request;
32
- let membership = locals.membership ? JSON.stringify(locals.membership) : null;
33
- let headers = omitBy({ ...options.headers,
34
- "tws-account-id": locals.account?.id,
35
- "tws-tenant-id": locals.tenant?.id,
36
- "tws-membership-id": locals.membership?.id,
37
- "tws-membership": membership
38
- }, isNil);
39
-
40
- switch(method) {
41
- case "post":
42
- request = axios.post(url, { ...options.data }, { headers })
43
- break;
44
- case "delete":
45
- request = axios.delete(url, { ...options.data, headers } )
46
- break;
47
- case "get":
48
- request = axios.get(url, { headers, data } )
49
- break;
50
- default:
51
- throw new Error("uknown type called in proxyRequest");
52
- }
53
-
54
- return request;
55
- }
56
-
57
- }
58
-
59
- module.exports = new SafeProxy();