@flink-app/email-plugin 2.0.0-alpha.126 → 2.0.0-alpha.128
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 +20 -0
- package/dist/flowmailerClient.js +17 -15
- package/dist/index.d.ts +1 -1
- package/dist/mailersendClient.d.ts +10 -2
- package/package.json +5 -5
- package/spec/flowmailerClient.spec.ts +64 -0
- package/src/flowmailerClient.ts +2 -2
- package/src/index.ts +1 -1
- package/src/mailersendClient.ts +11 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @flink-app/email-plugin
|
|
2
2
|
|
|
3
|
+
## 2.0.0-alpha.128
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 55bd361: Bump `@sendgrid/mail` to `^8.1.6`, which moves its internal HTTP client from vulnerable `axios` 0.26 to 1.x. The SendGrid API surface used by the plugin is unchanged
|
|
8
|
+
- c004433: Bump `axios` from 0.27 to `^1.20.0` to fix several high-severity advisories. Requests sent to Flowmailer, MailerSend and 46elks are unchanged apart from an added `Accept-Encoding` header
|
|
9
|
+
|
|
10
|
+
The `http` parameter of `mailersendClient` is now typed as the new exported `MailersendHttp` interface (only `post` is used) instead of `AxiosInstance`, so instances from any axios version, or a test double, are accepted
|
|
11
|
+
|
|
12
|
+
- ac10540: - sms-plugin: stop logging the full axios error when a 46elks send fails, which leaked the Basic auth credentials into logs. Only status, message and response body are logged now
|
|
13
|
+
- email-plugin: Flowmailer client now fetches an access token before the first send instead of always making one failed request with an empty bearer token
|
|
14
|
+
- Updated dependencies [5b666f2]
|
|
15
|
+
- @flink-app/flink@2.0.0-alpha.128
|
|
16
|
+
|
|
17
|
+
## 2.0.0-alpha.127
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- @flink-app/flink@2.0.0-alpha.127
|
|
22
|
+
|
|
3
23
|
## 2.0.0-alpha.126
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/flowmailerClient.js
CHANGED
|
@@ -148,32 +148,34 @@ var flowMailerClient = /** @class */ (function () {
|
|
|
148
148
|
_i = 0;
|
|
149
149
|
_d.label = 1;
|
|
150
150
|
case 1:
|
|
151
|
-
if (!(_i < _b.length)) return [3 /*break*/,
|
|
151
|
+
if (!(_i < _b.length)) return [3 /*break*/, 10];
|
|
152
152
|
_c = _b[_i];
|
|
153
|
-
if (!(_c in _a)) return [3 /*break*/,
|
|
153
|
+
if (!(_c in _a)) return [3 /*break*/, 9];
|
|
154
154
|
i = _c;
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
return [4 /*yield*/, this.sendEmail(email, email.to[i])];
|
|
155
|
+
if (!!this.accessToken) return [3 /*break*/, 3];
|
|
156
|
+
return [4 /*yield*/, this.getToken()];
|
|
159
157
|
case 2:
|
|
158
|
+
_d.sent();
|
|
159
|
+
_d.label = 3;
|
|
160
|
+
case 3: return [4 /*yield*/, this.sendEmail(email, email.to[i])];
|
|
161
|
+
case 4:
|
|
160
162
|
success = _d.sent();
|
|
161
|
-
if (!!success) return [3 /*break*/,
|
|
163
|
+
if (!!success) return [3 /*break*/, 6];
|
|
162
164
|
return [4 /*yield*/, this.getToken()];
|
|
163
|
-
case
|
|
165
|
+
case 5:
|
|
164
166
|
_d.sent();
|
|
165
|
-
return [3 /*break*/,
|
|
166
|
-
case
|
|
167
|
-
case
|
|
168
|
-
case
|
|
167
|
+
return [3 /*break*/, 7];
|
|
168
|
+
case 6: return [3 /*break*/, 9];
|
|
169
|
+
case 7: return [4 /*yield*/, this.sendEmail(email, email.to[i])];
|
|
170
|
+
case 8:
|
|
169
171
|
success = _d.sent();
|
|
170
172
|
if (!success)
|
|
171
173
|
failure = true;
|
|
172
|
-
_d.label =
|
|
173
|
-
case
|
|
174
|
+
_d.label = 9;
|
|
175
|
+
case 9:
|
|
174
176
|
_i++;
|
|
175
177
|
return [3 /*break*/, 1];
|
|
176
|
-
case
|
|
178
|
+
case 10: return [2 /*return*/, !failure];
|
|
177
179
|
}
|
|
178
180
|
});
|
|
179
181
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { flowMailerClient } from "./flowmailerClient";
|
|
|
6
6
|
export { sesClient } from "./sesClient";
|
|
7
7
|
export { postmarkClient } from "./postmarkClient";
|
|
8
8
|
export { mailersendClient, toMailersendAddress } from "./mailersendClient";
|
|
9
|
-
export type { mailersendClientOptions, MailersendResult } from "./mailersendClient";
|
|
9
|
+
export type { mailersendClientOptions, MailersendResult, MailersendHttp } from "./mailersendClient";
|
|
10
10
|
export type { email } from "./schemas/email";
|
|
11
11
|
export type { emailSes } from "./schemas/emailSes";
|
|
12
12
|
export type { emailPostmark, PostmarkAttachment } from "./schemas/emailPostmark";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AxiosInstance } from "axios";
|
|
2
1
|
import { client } from "./schemas/client";
|
|
3
2
|
import { emailMailersend as email, MailersendAddress } from "./schemas/emailMailersend";
|
|
4
3
|
export interface mailersendClientOptions {
|
|
@@ -33,6 +32,15 @@ export interface MailersendResult {
|
|
|
33
32
|
details?: any;
|
|
34
33
|
};
|
|
35
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* The part of an HTTP client (such as an axios instance) used to talk to
|
|
37
|
+
* MailerSend. Kept minimal so instances from any axios version fit.
|
|
38
|
+
*/
|
|
39
|
+
export interface MailersendHttp {
|
|
40
|
+
post(url: string, data?: any): Promise<{
|
|
41
|
+
headers?: any;
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
36
44
|
type MailersendAddressPayload = {
|
|
37
45
|
email: string;
|
|
38
46
|
name?: string;
|
|
@@ -45,7 +53,7 @@ export declare function toMailersendAddress(address: MailersendAddress): Mailers
|
|
|
45
53
|
export declare class mailersendClient implements client {
|
|
46
54
|
private http;
|
|
47
55
|
private defaultFrom?;
|
|
48
|
-
constructor(options: mailersendClientOptions, http?:
|
|
56
|
+
constructor(options: mailersendClientOptions, http?: MailersendHttp);
|
|
49
57
|
/**
|
|
50
58
|
* Send an email via MailerSend. Implements the base `client` interface.
|
|
51
59
|
* Returns `true` on success, `false` on failure.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flink-app/email-plugin",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.128",
|
|
4
4
|
"description": "Flink plugin that provides multi-provider email sending capabilities with support for SendGrid, SMTP, Flowmailer, AWS SES, Postmark, and MailerSend",
|
|
5
5
|
"author": "johan@frost.se",
|
|
6
6
|
"publishConfig": {
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"main": "dist/index.js",
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@aws-sdk/client-sesv2": "^3.700.0",
|
|
14
|
-
"@sendgrid/mail": "^
|
|
14
|
+
"@sendgrid/mail": "^8.1.6",
|
|
15
15
|
"@types/nodemailer": "^6.4.4",
|
|
16
|
-
"axios": "^
|
|
16
|
+
"axios": "^1.20.0",
|
|
17
17
|
"nodemailer": "^6.6.2",
|
|
18
18
|
"postmark": "^4.0.7",
|
|
19
19
|
"querystring": "^0.2.1"
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/jasmine": "^3.7.1",
|
|
23
23
|
"@types/node": "22.13.10",
|
|
24
|
-
"@flink-app/flink": "2.0.0-alpha.
|
|
24
|
+
"@flink-app/flink": "2.0.0-alpha.128"
|
|
25
25
|
},
|
|
26
26
|
"gitHead": "4243e3b3cd6d4e1ca001a61baa8436bf2bbe4113",
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@flink-app/flink": ">=2.0.0-alpha.
|
|
28
|
+
"@flink-app/flink": ">=2.0.0-alpha.128"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"test": "jasmine-ts --config=./spec/support/jasmine.json",
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { flowMailerClient } from "../src/flowmailerClient";
|
|
3
|
+
|
|
4
|
+
const TOKEN_URL = "https://login.flowmailer.net/oauth/token";
|
|
5
|
+
|
|
6
|
+
function createClient() {
|
|
7
|
+
return new flowMailerClient({ client_id: "id", client_secrect: "secret", account_id: "acc" });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const email = { from: "a@example.com", to: ["b@example.com", "c@example.com"], subject: "Hi", text: "Body" };
|
|
11
|
+
|
|
12
|
+
describe("flowMailerClient", () => {
|
|
13
|
+
let post: jasmine.Spy;
|
|
14
|
+
let tokenRequests: number;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
tokenRequests = 0;
|
|
18
|
+
post = spyOn(axios, "post").and.callFake((async (url: string) => {
|
|
19
|
+
if (url === TOKEN_URL) {
|
|
20
|
+
tokenRequests++;
|
|
21
|
+
return { status: 200, data: { access_token: `tok-${tokenRequests}` } };
|
|
22
|
+
}
|
|
23
|
+
return { status: 201 };
|
|
24
|
+
}) as any);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
function submitAuthHeaders() {
|
|
28
|
+
return post.calls
|
|
29
|
+
.all()
|
|
30
|
+
.filter((c) => c.args[0] !== TOKEN_URL)
|
|
31
|
+
.map((c) => c.args[2].headers.Authorization);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
it("fetches a token before the first send and reuses it", async () => {
|
|
35
|
+
expect(await createClient().send(email)).toBe(true);
|
|
36
|
+
|
|
37
|
+
expect(tokenRequests).toBe(1);
|
|
38
|
+
expect(post.calls.first().args[0]).toBe(TOKEN_URL);
|
|
39
|
+
expect(submitAuthHeaders()).toEqual(["Bearer tok-1", "Bearer tok-1"]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("refreshes the token and retries once when a send fails", async () => {
|
|
43
|
+
const client = createClient();
|
|
44
|
+
await client.send({ ...email, to: ["b@example.com"] });
|
|
45
|
+
|
|
46
|
+
let rejected = false;
|
|
47
|
+
post.and.callFake((async (url: string) => {
|
|
48
|
+
if (url === TOKEN_URL) {
|
|
49
|
+
tokenRequests++;
|
|
50
|
+
return { status: 200, data: { access_token: `tok-${tokenRequests}` } };
|
|
51
|
+
}
|
|
52
|
+
if (!rejected) {
|
|
53
|
+
rejected = true;
|
|
54
|
+
throw { response: { status: 401, data: { error: "invalid_token" } } };
|
|
55
|
+
}
|
|
56
|
+
return { status: 201 };
|
|
57
|
+
}) as any);
|
|
58
|
+
post.calls.reset();
|
|
59
|
+
|
|
60
|
+
expect(await client.send({ ...email, to: ["b@example.com"] })).toBe(true);
|
|
61
|
+
expect(tokenRequests).toBe(2);
|
|
62
|
+
expect(submitAuthHeaders()).toEqual(["Bearer tok-1", "Bearer tok-2"]);
|
|
63
|
+
});
|
|
64
|
+
});
|
package/src/flowmailerClient.ts
CHANGED
|
@@ -89,8 +89,8 @@ export class flowMailerClient implements client {
|
|
|
89
89
|
async send(email: email) {
|
|
90
90
|
let failure = false;
|
|
91
91
|
for (const i in email.to) {
|
|
92
|
-
if (!this.
|
|
93
|
-
this.getToken();
|
|
92
|
+
if (!this.accessToken) {
|
|
93
|
+
await this.getToken();
|
|
94
94
|
}
|
|
95
95
|
let success = await this.sendEmail(email, email.to[i]);
|
|
96
96
|
if (!success) {
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { flowMailerClient } from "./flowmailerClient";
|
|
|
6
6
|
export { sesClient } from "./sesClient";
|
|
7
7
|
export { postmarkClient } from "./postmarkClient";
|
|
8
8
|
export { mailersendClient, toMailersendAddress } from "./mailersendClient";
|
|
9
|
-
export type { mailersendClientOptions, MailersendResult } from "./mailersendClient";
|
|
9
|
+
export type { mailersendClientOptions, MailersendResult, MailersendHttp } from "./mailersendClient";
|
|
10
10
|
export type { email } from "./schemas/email";
|
|
11
11
|
export type { emailSes } from "./schemas/emailSes";
|
|
12
12
|
export type { emailPostmark, PostmarkAttachment } from "./schemas/emailPostmark";
|
package/src/mailersendClient.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import axios
|
|
1
|
+
import axios from "axios";
|
|
2
2
|
import { client } from "./schemas/client";
|
|
3
3
|
import {
|
|
4
4
|
emailMailersend as email,
|
|
@@ -41,6 +41,14 @@ export interface MailersendResult {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* The part of an HTTP client (such as an axios instance) used to talk to
|
|
46
|
+
* MailerSend. Kept minimal so instances from any axios version fit.
|
|
47
|
+
*/
|
|
48
|
+
export interface MailersendHttp {
|
|
49
|
+
post(url: string, data?: any): Promise<{ headers?: any }>;
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
type MailersendAddressPayload = { email: string; name?: string };
|
|
45
53
|
|
|
46
54
|
type MailersendPayload = {
|
|
@@ -83,10 +91,10 @@ export function toMailersendAddress(
|
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
export class mailersendClient implements client {
|
|
86
|
-
private http:
|
|
94
|
+
private http: MailersendHttp;
|
|
87
95
|
private defaultFrom?: MailersendAddress;
|
|
88
96
|
|
|
89
|
-
constructor(options: mailersendClientOptions, http?:
|
|
97
|
+
constructor(options: mailersendClientOptions, http?: MailersendHttp) {
|
|
90
98
|
this.defaultFrom = options.defaultFrom;
|
|
91
99
|
this.http =
|
|
92
100
|
http ??
|