@sera4/essentia 1.1.65 → 3.0.6
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/README.md +352 -8
- package/dist/ts/cache/index.d.ts +33 -0
- package/dist/ts/cache/index.js +171 -0
- package/dist/ts/cache/index.js.map +1 -0
- package/dist/ts/configurations/server-config.d.ts +4 -0
- package/dist/ts/configurations/server-config.js +2 -0
- package/dist/ts/configurations/server-config.js.map +1 -0
- package/dist/ts/constants/index.d.ts +7 -0
- package/{constants → dist/ts/constants}/index.js +5 -6
- package/dist/ts/constants/index.js.map +1 -0
- package/dist/ts/cycle/index.d.ts +53 -0
- package/dist/ts/cycle/index.js +169 -0
- package/dist/ts/cycle/index.js.map +1 -0
- package/dist/ts/dns/DnsCache.d.ts +50 -0
- package/dist/ts/dns/DnsCache.js +137 -0
- package/dist/ts/dns/DnsCache.js.map +1 -0
- package/dist/ts/dns/index.d.ts +4 -0
- package/dist/ts/dns/index.js +4 -0
- package/dist/ts/dns/index.js.map +1 -0
- package/dist/ts/formatter/index.d.ts +44 -0
- package/dist/ts/formatter/index.js +76 -0
- package/dist/ts/formatter/index.js.map +1 -0
- package/dist/ts/hal/index.d.ts +26 -0
- package/dist/ts/hal/index.js +70 -0
- package/dist/ts/hal/index.js.map +1 -0
- package/dist/ts/health/index.d.ts +53 -0
- package/dist/ts/health/index.js +165 -0
- package/dist/ts/health/index.js.map +1 -0
- package/dist/ts/helpers/index.d.ts +1 -0
- package/dist/ts/helpers/index.js +2 -0
- package/dist/ts/helpers/index.js.map +1 -0
- package/dist/ts/helpers/test-server-wrapper.d.ts +56 -0
- package/dist/ts/helpers/test-server-wrapper.js +144 -0
- package/dist/ts/helpers/test-server-wrapper.js.map +1 -0
- package/dist/ts/index.d.ts +21 -0
- package/dist/ts/index.js +25 -0
- package/dist/ts/index.js.map +1 -0
- package/dist/ts/last-commit/index.d.ts +12 -0
- package/dist/ts/last-commit/index.js +82 -0
- package/dist/ts/last-commit/index.js.map +1 -0
- package/dist/ts/logger/index.d.ts +3 -0
- package/dist/ts/logger/index.js +4 -0
- package/dist/ts/logger/index.js.map +1 -0
- package/dist/ts/logger/s4-logger.d.ts +23 -0
- package/dist/ts/logger/s4-logger.js +103 -0
- package/dist/ts/logger/s4-logger.js.map +1 -0
- package/dist/ts/paginator/index.d.ts +2 -0
- package/dist/ts/paginator/index.js +3 -0
- package/dist/ts/paginator/index.js.map +1 -0
- package/dist/ts/paginator/s4-pagination.d.ts +26 -0
- package/dist/ts/paginator/s4-pagination.js +49 -0
- package/dist/ts/paginator/s4-pagination.js.map +1 -0
- package/dist/ts/paginator/sql-pagination.d.ts +52 -0
- package/dist/ts/paginator/sql-pagination.js +157 -0
- package/dist/ts/paginator/sql-pagination.js.map +1 -0
- package/dist/ts/paper-trail/helpers.d.ts +14 -0
- package/dist/ts/paper-trail/helpers.js +74 -0
- package/dist/ts/paper-trail/helpers.js.map +1 -0
- package/dist/ts/paper-trail/index.d.ts +54 -0
- package/dist/ts/paper-trail/index.js +236 -0
- package/dist/ts/paper-trail/index.js.map +1 -0
- package/dist/ts/prompts/index.d.ts +21 -0
- package/dist/ts/prompts/index.js +68 -0
- package/dist/ts/prompts/index.js.map +1 -0
- package/dist/ts/queue/index.d.ts +196 -0
- package/dist/ts/queue/index.js +371 -0
- package/dist/ts/queue/index.js.map +1 -0
- package/dist/ts/queue/publisher.d.ts +41 -0
- package/dist/ts/queue/publisher.js +84 -0
- package/dist/ts/queue/publisher.js.map +1 -0
- package/dist/ts/queue/queue-logger.d.ts +10 -0
- package/dist/ts/queue/queue-logger.js +35 -0
- package/dist/ts/queue/queue-logger.js.map +1 -0
- package/dist/ts/queue/subscriber.d.ts +55 -0
- package/dist/ts/queue/subscriber.js +98 -0
- package/dist/ts/queue/subscriber.js.map +1 -0
- package/dist/ts/safe-proxy/index.d.ts +35 -0
- package/dist/ts/safe-proxy/index.js +54 -0
- package/dist/ts/safe-proxy/index.js.map +1 -0
- package/dist/ts/serializer/index.d.ts +52 -0
- package/dist/ts/serializer/index.js +83 -0
- package/dist/ts/serializer/index.js.map +1 -0
- package/dist/ts/utils/index.d.ts +49 -0
- package/dist/ts/utils/index.js +157 -0
- package/dist/ts/utils/index.js.map +1 -0
- package/package.json +52 -11
- package/package.tar.gz +0 -0
- package/cache/index.js +0 -188
- package/formatter/index.js +0 -81
- package/hal/README.md +0 -54
- package/hal/index.js +0 -75
- package/health/health-logger.js +0 -40
- package/health/index.js +0 -188
- package/helpers/index.js +0 -1
- package/helpers/test-server-wrapper.js +0 -196
- package/last-commit.js +0 -12
- package/last_commit/index.js +0 -82
- package/logger/s4-logger.js +0 -128
- package/paginator/README.md +0 -183
- package/paginator/s4-pagination.js +0 -51
- package/paginator/sql-pagination.js +0 -178
- package/paper-trail/README.md +0 -68
- package/paper-trail/helpers.js +0 -99
- package/paper-trail/index.js +0 -842
- package/prompts/index.js +0 -78
- package/queue/index.js +0 -414
- package/queue/publisher.js +0 -96
- package/queue/queue-logger.js +0 -40
- package/queue/subscriber.js +0 -107
- package/safe_proxy/index.js +0 -61
- package/serializer/index.js +0 -90
- package/utils/index.js +0 -74
package/package.tar.gz
CHANGED
|
Binary file
|
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
|
-
}
|
package/formatter/index.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
|
|
3
|
-
class FormatError extends Error {
|
|
4
|
-
constructor(m) {
|
|
5
|
-
super(m);
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// helps to clean up response formats for services responding to rest requests
|
|
10
|
-
class S4Formatter {
|
|
11
|
-
constructor() {
|
|
12
|
-
this.defaults = {
|
|
13
|
-
status: 422,
|
|
14
|
-
errors: {}
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
_isArray (value) {
|
|
19
|
-
return value && typeof value === 'object' && value.constructor === Array;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
_fromHash(error) {
|
|
23
|
-
let response = Object.assign({}, this.defaults);
|
|
24
|
-
|
|
25
|
-
if (error.status) {
|
|
26
|
-
let errorStatus = parseInt(error.status);
|
|
27
|
-
|
|
28
|
-
if ((errorStatus >= 200) && (errorStatus < 522)) {
|
|
29
|
-
response.status = errorStatus
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (error.error && (typeof(error.error) === "string")) {
|
|
34
|
-
response.errors["generic"] = { msg: error.error }
|
|
35
|
-
} else if (error.errors) {
|
|
36
|
-
if (this._isArray(error.errors)) {
|
|
37
|
-
// many legacy responses which are errors: ["error_name"]
|
|
38
|
-
error.errors.forEach(function(el, index) {
|
|
39
|
-
response.errors[`generic_${index}`] = { msg: el }
|
|
40
|
-
})
|
|
41
|
-
} else if (typeof(error.errors) === "object") {
|
|
42
|
-
response.errors = error.errors
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return response;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Desired Response format
|
|
51
|
-
*{
|
|
52
|
-
* "error": {
|
|
53
|
-
* "status": 422,
|
|
54
|
-
* "errors": {
|
|
55
|
-
* "password": {
|
|
56
|
-
* "location": "body",
|
|
57
|
-
* "param": "password",
|
|
58
|
-
* "value": "mypassword",
|
|
59
|
-
* "msg": "weak"
|
|
60
|
-
* }
|
|
61
|
-
* }
|
|
62
|
-
* },
|
|
63
|
-
* "error_id": "a2ddf895-2aaf-4189-88a2-8e11f6843f91"
|
|
64
|
-
*}
|
|
65
|
-
*/
|
|
66
|
-
formatError(error) {
|
|
67
|
-
let response;
|
|
68
|
-
if (error === null) {
|
|
69
|
-
response = this.defaults;
|
|
70
|
-
} else if (typeof(error) === "object") {
|
|
71
|
-
response = this._fromHash(error);
|
|
72
|
-
} else {
|
|
73
|
-
return new FormatError("invalid_error_format");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return response;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const formatter = new S4Formatter();
|
|
81
|
-
export default formatter;
|
package/hal/README.md
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# HAL DECORATOR
|
|
2
|
-
|
|
3
|
-
A module to add HAL decoration to JSON responses in Sequelize ORM based projects.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
In your model definition, set decoration on your model
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
import { halDecorator as decorator } from "@sera4/essentia"
|
|
11
|
-
...
|
|
12
|
-
|
|
13
|
-
module.exports = (sequelize, DataTypes) => {
|
|
14
|
-
const Post = sequelize.define('Post', {...}, {...});
|
|
15
|
-
// configure the decorator (optional)
|
|
16
|
-
const configs = {
|
|
17
|
-
links: {
|
|
18
|
-
"self" : {
|
|
19
|
-
"get": "/:id/post/"
|
|
20
|
-
},
|
|
21
|
-
"update" : {
|
|
22
|
-
"post": "/:id/post/"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
resource: "/posts",
|
|
26
|
-
exclude : ["created_at", "updated_at"],
|
|
27
|
-
linksTag : "myLinks",
|
|
28
|
-
resourceTag: "myResource"
|
|
29
|
-
}
|
|
30
|
-
decorator.decorate(Post, configs)
|
|
31
|
-
return Post;
|
|
32
|
-
};
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
The above configuration (which is optional) should produce the following JSON for each instance of Post sent out to the client:
|
|
36
|
-
```
|
|
37
|
-
{
|
|
38
|
-
"myLinks": {
|
|
39
|
-
"self": {
|
|
40
|
-
"get": "/posts/42801"
|
|
41
|
-
},
|
|
42
|
-
"update": {
|
|
43
|
-
"post": "/posts/42801"
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
"myResource": {
|
|
47
|
-
"id": 42801,
|
|
48
|
-
"title": "LJitZgbNPLpOlnkYdynKlSYnCjuLBYiVHYMfAPlSALeoVTuNKw",
|
|
49
|
-
"name": "cvnititqxdPnHdomgxJJVGynNInkScmDlkzAALunYFHNRjffqE",
|
|
50
|
-
"content": "LcURropLnJiudElgAVhsBSMRBRNUzHLDiTebZxxpplXdpeGEFa"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
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.
|
package/hal/index.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
|
|
3
|
-
function lastElement(arr) {
|
|
4
|
-
if (arr && arr.length) {
|
|
5
|
-
return arr[arr.length - 1];
|
|
6
|
-
} else {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
class HalDecorator {
|
|
12
|
-
|
|
13
|
-
decorate(Model, options) {
|
|
14
|
-
const model = Model.instance || Model;
|
|
15
|
-
const resource = (options && options.resource) ? options.resource : "";
|
|
16
|
-
const exclude = (options && options.exclude) ? options.exclude : [];
|
|
17
|
-
const links = (options && options.links) ? options.links : {};
|
|
18
|
-
const linksTag = (options && options.linksTag) ? options.linksTag : "_links";
|
|
19
|
-
const resourceTag = (options && options.resourceTag) ? options.resourceTag : "_resource";
|
|
20
|
-
|
|
21
|
-
const link = (name, method, l) => {
|
|
22
|
-
if (name && method && l) {
|
|
23
|
-
var aLink = {};
|
|
24
|
-
alink[method] = l;
|
|
25
|
-
links[name] = aLink;
|
|
26
|
-
}
|
|
27
|
-
return model;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const getLinkData = (values) => {
|
|
31
|
-
var linkData = {};
|
|
32
|
-
if (links) {
|
|
33
|
-
for (const key in links) {
|
|
34
|
-
if (links.hasOwnProperty(key)) {
|
|
35
|
-
const link = links[key];
|
|
36
|
-
const method = lastElement(Object.keys(link));
|
|
37
|
-
var url = link[method];
|
|
38
|
-
const paramPattern = /\:([a-zA-z_0-9]*)/;
|
|
39
|
-
const arr = paramPattern.exec(url);
|
|
40
|
-
if (arr) {
|
|
41
|
-
// Replace parameters
|
|
42
|
-
url = `/${resource}/${url.split(arr[0]).join(values[arr[1]])}`;
|
|
43
|
-
// Remove extra slashes that may have been added
|
|
44
|
-
url = url.replace(/\/\/*/g, "/");
|
|
45
|
-
linkData[key] = {}
|
|
46
|
-
linkData[key][method] = url;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return Object.keys(linkData).length > 0 ? linkData : null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
model.link = link;
|
|
55
|
-
Model.prototype.toJSON = function() {
|
|
56
|
-
var values = Object.assign({}, this.get());
|
|
57
|
-
if (exclude) {
|
|
58
|
-
exclude.forEach(element => {
|
|
59
|
-
delete values[element];
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
const links = getLinkData(values);
|
|
63
|
-
const result = {}
|
|
64
|
-
if (links) {
|
|
65
|
-
result[linksTag] = links;
|
|
66
|
-
}
|
|
67
|
-
result[resourceTag] = values;
|
|
68
|
-
return result;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const halDecorator = new HalDecorator();
|
|
75
|
-
export default halDecorator;
|
package/health/health-logger.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import logger from "../logger/s4-logger.js";
|
|
2
|
-
let enabled = false;
|
|
3
|
-
|
|
4
|
-
const helpers = {
|
|
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
|
-
}
|
|
39
|
-
|
|
40
|
-
export default helpers;
|
package/health/index.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
|
|
3
|
-
import pathHelper from "path";
|
|
4
|
-
import logger from "./health-logger.js";
|
|
5
|
-
import morgan from "morgan";
|
|
6
|
-
|
|
7
|
-
class HealthCheckError extends Error {}
|
|
8
|
-
|
|
9
|
-
/* Health Checking router + controller for use in all of our modules
|
|
10
|
-
* Example use: Place the following code in your routes file
|
|
11
|
-
*
|
|
12
|
-
* import { healthCheck } from "@sera4/essentia";
|
|
13
|
-
* const router = require('express').Router();
|
|
14
|
-
*
|
|
15
|
-
* ....
|
|
16
|
-
*
|
|
17
|
-
* const checkRedis = async () => { await cache.ping(); }
|
|
18
|
-
* hc.setupCheck({ name: "redis", checkResult: false, critical: true, healthFunction: checkRedis });
|
|
19
|
-
* app.use(hc.defaultPath(serverConfigs.api_prefix), hc.routes(router));
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
class HealthCheck {
|
|
23
|
-
constructor(appendData = {}, enableLogging = true) {
|
|
24
|
-
logger.setEnabled(enableLogging);
|
|
25
|
-
|
|
26
|
-
this.defaultResponse = {
|
|
27
|
-
...
|
|
28
|
-
appendData,
|
|
29
|
-
status: 200,
|
|
30
|
-
errors: {}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
this.defaultPathRoute = `health_check\(.*\)?`
|
|
34
|
-
this.suppressLogs = false;
|
|
35
|
-
this.lastCallId = 0; // default start point/integer
|
|
36
|
-
this.pathPrefix = "";
|
|
37
|
-
this.healthChecks = [];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/* Deprecated and replaced by setupCheck
|
|
41
|
-
* call this with an async function, must support wait capability
|
|
42
|
-
*
|
|
43
|
-
* const dbCheck = async () => {
|
|
44
|
-
* return { name: "db", "result": "success", critical: false };
|
|
45
|
-
* }
|
|
46
|
-
*/
|
|
47
|
-
addCheck(fcn) {
|
|
48
|
-
this.healthChecks.push(fcn);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
setPrefix(prefix) {
|
|
52
|
-
this.pathPrefix = prefix;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
defaultPath(prefix = "") {
|
|
56
|
-
if (prefix === "") {
|
|
57
|
-
prefix = this.pathPrefix; // maybe setup manually
|
|
58
|
-
}
|
|
59
|
-
return `${prefix}/${this.defaultPathRoute}`
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
routes(router) {
|
|
63
|
-
if (!router) {
|
|
64
|
-
throw new HealthCheckError("missing_express_router");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/* definition of all routes, rooted at defaultPath */
|
|
68
|
-
router.get('/', (req, res) => {
|
|
69
|
-
this.checkHealth(req, res)
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
return router
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
suppressHealthCheckLog(app) {
|
|
76
|
-
// Custom morgan skip function to ignore health check logging
|
|
77
|
-
console.log("skip: ", this.defaultPath())
|
|
78
|
-
app.use(morgan('combined', {
|
|
79
|
-
skip: (req) => req.path === defaultPath()
|
|
80
|
-
}));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// v2 version of health check, replaced addCheck
|
|
84
|
-
// example:
|
|
85
|
-
// const checkRedisFcn = async () => { await cache.ping().then(() => true) }
|
|
86
|
-
// setupCheck({ name: "redis", checkResult: false, critical: false, healthFunction: checkRedisFcn });
|
|
87
|
-
setupCheck(config) {
|
|
88
|
-
this.healthChecks.push(config);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/* performs health checks and returns 200 if true and 500 if not */
|
|
92
|
-
async checkHealth(req, res) {
|
|
93
|
-
const checkFormat = pathHelper.extname(req.baseUrl);
|
|
94
|
-
|
|
95
|
-
const result = await Promise.all(this.healthChecks.map(async hc => {
|
|
96
|
-
if (typeof(hc) === "function") {
|
|
97
|
-
try {
|
|
98
|
-
return await hc();
|
|
99
|
-
} catch(e) {
|
|
100
|
-
return { name: "unknown", result: 'fail', status: e.status }
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
let res = { name: hc.name, critical: hc.critical }
|
|
104
|
-
try {
|
|
105
|
-
const result = await hc.healthFunction();
|
|
106
|
-
if (typeof(result) === "boolean") {
|
|
107
|
-
if (result === false) {
|
|
108
|
-
res = {"result": "fail", ...res }
|
|
109
|
-
} else {
|
|
110
|
-
res = {"result": "success", ...res }
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
res = {"result": "success", ...res }
|
|
114
|
-
}
|
|
115
|
-
return res;
|
|
116
|
-
} catch(e) {
|
|
117
|
-
const appendStatus = e.status ? ` (${e.status})` : ""
|
|
118
|
-
logger.warn(`${hc.name} service failed${appendStatus}` )
|
|
119
|
-
return { ...res, "result": "fail", status: e.status }
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}));
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
let callId = ++this.lastCallId;
|
|
126
|
-
|
|
127
|
-
// start the counter over
|
|
128
|
-
if ((callId % (1 << 30)) === 0) {
|
|
129
|
-
callId = this.lastCallId = 1;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
let status = this.defaultResponse.status;
|
|
133
|
-
|
|
134
|
-
let nonCriticalFail = false;
|
|
135
|
-
let criticalFail = false;
|
|
136
|
-
|
|
137
|
-
result.some(e => {
|
|
138
|
-
if (e.result.match(/fail/)) {
|
|
139
|
-
if (e.critical === false) {
|
|
140
|
-
nonCriticalFail = true;
|
|
141
|
-
} else {
|
|
142
|
-
criticalFail = true;
|
|
143
|
-
status = 500;
|
|
144
|
-
return true; // break
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
// set this in the header no matter what
|
|
150
|
-
res.setHeader('check', callId)
|
|
151
|
-
|
|
152
|
-
if (checkFormat === ".json") {
|
|
153
|
-
const payload = { "check": callId, healthy: "true", message: "success" }
|
|
154
|
-
|
|
155
|
-
if (criticalFail) {
|
|
156
|
-
res.status(status).json({
|
|
157
|
-
... payload,
|
|
158
|
-
"healthy": false,
|
|
159
|
-
"message": "fail",
|
|
160
|
-
"services": result
|
|
161
|
-
});
|
|
162
|
-
} else if (nonCriticalFail) {
|
|
163
|
-
res.status(status).json({
|
|
164
|
-
... payload,
|
|
165
|
-
"message": "fail",
|
|
166
|
-
"services": result
|
|
167
|
-
});
|
|
168
|
-
} else if (status === 200) {
|
|
169
|
-
res.status(status).json(payload);
|
|
170
|
-
}
|
|
171
|
-
} else {
|
|
172
|
-
let status_message;
|
|
173
|
-
if (criticalFail) {
|
|
174
|
-
status_message = "fail"
|
|
175
|
-
} else if ((status === 200) || nonCriticalFail) {
|
|
176
|
-
status_message = "success"
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
res.status(status).send(status_message);
|
|
180
|
-
}
|
|
181
|
-
} catch(error) {
|
|
182
|
-
console.warn("error: ", error)
|
|
183
|
-
res.status(500).send();
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export { HealthCheck };
|
package/helpers/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./test-server-wrapper.js";
|