@johnmmackey/ms-utils 3.3.3 → 4.1.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/CHANGELOG.md CHANGED
@@ -1,7 +1,20 @@
1
- ## Version 3.3.3
1
+ ## Version 4.1.0
2
+ Added functionality:
3
+ * uses ```dotenv``` to load a local .env file
4
+ * pushes configuration into environment variables
5
+
6
+ ## Version 4.0.0
7
+ BREAKING CHANGES
8
+ * @johnmmackey/amqp-utils removed as a dependency
9
+ * sendmail is removed, and replaced with the Mailer Class
10
+ ```js
11
+ let m = new Mailer(connectionManager);
12
+ await m.send(recipients, options);
13
+ ```
14
+ * winstonMSLoggerFactory now requires the third parameter of connectionManager
15
+ * mail attachements now placed in REDIS with base64 encoding
16
+ * new REDIS client and other dependency upgrades
2
17
 
3
- * updated Buffer() to Buffer.from()
4
- * updated to latest @johnmmackey/amqp-utils package
5
18
  ## Version 3.3.1
6
19
 
7
20
  * updated etcd3 package to v1.1.0 (major rev upgrade)
package/README.md CHANGED
@@ -28,7 +28,6 @@ let x = Config.get('key'); //typeof string
28
28
  let y = Config.getObj('key'); // typeof Object
29
29
 
30
30
  sendmail(
31
- [
32
31
  {"email": "user1@gmail.com","name": "John Smith"},
33
32
  {"email": "user2@yahoo.com","name": "Jane Doe"},
34
33
  {"email": "user3@aol.com","name": "Karen from Texas"}
@@ -42,6 +41,14 @@ sendmail(
42
41
  .then( () => console.log('Success'))
43
42
  .catch( err => console.log(err))
44
43
  ```
44
+
45
+ ##
46
+ ```Config.load``` now has 2 side effects:
47
+ * uses ```dotenv``` to load a .env file in the current working directory into the environment
48
+ * pushes all items loaded from etcd into the environment.
49
+
50
+ The order of precedence: .env > etcd > external set environment
51
+
45
52
  ## Future
46
53
  * Add local queueing for log events when AMQP is not operative.
47
54
  * Configurable logging setup (drivers)
package/index.js CHANGED
@@ -3,6 +3,6 @@
3
3
  const Config = require('./lib/config');
4
4
  const winstonMSLoggerFactory = require('./lib/winston-mslogger');
5
5
  const Utils = require('./lib/utils');
6
- const sendmail = require('./lib/mail');
6
+ const Mailer = require('./lib/mail');
7
7
 
8
- module.exports = { Utils, Config, winstonMSLoggerFactory, sendmail };
8
+ module.exports = { Utils, Config, winstonMSLoggerFactory, Mailer };
package/lib/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { Etcd3 } = require('etcd3');
4
+ const dotenv = require('dotenv');
4
5
  const client = new Etcd3({ hosts: process.env.ETCD_URI || 'http://localhost:2379' });
5
6
 
6
7
 
@@ -24,7 +25,14 @@ async function tryLoad(serviceName) {
24
25
  }
25
26
 
26
27
  async function load(serviceName) {
27
- return Promise.retry(10, tryLoad.bind(this, serviceName), 5000)
28
+ await Promise.retry(10, tryLoad.bind(this, serviceName), 5000);
29
+
30
+ // as a side-effect, load these into process.env
31
+ dotenv.populate(process.env, config, { override: true });
32
+
33
+ // load any .env file that may be present into the environment
34
+ dotenv.config({ override: true });
35
+
28
36
  }
29
37
 
30
38
  function get(k) {
@@ -34,10 +42,10 @@ function get(k) {
34
42
  function getObj(k) {
35
43
  try {
36
44
  return JSON.parse(config[k]);
37
- }
38
- catch (err) {
39
- return null;
40
- }
45
+ }
46
+ catch (err) {
47
+ return null;
48
+ }
41
49
  }
42
50
 
43
51
  module.exports = { load, get, getObj }
package/lib/mail.js CHANGED
@@ -3,79 +3,84 @@
3
3
  const fs = require('fs');
4
4
  const redis = require("redis");
5
5
  const { v4: uuid } = require('uuid');
6
-
7
- const { ConnectionManager: aC } = require('@johnmmackey/amqp-utils');
8
-
9
- const rClient = redis.createClient({ url: process.env.REDIS_URI || 'redis://localhost' });
10
-
11
6
  const { promisify } = require('util');
12
- const setAsync = promisify(rClient.set).bind(rClient);
13
- const expireAsync = promisify(rClient.expire).bind(rClient);
14
7
  const readFileAsync = promisify(fs.readFile);
15
8
 
16
- aC.addConfig(ch => {
17
- ch.assertQueue('email', { durable: true });
18
- })
19
-
20
- // recipients structure: [{"email": "johnmmackey@yahoo.ca","name": "John Mackey"}]
21
- // options:
22
- // from
23
- // subject
24
- // replyTo
25
- // textBody
26
- // htmlBody
27
- // attachments[]
28
- // includeUnsubscribeLink
29
-
30
- // returns a promise
31
-
32
- module.exports = async function (recipients, options) {
33
-
34
- if (!options.htmlBody) // Always want a html body
35
- options.htmlBody = (options.textBody || '').replace(/\r?\n/g, '<br>');
36
-
37
- var msg = {
38
- from: options.from || "",
39
- subject: options.subject || "",
40
- attachments: [],
41
- includeUnsubscribeLink: options.includeUnsubscribeLink
42
- }
43
-
44
- if (options.textBody) {
45
- msg.textBodyKey = await writeKey(options.textBody, 'txt');
9
+ module.exports = class Mailer {
10
+ constructor(connectionManager) {
11
+ // param is amqp connection manager - see @johnmmackey/amqp-utils
12
+ this.aC = connectionManager;
13
+ this.rClient = redis.createClient({ url: process.env.REDIS_URI || 'redis://localhost' });
14
+ // while this is async, it has a retry, so should be OK
15
+ this.rClient.connect();
16
+ this.aC.addConfig(ch => {
17
+ ch.assertQueue('email', { durable: true });
18
+ })
46
19
  }
47
20
 
48
- msg.htmlBodyKey = await writeKey(options.htmlBody, 'html');
49
-
50
- for (let a of (options.attachments || [])) {
51
- var da = {
52
- filename: a.originalname,
53
- contentType: a.mimetype
21
+ // recipients structure: [{"email": "johnmmackey@yahoo.ca","name": "John Mackey"}]
22
+ // options:
23
+ // from
24
+ // subject
25
+ // replyTo
26
+ // textBody
27
+ // htmlBody
28
+ // attachments[]
29
+ // includeUnsubscribeLink
30
+
31
+ // returns a promise
32
+
33
+ async send(recipients, options) {
34
+
35
+
36
+ if (!options.htmlBody) // Always want a html body
37
+ options.htmlBody = (options.textBody || '').replace(/\r?\n/g, '<br>');
38
+
39
+ var msg = {
40
+ from: options.from || "",
41
+ subject: options.subject || "",
42
+ attachments: [],
43
+ includeUnsubscribeLink: options.includeUnsubscribeLink,
44
+ ...(options.mailingLists ? {mailingLists: options.mailingLists} : {})
45
+ }
46
+
47
+ if (options.textBody) {
48
+ msg.textBodyKey = await this.writeKey(options.textBody, 'txt');
49
+ }
50
+
51
+ msg.htmlBodyKey = await this.writeKey(options.htmlBody, 'html');
52
+
53
+ for (let a of (options.attachments || [])) {
54
+ var da = {
55
+ filename: a.originalname,
56
+ contentType: a.mimetype
57
+ };
58
+ a.contentDisposition && (da.contentDisposition = a.contentDisposition);
59
+ a.cid && (da.cid = a.cid);
60
+
61
+ da.key = await this.writeKey(
62
+ Buffer.from(a.path ? await readFileAsync(a.path) : a.content).toString('base64'),
63
+ 'attachment'
64
+ );
65
+ msg.attachments.push(da);
54
66
  };
55
- a.contentDisposition && (da.contentDisposition = a.contentDisposition);
56
- a.cid && (da.cid = a.cid);
57
67
 
58
- da.key = await writeKey(
59
- a.path ? await readFileAsync(a.path) : a.content,
60
- 'attachment'
61
- );
62
- msg.attachments.push(da);
63
- };
68
+ if (options.replyTo)
69
+ msg.replyTo = options.replyTo;
64
70
 
65
- if (options.replyTo)
66
- msg.replyTo = options.replyTo;
71
+ msg.recipientsKey = await this.writeKey(JSON.stringify(recipients), 'recipients');
67
72
 
68
- msg.recipientsKey = await writeKey(JSON.stringify(recipients), 'recipients');
73
+ // Send it to queue here
74
+ if (!this.aC.ch)
75
+ throw new Error('No current AMQP channel available');
69
76
 
70
- // Send it to queue here
71
- if (!aC.ch)
72
- throw new Error('No current AMQP channel available');
73
- aC.ch.sendToQueue('email', new Buffer.from(JSON.stringify(msg)));
74
- }
77
+ this.aC.ch.sendToQueue('email', Buffer.from(JSON.stringify(msg)));
78
+ }
75
79
 
76
- function writeKey(v, type) {
77
- let k = 'mail:' + uuid() + ':' + type;
78
- return setAsync(k, v)
79
- .then(() => expireAsync(k, 60*60*24))
80
- .then(() => k); // resolve to key name
80
+ async writeKey(v, type) {
81
+ let k = 'mail:' + uuid() + ':' + type;
82
+ await this.rClient.set(k, v);
83
+ await this.rClient.expire(k, 60 * 60 * 24);
84
+ return k;
85
+ }
81
86
  }
@@ -1,18 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  const util = require('util');
4
- const {ConnectionManagerClass} = require('@johnmmackey/amqp-utils');
5
4
 
6
- module.exports = function(winston, serviceName, existingConnectionManager) {
5
+ module.exports = function(winston, serviceName, cm) {
7
6
 
8
- var cm;
9
-
10
- if(existingConnectionManager) {
11
- cm = existingConnectionManager;
12
- } else {
13
- cm = new ConnectionManagerClass();
14
- cm.connect();
15
- }
16
7
  cm.addConfig(ch => {
17
8
  ch.assertQueue('logger', { durable: true });
18
9
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johnmmackey/ms-utils",
3
- "version": "3.3.3",
3
+ "version": "4.1.0",
4
4
  "description": "Utility functions for Microservice Architecture",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -14,9 +14,9 @@
14
14
  "license": "ISC",
15
15
  "homepage": "https://bitbucket.org/52westlabs/ms-utils#readme",
16
16
  "dependencies": {
17
- "@johnmmackey/amqp-utils": "^1.3.2",
18
- "etcd3": "^1.1.0",
19
- "redis": "^3.0.2",
20
- "uuid": "^8.3.2"
17
+ "dotenv": "^16.4.7",
18
+ "etcd3": "^1.1.2",
19
+ "redis": "^4.6.12",
20
+ "uuid": "^9.0.1"
21
21
  }
22
22
  }
@@ -0,0 +1,9 @@
1
+ const { Config } = require('../index.js');
2
+
3
+ ( async () => {
4
+ console.log('env: before network load', process.env)
5
+ let config = await Config.load('mailrelay')
6
+ console.log('env: after network and file load', process.env)
7
+
8
+
9
+ })()