@8ms/helpers 2.1.2 → 2.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.
Binary file
@@ -2,7 +2,7 @@ import { BaseClass } from "../../_class";
2
2
  type AttachmentSource = {
3
3
  filename: string;
4
4
  contentType?: string;
5
- data64?: string;
5
+ data?: string;
6
6
  url?: string;
7
7
  };
8
8
  type ConstructorProps = {
@@ -31,7 +31,7 @@ export declare class SimpleEmail extends BaseClass {
31
31
  setSubject: (subject: string) => this;
32
32
  setAttachments: (attachments: AttachmentSource[]) => this;
33
33
  addAttachment: (attachment: AttachmentSource) => this;
34
- addAttachmentFromData64: (filename: string, data64: string, contentType?: string) => this;
34
+ addAttachmentFromdata: (filename: string, data: string, contentType?: string) => this;
35
35
  addAttachmentFromUrl: (filename: string, url: string, contentType?: string) => this;
36
36
  clearAttachments: () => this;
37
37
  pushBcc: (recipient: string | string[]) => this;
@@ -71,7 +71,10 @@ export declare class SimpleEmail extends BaseClass {
71
71
  Source: string;
72
72
  }>;
73
73
  private _getRawEmailParams;
74
+ private _isTextFile;
75
+ private _getAttachmentTextData;
74
76
  private _getAttachmentData;
77
+ private _isBase64;
75
78
  private _getContentTypeFromFilename;
76
79
  private _filterRecipients;
77
80
  }
@@ -65,10 +65,10 @@ class SimpleEmail extends _class_1.BaseClass {
65
65
  this.attachments.push(attachment);
66
66
  return this;
67
67
  };
68
- this.addAttachmentFromData64 = (filename, data64, contentType) => {
68
+ this.addAttachmentFromdata = (filename, data, contentType) => {
69
69
  return this.addAttachment({
70
70
  filename,
71
- data64,
71
+ data,
72
72
  contentType: contentType || this._getContentTypeFromFilename(filename)
73
73
  });
74
74
  };
@@ -164,12 +164,20 @@ class SimpleEmail extends _class_1.BaseClass {
164
164
  rawMessage += `${this.html}\r\n\r\n`;
165
165
  // Add attachments
166
166
  for (const attachment of this.attachments) {
167
- const attachmentData = await this._getAttachmentData(attachment);
167
+ const isTextFile = this._isTextFile(attachment.contentType || this._getContentTypeFromFilename(attachment.filename));
168
168
  rawMessage += `--${boundary}\r\n`;
169
169
  rawMessage += `Content-Type: ${attachment.contentType || "application/octet-stream"}\r\n`;
170
170
  rawMessage += `Content-Disposition: attachment; filename="${attachment.filename}"\r\n`;
171
- rawMessage += `Content-Transfer-Encoding: base64\r\n\r\n`;
172
- rawMessage += `${attachmentData}\r\n\r\n`;
171
+ if (isTextFile) {
172
+ rawMessage += `Content-Transfer-Encoding: 7bit\r\n\r\n`;
173
+ const textData = await this._getAttachmentTextData(attachment);
174
+ rawMessage += `${textData}\r\n\r\n`;
175
+ }
176
+ else {
177
+ rawMessage += `Content-Transfer-Encoding: base64\r\n\r\n`;
178
+ const attachmentData = await this._getAttachmentData(attachment);
179
+ rawMessage += `${attachmentData}\r\n\r\n`;
180
+ }
173
181
  }
174
182
  rawMessage += `--${boundary}--\r\n`;
175
183
  return {
@@ -180,11 +188,50 @@ class SimpleEmail extends _class_1.BaseClass {
180
188
  Source: this.from
181
189
  };
182
190
  };
191
+ this._isTextFile = (contentType) => {
192
+ const textTypes = [
193
+ "text/csv",
194
+ "text/plain",
195
+ "text/html",
196
+ "application/json",
197
+ "application/xml",
198
+ "text/xml"
199
+ ];
200
+ return textTypes.some(type => contentType.startsWith(type));
201
+ };
202
+ this._getAttachmentTextData = async (attachment) => {
203
+ // If data is already provided as base64, decode it first
204
+ if (attachment.data) {
205
+ // Remove data URL prefix if present (e.g., "data:text/csv;base64,")
206
+ const base64Data = attachment.data.replace(/^data:[^;]+;base64,/, "");
207
+ // Check if it's actually base64 encoded
208
+ if (this._isBase64(base64Data)) {
209
+ return Buffer.from(base64Data, "base64")
210
+ .toString("utf-8");
211
+ }
212
+ // If not base64, assume it's already plain text
213
+ return attachment.data;
214
+ }
215
+ // If URL is provided, fetch the data as text
216
+ if (attachment.url) {
217
+ const fetch = await Promise.resolve().then(() => __importStar(require("node-fetch"))).then(mod => mod.default);
218
+ const response = await fetch(attachment.url);
219
+ return await response.text();
220
+ }
221
+ throw new Error(`No valid data source provided for attachment: ${attachment.filename}`);
222
+ };
183
223
  this._getAttachmentData = async (attachment) => {
184
224
  // If data is already provided as base64
185
- if (attachment.data64) {
225
+ if (attachment.data) {
186
226
  // Remove data URL prefix if present (e.g., "data:image/png;base64,")
187
- return attachment.data64.replace(/^data:[^;]+;base64,/, "");
227
+ const cleanData = attachment.data.replace(/^data:[^;]+;base64,/, "");
228
+ // Check if it's actually base64 encoded
229
+ if (this._isBase64(cleanData)) {
230
+ return cleanData;
231
+ }
232
+ // If not base64, encode it
233
+ return Buffer.from(attachment.data, "utf-8")
234
+ .toString("base64");
188
235
  }
189
236
  // If URL is provided, fetch the data
190
237
  if (attachment.url) {
@@ -195,6 +242,15 @@ class SimpleEmail extends _class_1.BaseClass {
195
242
  }
196
243
  throw new Error(`No valid data source provided for attachment: ${attachment.filename}`);
197
244
  };
245
+ this._isBase64 = (str) => {
246
+ try {
247
+ return Buffer.from(str, "base64")
248
+ .toString("base64") === str;
249
+ }
250
+ catch {
251
+ return false;
252
+ }
253
+ };
198
254
  this._getContentTypeFromFilename = (filename) => {
199
255
  const extension = filename.split(".")
200
256
  .pop()
@@ -219,6 +275,7 @@ class SimpleEmail extends _class_1.BaseClass {
219
275
  "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
220
276
  // Data
221
277
  "csv": "text/csv",
278
+ "tsv": "text/tab-separated-values",
222
279
  "json": "application/json",
223
280
  "xml": "application/xml",
224
281
  "txt": "text/plain",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@8ms/helpers",
3
3
  "license": "UNLICENSED",
4
- "version": "2.1.2",
4
+ "version": "2.1.4",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/8millionstories-organisation/8ms-helpers-ts.git"