@flink-app/email-plugin 2.0.0-alpha.127 → 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 CHANGED
@@ -1,5 +1,19 @@
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
+
3
17
  ## 2.0.0-alpha.127
4
18
 
5
19
  ### Patch Changes
@@ -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*/, 8];
151
+ if (!(_i < _b.length)) return [3 /*break*/, 10];
152
152
  _c = _b[_i];
153
- if (!(_c in _a)) return [3 /*break*/, 7];
153
+ if (!(_c in _a)) return [3 /*break*/, 9];
154
154
  i = _c;
155
- if (!this.client_secrect) {
156
- this.getToken();
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*/, 4];
163
+ if (!!success) return [3 /*break*/, 6];
162
164
  return [4 /*yield*/, this.getToken()];
163
- case 3:
165
+ case 5:
164
166
  _d.sent();
165
- return [3 /*break*/, 5];
166
- case 4: return [3 /*break*/, 7];
167
- case 5: return [4 /*yield*/, this.sendEmail(email, email.to[i])];
168
- case 6:
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 = 7;
173
- case 7:
174
+ _d.label = 9;
175
+ case 9:
174
176
  _i++;
175
177
  return [3 /*break*/, 1];
176
- case 8: return [2 /*return*/, !failure];
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?: AxiosInstance);
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.127",
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": "^7.4.5",
14
+ "@sendgrid/mail": "^8.1.6",
15
15
  "@types/nodemailer": "^6.4.4",
16
- "axios": "^0.27.2",
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.127"
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.127"
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
+ });
@@ -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.client_secrect) {
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";
@@ -1,4 +1,4 @@
1
- import axios, { AxiosInstance } from "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: AxiosInstance;
94
+ private http: MailersendHttp;
87
95
  private defaultFrom?: MailersendAddress;
88
96
 
89
- constructor(options: mailersendClientOptions, http?: AxiosInstance) {
97
+ constructor(options: mailersendClientOptions, http?: MailersendHttp) {
90
98
  this.defaultFrom = options.defaultFrom;
91
99
  this.http =
92
100
  http ??