mailisk 2.1.1 → 2.2.2

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 CHANGED
@@ -1,10 +1,11 @@
1
1
  # Mailisk Node Client
2
2
 
3
- Mailisk is an end-to-end email testing platform. It allows you to receive emails with code and automate email tests.
3
+ Mailisk is an end-to-end email and SMS testing platform. It allows you to receive emails and SMS messages with code to automate tests.
4
4
 
5
5
  - Get a unique subdomain and unlimited email addresses for free.
6
6
  - Easily automate E2E password reset and account verification by catching emails.
7
- - Virtual SMTP support to test outbound email without 3rd party clients.
7
+ - Receive SMS messages and automate SMS tests.
8
+ - Virtual SMTP and SMS support to test without 3rd party clients.
8
9
 
9
10
  ## Get started
10
11
 
@@ -52,9 +53,9 @@ console.log(result);
52
53
 
53
54
  This library wraps the REST API endpoints. Find out more in the [API Reference](https://docs.mailisk.com/api-reference/).
54
55
 
55
- ## Client functions
56
+ ## Client functions (Email)
56
57
 
57
- ### `searchInbox(namespace, params?)`
58
+ ### `searchInbox(namespace, params?, requestOptions?)`
58
59
 
59
60
  Use `searchInbox` to fetch messages that arrived in a given namespace, optionally waiting until the first new mail shows up.
60
61
 
@@ -70,13 +71,13 @@ Default behaviour:
70
71
 
71
72
  ```js
72
73
  // wait up to the default 5 min for *any* new mail
73
- const { data: emails } = await mailisk.searchInbox(namespace);
74
-
74
+ await mailisk.searchInbox(namespace);
75
75
  // custom 60-second timeout
76
76
  await mailisk.searchInbox(namespace, {}, { timeout: 1000 * 60 });
77
-
78
77
  // polling pattern — return immediately, even if inbox is empty
79
78
  await mailisk.searchInbox(namespace, { wait: false });
79
+ // returns the last 20 emails in the namespace immediately
80
+ await mailisk.searchInbox(namespace, { wait: false, from_timestamp: 0, limit: 20 });
80
81
  ```
81
82
 
82
83
  #### Filter by destination address
@@ -105,17 +106,15 @@ await mailisk.sendVirtualEmail(namespace, {
105
106
  });
106
107
  ```
107
108
 
108
- This does not call an API endpoint but rather uses nodemailer to send an email using SMTP.
109
-
110
109
  ### `listNamespaces()`
111
110
 
112
111
  List all namespaces associated with the current API Key.
113
112
 
114
113
  ```js
115
- const namespacesResponse = await mailisk.listNamespaces();
114
+ const { data: namespaces } = await mailisk.listNamespaces();
116
115
 
117
116
  // will be ['namespace1', 'namespace2']
118
- const namespaces = namespacesResponse.map((nr) => nr.namespace);
117
+ const namespacesList = namespaces.map((nr) => nr.namespace);
119
118
  ```
120
119
 
121
120
  ### `getAttachment(attachmentId)`
@@ -158,3 +157,56 @@ const res = await fetch(meta.download_url);
158
157
  const fileStream = fs.createWriteStream(filename);
159
158
  await new Promise((ok, err) => res.body.pipe(fileStream).on("finish", ok).on("error", err));
160
159
  ```
160
+
161
+ ## Client functions (SMS)
162
+
163
+ ### `searchSmsMessages(phoneNumber, params?, requestOptions?)`
164
+
165
+ Fetch recent SMS messages that were delivered to one of your Mailisk phone numbers.
166
+ For the full parameter list see the [Search SMS reference](https://docs.mailisk.com/api-reference/search-sms-messages.html#request).
167
+
168
+ Default behaviour:
169
+
170
+ - Waits until at least one SMS matches the filters (override with `wait: false`).
171
+ - Times out after 5 minutes if nothing shows up (adjust via `requestOptions.timeout`).
172
+ - Ignores messages older than 15 minutes (change via `from_date`).
173
+
174
+ #### Quick examples
175
+
176
+ ```js
177
+ // get or wait for SMS messages sent to ths number
178
+ const { data: sms } = await mailisk.searchSmsMessages(phoneNumber);
179
+
180
+ // look for a verification code coming from a known sender
181
+ await mailisk.searchSmsMessages(phoneNumber, {
182
+ from_number: "+1800555",
183
+ body: "Your code",
184
+ });
185
+
186
+ // polling pattern — return immediately even if nothing matched
187
+ await mailisk.searchSmsMessages(
188
+ phoneNumber,
189
+ { wait: false, limit: 10, from_date: new Date(Date.now() - 1000 * 60 * 5).toISOString() },
190
+ { timeout: 10_000 }
191
+ );
192
+ ```
193
+
194
+ ### `listSmsNumbers()`
195
+
196
+ List all SMS phone numbers associated with the current account.
197
+
198
+ ```js
199
+ const { data: phoneNumbers } = await mailisk.listSmsNumbers();
200
+ ```
201
+
202
+ ### `sendVirtualSms(params)`
203
+
204
+ Send a virtual SMS message to a phone number you have access to.
205
+
206
+ ```js
207
+ await mailisk.sendVirtualSms({
208
+ from_number: "15551234567",
209
+ to_number: "15557654321",
210
+ body: "Test message",
211
+ });
212
+ ```
package/dist/index.d.ts CHANGED
@@ -47,6 +47,40 @@ interface Email {
47
47
  /** The attachments of the email */
48
48
  attachments?: EmailAttachment[];
49
49
  }
50
+ interface SmsMessage {
51
+ /** Unique identifier for the message */
52
+ id: string;
53
+ /** Unique identifier for the SMS phone number */
54
+ sms_phone_number_id: string;
55
+ /** Body of the message */
56
+ body: string;
57
+ /** From number of the message */
58
+ from_number: string;
59
+ /** To number of the message */
60
+ to_number: string;
61
+ /** Provider message ID */
62
+ provider_message_id?: string;
63
+ /** Date and time the message was created */
64
+ created_at: string;
65
+ /** Direction of the message */
66
+ direction: "inbound" | "outbound";
67
+ }
68
+ interface SmsNumber {
69
+ /** Unique identifier for the SMS number */
70
+ id: string;
71
+ /** Unique identifier for the organisation */
72
+ organisation_id: string;
73
+ /** Status of the SMS number */
74
+ status: "requested" | "active" | "disabled";
75
+ /** Country of the SMS number */
76
+ country: string;
77
+ /** SMS Phone number */
78
+ phone_number?: string;
79
+ /** Date and time the SMS number was created */
80
+ created_at: string;
81
+ /** Date and time the SMS number was updated */
82
+ updated_at: string;
83
+ }
50
84
  interface SearchInboxParams {
51
85
  /**
52
86
  * The maximum number of emails that can be returned in this request, used alongside `offset` for pagination.
@@ -122,12 +156,11 @@ interface GetAttachmentResponse {
122
156
  };
123
157
  }
124
158
  interface ListNamespacesResponse {
125
- data: [
126
- {
127
- id: string;
128
- namespace: string;
129
- }
130
- ];
159
+ total_count: number;
160
+ data: {
161
+ id: string;
162
+ namespace: string;
163
+ }[];
131
164
  }
132
165
  interface SendVirtualEmailParams {
133
166
  /** Sender of email */
@@ -149,6 +182,55 @@ interface SendVirtualEmailParams {
149
182
  /** Attachments to the email */
150
183
  attachments?: Attachment[];
151
184
  }
185
+ interface SearchSmsMessagesParams {
186
+ /**
187
+ * The maximum number of SMS messages returned (1-100), used alongside `offset` for pagination.
188
+ */
189
+ limit?: number;
190
+ /**
191
+ * The number of SMS messages to skip/ignore, used alongside `limit` for pagination.
192
+ */
193
+ offset?: number;
194
+ /**
195
+ * Filter messages by body contents (case insensitive).
196
+ */
197
+ body?: string;
198
+ /**
199
+ * Filter messages by sender phone number prefix.
200
+ */
201
+ from_number?: string;
202
+ /**
203
+ * Filter messages created on or after this date.
204
+ * Provide an ISO 8601 timestamp string.
205
+ */
206
+ from_date?: string;
207
+ /**
208
+ * Filter messages created on or before this date.
209
+ * Provide an ISO 8601 timestamp string.
210
+ */
211
+ to_date?: string;
212
+ /**
213
+ * When true, keep the request open until at least one SMS is returned.
214
+ */
215
+ wait?: boolean;
216
+ }
217
+ interface SearchSmsMessagesResponse {
218
+ total_count: number;
219
+ options: SearchSmsMessagesParams;
220
+ data: SmsMessage[];
221
+ }
222
+ interface ListSmsNumbersResponse {
223
+ total_count: number;
224
+ data: SmsNumber[];
225
+ }
226
+ interface SendVirtualSmsParams {
227
+ /** The phone number to send the SMS from */
228
+ from_number: string;
229
+ /** The phone number to send the SMS to */
230
+ to_number: string;
231
+ /** The body of the SMS message */
232
+ body: string;
233
+ }
152
234
 
153
235
  declare class MailiskClient {
154
236
  constructor({ apiKey, baseUrl, auth }: {
@@ -157,6 +239,27 @@ declare class MailiskClient {
157
239
  auth?: AxiosBasicCredentials;
158
240
  });
159
241
  private readonly axiosInstance;
242
+ /**
243
+ * Search SMS messages sent to a phone number.
244
+ *
245
+ * @example
246
+ * Search for SMS messages sent to a phone number
247
+ * ```typescript
248
+ * const { data: smsMessages } = await client.searchSmsMessages("1234567890");
249
+ * ```
250
+ */
251
+ searchSmsMessages(phoneNumber: string, params?: SearchSmsMessagesParams, config?: AxiosRequestConfig): Promise<SearchSmsMessagesResponse>;
252
+ /**
253
+ * List all SMS phone numbers associated with the current account.
254
+ *
255
+ * @example
256
+ * List all SMS phone numbers
257
+ * ```typescript
258
+ * const { data: smsNumbers } = await client.listSmsNumbers();
259
+ * ```
260
+ */
261
+ listSmsNumbers(): Promise<ListSmsNumbersResponse>;
262
+ sendVirtualSms(params: SendVirtualSmsParams): Promise<void>;
160
263
  /**
161
264
  * List all namespaces that belong to the current account (API key).
162
265
  */
@@ -182,12 +285,12 @@ declare class MailiskClient {
182
285
  * Search inbox of a namespace.
183
286
  *
184
287
  * By default, this calls the api using the `wait` flag. This means the call won't timeout until at least one email is received or 5 minutes pass.
185
- * It also uses a default `from_timestamp` of **current timestamp - 5 seconds**. This means that older emails will be ignored.
288
+ * It also uses a default `from_timestamp` of **current timestamp - 15 minutes**. This means that older emails will be ignored.
186
289
  *
187
290
  * Both of these settings can be overriden by passing them in the `params` object.
188
291
  *
189
292
  * @example
190
- * Get the latest emails in the namespace
293
+ * Get the latest emails
191
294
  * ```typescript
192
295
  * const { data: emails } = await client.searchInbox(namespace);
193
296
  * ```
@@ -196,7 +299,17 @@ declare class MailiskClient {
196
299
  * Get the latest emails for a specific email address
197
300
  * ```typescript
198
301
  * const { data: emails } = await client.searchInbox(namespace, {
199
- * to_addr_prefix: 'john@mynamespace.mailisk.net'
302
+ * to_addr_prefix: 'john@mynamespace.mailisk.net'
303
+ * });
304
+ * ```
305
+ *
306
+ * @example
307
+ * Get the last 20 emails in the namespace
308
+ * ```typescript
309
+ * const { data: emails } = await mailisk.searchInbox(namespace, {
310
+ * wait: false,
311
+ * from_timestamp: 0,
312
+ * limit: 20
200
313
  * });
201
314
  * ```
202
315
  */
package/dist/index.js CHANGED
@@ -45,6 +45,37 @@ var MailiskClient = class {
45
45
  });
46
46
  }
47
47
  axiosInstance;
48
+ async searchSmsMessages(phoneNumber, params, config) {
49
+ let _params = { ...params };
50
+ if (params?.from_date === void 0 || params?.from_date === null) {
51
+ _params.from_date = new Date(Date.now() - 15 * 60 * 1e3).toISOString();
52
+ }
53
+ if (params?.wait !== false) {
54
+ _params.wait = true;
55
+ }
56
+ let _config = { ...config };
57
+ if (config?.maxRedirects === void 0) {
58
+ _config.maxRedirects = 99999;
59
+ }
60
+ if (_params.wait && config?.timeout === void 0) {
61
+ _config.timeout = 1e3 * 60 * 5;
62
+ }
63
+ const requestParams = {
64
+ ..._params,
65
+ from_date: _params.from_date ?? void 0,
66
+ to_date: _params.to_date ?? void 0
67
+ };
68
+ return (await this.axiosInstance.get(`api/sms/${phoneNumber}/messages`, {
69
+ ..._config,
70
+ params: requestParams
71
+ })).data;
72
+ }
73
+ async listSmsNumbers() {
74
+ return (await this.axiosInstance.get("api/sms/numbers")).data;
75
+ }
76
+ async sendVirtualSms(params) {
77
+ return (await this.axiosInstance.post("api/sms/virtual", params)).data;
78
+ }
48
79
  async listNamespaces() {
49
80
  return (await this.axiosInstance.get("api/namespaces")).data;
50
81
  }
@@ -80,10 +111,10 @@ var MailiskClient = class {
80
111
  _params.wait = true;
81
112
  }
82
113
  let _config = { ...config };
83
- if (!config?.maxRedirects) {
114
+ if (config?.maxRedirects === void 0) {
84
115
  _config.maxRedirects = 99999;
85
116
  }
86
- if (_params.wait && !config?.timeout) {
117
+ if (_params.wait && config?.timeout === void 0) {
87
118
  _config.timeout = 1e3 * 60 * 5;
88
119
  }
89
120
  return (await this.axiosInstance.get(`api/emails/${namespace}/inbox`, {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/mailisk.ts"],"sourcesContent":["export * from \"./mailisk\";\n","import axios, { AxiosBasicCredentials, AxiosRequestConfig } from \"axios\";\nimport {\n GetAttachmentResponse,\n ListNamespacesResponse,\n SearchInboxParams,\n SearchInboxResponse,\n SendVirtualEmailParams,\n SmtpSettings,\n} from \"./mailisk.interfaces\";\nimport nodemailer from \"nodemailer\";\n\nexport class MailiskClient {\n constructor({ apiKey, baseUrl, auth }: { apiKey: string; baseUrl?: string; auth?: AxiosBasicCredentials }) {\n this.axiosInstance = axios.create({\n headers: {\n \"X-Api-Key\": apiKey,\n },\n baseURL: baseUrl || \"https://api.mailisk.com/\",\n auth,\n });\n }\n\n private readonly axiosInstance;\n\n /**\n * List all namespaces that belong to the current account (API key).\n */\n async listNamespaces(): Promise<ListNamespacesResponse> {\n return (await this.axiosInstance.get(\"api/namespaces\")).data;\n }\n\n /**\n * Send an email using the Virtual SMTP.\n *\n * These emails can only be sent to valid Mailisk namespaces, i.e. emails that end in @mynamespace.mailisk.net\n *\n * @example\n * For example, sending a test email:\n * ```typescript\n * client.sendVirtualEmail(namespace, {\n * from: \"test@example.com\",\n * to: `john@${namespace}.mailisk.net`,\n * subject: \"This is a test\",\n * text: \"Testing\",\n * });\n * ```\n */\n async sendVirtualEmail(namespace: string, params: SendVirtualEmailParams): Promise<void> {\n const smtpSettings = await this.getSmtpSettings(namespace);\n\n const transport = nodemailer.createTransport({\n host: smtpSettings.data.host,\n port: smtpSettings.data.port,\n secure: false,\n auth: {\n user: smtpSettings.data.username,\n pass: smtpSettings.data.password,\n },\n });\n\n const { from, to, subject, text, html, headers, attachments } = params;\n\n await transport.sendMail({\n from,\n to,\n subject,\n text,\n html,\n headers,\n attachments,\n });\n\n transport.close();\n }\n\n /**\n * Search inbox of a namespace.\n *\n * By default, this calls the api using the `wait` flag. This means the call won't timeout until at least one email is received or 5 minutes pass.\n * It also uses a default `from_timestamp` of **current timestamp - 5 seconds**. This means that older emails will be ignored.\n *\n * Both of these settings can be overriden by passing them in the `params` object.\n *\n * @example\n * Get the latest emails in the namespace\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace);\n * ```\n *\n * @example\n * Get the latest emails for a specific email address\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace, {\n * to_addr_prefix: 'john@mynamespace.mailisk.net'\n * });\n * ```\n */\n async searchInbox(\n namespace: string,\n params?: SearchInboxParams,\n config?: AxiosRequestConfig\n ): Promise<SearchInboxResponse> {\n let _params = { ...params };\n\n // default from timestamp, 15 minutes before starting this request\n if (params?.from_timestamp === undefined || params?.from_timestamp === null) {\n _params.from_timestamp = Math.floor(new Date().getTime() / 1000) - 15 * 60;\n }\n\n // by default wait for email\n if (params?.wait !== false) {\n _params.wait = true;\n }\n\n let _config = { ...config };\n\n if (!config?.maxRedirects) {\n _config.maxRedirects = 99999;\n }\n\n // by default, wait 5 minutes for emails before timing out\n if (_params.wait && !config?.timeout) {\n _config.timeout = 1000 * 60 * 5;\n }\n\n return (\n await this.axiosInstance.get(`api/emails/${namespace}/inbox`, {\n ..._config,\n params: _params,\n })\n ).data;\n }\n\n /**\n * Get the SMTP settings for a namespace.\n */\n async getSmtpSettings(namespace: string): Promise<SmtpSettings> {\n const result = await this.axiosInstance.get(`api/smtp/${namespace}`);\n return result.data;\n }\n\n async getAttachment(attachmentId: string): Promise<GetAttachmentResponse> {\n const result = await this.axiosInstance.get(`api/attachments/${attachmentId}`);\n return result.data;\n }\n\n /**\n * Download an attachment from an attachment ID.\n *\n * @example\n * Download an attachment from an email\n * ```typescript\n * const attachment = email.attachments[0];\n * const attachmentBuffer = await client.downloadAttachment(attachment.id);\n *\n * // save to file\n * fs.writeFileSync(attachment.filename, attachmentBuffer);\n * ```\n */\n async downloadAttachment(attachmentId: string): Promise<Buffer> {\n const result = await this.getAttachment(attachmentId);\n\n const response = await axios.get(result.data.download_url, { responseType: \"arraybuffer\" });\n return Buffer.from(response.data);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAiE;AASjE,wBAAuB;AAEhB,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAY,EAAE,QAAQ,SAAS,KAAK,GAAuE;AACzG,SAAK,gBAAgB,aAAAA,QAAM,OAAO;AAAA,MAChC,SAAS;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA,SAAS,WAAW;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEiB;AAAA,EAKjB,MAAM,iBAAkD;AACtD,YAAQ,MAAM,KAAK,cAAc,IAAI,gBAAgB,GAAG;AAAA,EAC1D;AAAA,EAkBA,MAAM,iBAAiB,WAAmB,QAA+C;AACvF,UAAM,eAAe,MAAM,KAAK,gBAAgB,SAAS;AAEzD,UAAM,YAAY,kBAAAC,QAAW,gBAAgB;AAAA,MAC3C,MAAM,aAAa,KAAK;AAAA,MACxB,MAAM,aAAa,KAAK;AAAA,MACxB,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,MAAM,aAAa,KAAK;AAAA,QACxB,MAAM,aAAa,KAAK;AAAA,MAC1B;AAAA,IACF,CAAC;AAED,UAAM,EAAE,MAAM,IAAI,SAAS,MAAM,MAAM,SAAS,YAAY,IAAI;AAEhE,UAAM,UAAU,SAAS;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,cAAU,MAAM;AAAA,EAClB;AAAA,EAwBA,MAAM,YACJ,WACA,QACA,QAC8B;AAC9B,QAAI,UAAU,EAAE,GAAG,OAAO;AAG1B,QAAI,QAAQ,mBAAmB,UAAa,QAAQ,mBAAmB,MAAM;AAC3E,cAAQ,iBAAiB,KAAK,MAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,GAAI,IAAI,KAAK;AAAA,IAC1E;AAGA,QAAI,QAAQ,SAAS,OAAO;AAC1B,cAAQ,OAAO;AAAA,IACjB;AAEA,QAAI,UAAU,EAAE,GAAG,OAAO;AAE1B,QAAI,CAAC,QAAQ,cAAc;AACzB,cAAQ,eAAe;AAAA,IACzB;AAGA,QAAI,QAAQ,QAAQ,CAAC,QAAQ,SAAS;AACpC,cAAQ,UAAU,MAAO,KAAK;AAAA,IAChC;AAEA,YACE,MAAM,KAAK,cAAc,IAAI,cAAc,mBAAmB;AAAA,MAC5D,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC,GACD;AAAA,EACJ;AAAA,EAKA,MAAM,gBAAgB,WAA0C;AAC9D,UAAM,SAAS,MAAM,KAAK,cAAc,IAAI,YAAY,WAAW;AACnE,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,cAAc,cAAsD;AACxE,UAAM,SAAS,MAAM,KAAK,cAAc,IAAI,mBAAmB,cAAc;AAC7E,WAAO,OAAO;AAAA,EAChB;AAAA,EAeA,MAAM,mBAAmB,cAAuC;AAC9D,UAAM,SAAS,MAAM,KAAK,cAAc,YAAY;AAEpD,UAAM,WAAW,MAAM,aAAAD,QAAM,IAAI,OAAO,KAAK,cAAc,EAAE,cAAc,cAAc,CAAC;AAC1F,WAAO,OAAO,KAAK,SAAS,IAAI;AAAA,EAClC;AACF;AA1Ja;","names":["axios","nodemailer"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/mailisk.ts"],"sourcesContent":["export * from \"./mailisk\";\n","import axios, { AxiosBasicCredentials, AxiosInstance, AxiosRequestConfig } from \"axios\";\nimport {\n GetAttachmentResponse,\n ListNamespacesResponse,\n ListSmsNumbersResponse,\n SearchInboxParams,\n SearchInboxResponse,\n SearchSmsMessagesParams,\n SearchSmsMessagesResponse,\n SendVirtualEmailParams,\n SendVirtualSmsParams,\n SmtpSettings,\n} from \"./mailisk.interfaces\";\nimport nodemailer from \"nodemailer\";\n\nexport class MailiskClient {\n constructor({ apiKey, baseUrl, auth }: { apiKey: string; baseUrl?: string; auth?: AxiosBasicCredentials }) {\n this.axiosInstance = axios.create({\n headers: {\n \"X-Api-Key\": apiKey,\n },\n baseURL: baseUrl || \"https://api.mailisk.com/\",\n auth,\n });\n }\n\n private readonly axiosInstance: AxiosInstance;\n\n /**\n * Search SMS messages sent to a phone number.\n *\n * @example\n * Search for SMS messages sent to a phone number\n * ```typescript\n * const { data: smsMessages } = await client.searchSmsMessages(\"1234567890\");\n * ```\n */\n async searchSmsMessages(\n phoneNumber: string,\n params?: SearchSmsMessagesParams,\n config?: AxiosRequestConfig\n ): Promise<SearchSmsMessagesResponse> {\n let _params: SearchSmsMessagesParams = { ...params };\n\n // default from timestamp, 15 minutes before starting this request\n if (params?.from_date === undefined || params?.from_date === null) {\n _params.from_date = new Date(Date.now() - 15 * 60 * 1000).toISOString();\n }\n\n // by default wait for sms\n if (params?.wait !== false) {\n _params.wait = true;\n }\n\n let _config = { ...config };\n\n if (config?.maxRedirects === undefined) {\n _config.maxRedirects = 99999;\n }\n\n // by default, wait 5 minutes for emails before timing out\n if (_params.wait && config?.timeout === undefined) {\n _config.timeout = 1000 * 60 * 5;\n }\n\n const requestParams = {\n ..._params,\n from_date: _params.from_date ?? undefined,\n to_date: _params.to_date ?? undefined,\n };\n\n return (\n await this.axiosInstance.get(`api/sms/${phoneNumber}/messages`, {\n ..._config,\n params: requestParams,\n })\n ).data;\n }\n\n /**\n * List all SMS phone numbers associated with the current account.\n *\n * @example\n * List all SMS phone numbers\n * ```typescript\n * const { data: smsNumbers } = await client.listSmsNumbers();\n * ```\n */\n async listSmsNumbers(): Promise<ListSmsNumbersResponse> {\n return (await this.axiosInstance.get(\"api/sms/numbers\")).data;\n }\n\n async sendVirtualSms(params: SendVirtualSmsParams): Promise<void> {\n return (await this.axiosInstance.post(\"api/sms/virtual\", params)).data;\n }\n\n /**\n * List all namespaces that belong to the current account (API key).\n */\n async listNamespaces(): Promise<ListNamespacesResponse> {\n return (await this.axiosInstance.get(\"api/namespaces\")).data;\n }\n\n /**\n * Send an email using the Virtual SMTP.\n *\n * These emails can only be sent to valid Mailisk namespaces, i.e. emails that end in @mynamespace.mailisk.net\n *\n * @example\n * For example, sending a test email:\n * ```typescript\n * client.sendVirtualEmail(namespace, {\n * from: \"test@example.com\",\n * to: `john@${namespace}.mailisk.net`,\n * subject: \"This is a test\",\n * text: \"Testing\",\n * });\n * ```\n */\n async sendVirtualEmail(namespace: string, params: SendVirtualEmailParams): Promise<void> {\n const smtpSettings = await this.getSmtpSettings(namespace);\n\n const transport = nodemailer.createTransport({\n host: smtpSettings.data.host,\n port: smtpSettings.data.port,\n secure: false,\n auth: {\n user: smtpSettings.data.username,\n pass: smtpSettings.data.password,\n },\n });\n\n const { from, to, subject, text, html, headers, attachments } = params;\n\n await transport.sendMail({\n from,\n to,\n subject,\n text,\n html,\n headers,\n attachments,\n });\n\n transport.close();\n }\n\n /**\n * Search inbox of a namespace.\n *\n * By default, this calls the api using the `wait` flag. This means the call won't timeout until at least one email is received or 5 minutes pass.\n * It also uses a default `from_timestamp` of **current timestamp - 15 minutes**. This means that older emails will be ignored.\n *\n * Both of these settings can be overriden by passing them in the `params` object.\n *\n * @example\n * Get the latest emails\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace);\n * ```\n *\n * @example\n * Get the latest emails for a specific email address\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace, {\n * to_addr_prefix: 'john@mynamespace.mailisk.net'\n * });\n * ```\n *\n * @example\n * Get the last 20 emails in the namespace\n * ```typescript\n * const { data: emails } = await mailisk.searchInbox(namespace, {\n * wait: false,\n * from_timestamp: 0,\n * limit: 20\n * });\n * ```\n */\n async searchInbox(\n namespace: string,\n params?: SearchInboxParams,\n config?: AxiosRequestConfig\n ): Promise<SearchInboxResponse> {\n let _params = { ...params };\n\n // default from timestamp, 15 minutes before starting this request\n if (params?.from_timestamp === undefined || params?.from_timestamp === null) {\n _params.from_timestamp = Math.floor(new Date().getTime() / 1000) - 15 * 60;\n }\n\n // by default wait for email\n if (params?.wait !== false) {\n _params.wait = true;\n }\n\n let _config = { ...config };\n\n if (config?.maxRedirects === undefined) {\n _config.maxRedirects = 99999;\n }\n\n // by default, wait 5 minutes for emails before timing out\n if (_params.wait && config?.timeout === undefined) {\n _config.timeout = 1000 * 60 * 5;\n }\n\n return (\n await this.axiosInstance.get(`api/emails/${namespace}/inbox`, {\n ..._config,\n params: _params,\n })\n ).data;\n }\n\n /**\n * Get the SMTP settings for a namespace.\n */\n async getSmtpSettings(namespace: string): Promise<SmtpSettings> {\n const result = await this.axiosInstance.get(`api/smtp/${namespace}`);\n return result.data;\n }\n\n async getAttachment(attachmentId: string): Promise<GetAttachmentResponse> {\n const result = await this.axiosInstance.get(`api/attachments/${attachmentId}`);\n return result.data;\n }\n\n /**\n * Download an attachment from an attachment ID.\n *\n * @example\n * Download an attachment from an email\n * ```typescript\n * const attachment = email.attachments[0];\n * const attachmentBuffer = await client.downloadAttachment(attachment.id);\n *\n * // save to file\n * fs.writeFileSync(attachment.filename, attachmentBuffer);\n * ```\n */\n async downloadAttachment(attachmentId: string): Promise<Buffer> {\n const result = await this.getAttachment(attachmentId);\n\n const response = await axios.get(result.data.download_url, { responseType: \"arraybuffer\" });\n return Buffer.from(response.data);\n }\n}\n"],"mappings":"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","names":["axios","nodemailer"]}
package/dist/index.mjs CHANGED
@@ -15,6 +15,37 @@ var MailiskClient = class {
15
15
  });
16
16
  }
17
17
  axiosInstance;
18
+ async searchSmsMessages(phoneNumber, params, config) {
19
+ let _params = { ...params };
20
+ if (params?.from_date === void 0 || params?.from_date === null) {
21
+ _params.from_date = new Date(Date.now() - 15 * 60 * 1e3).toISOString();
22
+ }
23
+ if (params?.wait !== false) {
24
+ _params.wait = true;
25
+ }
26
+ let _config = { ...config };
27
+ if (config?.maxRedirects === void 0) {
28
+ _config.maxRedirects = 99999;
29
+ }
30
+ if (_params.wait && config?.timeout === void 0) {
31
+ _config.timeout = 1e3 * 60 * 5;
32
+ }
33
+ const requestParams = {
34
+ ..._params,
35
+ from_date: _params.from_date ?? void 0,
36
+ to_date: _params.to_date ?? void 0
37
+ };
38
+ return (await this.axiosInstance.get(`api/sms/${phoneNumber}/messages`, {
39
+ ..._config,
40
+ params: requestParams
41
+ })).data;
42
+ }
43
+ async listSmsNumbers() {
44
+ return (await this.axiosInstance.get("api/sms/numbers")).data;
45
+ }
46
+ async sendVirtualSms(params) {
47
+ return (await this.axiosInstance.post("api/sms/virtual", params)).data;
48
+ }
18
49
  async listNamespaces() {
19
50
  return (await this.axiosInstance.get("api/namespaces")).data;
20
51
  }
@@ -50,10 +81,10 @@ var MailiskClient = class {
50
81
  _params.wait = true;
51
82
  }
52
83
  let _config = { ...config };
53
- if (!config?.maxRedirects) {
84
+ if (config?.maxRedirects === void 0) {
54
85
  _config.maxRedirects = 99999;
55
86
  }
56
- if (_params.wait && !config?.timeout) {
87
+ if (_params.wait && config?.timeout === void 0) {
57
88
  _config.timeout = 1e3 * 60 * 5;
58
89
  }
59
90
  return (await this.axiosInstance.get(`api/emails/${namespace}/inbox`, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mailisk.ts"],"sourcesContent":["import axios, { AxiosBasicCredentials, AxiosRequestConfig } from \"axios\";\nimport {\n GetAttachmentResponse,\n ListNamespacesResponse,\n SearchInboxParams,\n SearchInboxResponse,\n SendVirtualEmailParams,\n SmtpSettings,\n} from \"./mailisk.interfaces\";\nimport nodemailer from \"nodemailer\";\n\nexport class MailiskClient {\n constructor({ apiKey, baseUrl, auth }: { apiKey: string; baseUrl?: string; auth?: AxiosBasicCredentials }) {\n this.axiosInstance = axios.create({\n headers: {\n \"X-Api-Key\": apiKey,\n },\n baseURL: baseUrl || \"https://api.mailisk.com/\",\n auth,\n });\n }\n\n private readonly axiosInstance;\n\n /**\n * List all namespaces that belong to the current account (API key).\n */\n async listNamespaces(): Promise<ListNamespacesResponse> {\n return (await this.axiosInstance.get(\"api/namespaces\")).data;\n }\n\n /**\n * Send an email using the Virtual SMTP.\n *\n * These emails can only be sent to valid Mailisk namespaces, i.e. emails that end in @mynamespace.mailisk.net\n *\n * @example\n * For example, sending a test email:\n * ```typescript\n * client.sendVirtualEmail(namespace, {\n * from: \"test@example.com\",\n * to: `john@${namespace}.mailisk.net`,\n * subject: \"This is a test\",\n * text: \"Testing\",\n * });\n * ```\n */\n async sendVirtualEmail(namespace: string, params: SendVirtualEmailParams): Promise<void> {\n const smtpSettings = await this.getSmtpSettings(namespace);\n\n const transport = nodemailer.createTransport({\n host: smtpSettings.data.host,\n port: smtpSettings.data.port,\n secure: false,\n auth: {\n user: smtpSettings.data.username,\n pass: smtpSettings.data.password,\n },\n });\n\n const { from, to, subject, text, html, headers, attachments } = params;\n\n await transport.sendMail({\n from,\n to,\n subject,\n text,\n html,\n headers,\n attachments,\n });\n\n transport.close();\n }\n\n /**\n * Search inbox of a namespace.\n *\n * By default, this calls the api using the `wait` flag. This means the call won't timeout until at least one email is received or 5 minutes pass.\n * It also uses a default `from_timestamp` of **current timestamp - 5 seconds**. This means that older emails will be ignored.\n *\n * Both of these settings can be overriden by passing them in the `params` object.\n *\n * @example\n * Get the latest emails in the namespace\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace);\n * ```\n *\n * @example\n * Get the latest emails for a specific email address\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace, {\n * to_addr_prefix: 'john@mynamespace.mailisk.net'\n * });\n * ```\n */\n async searchInbox(\n namespace: string,\n params?: SearchInboxParams,\n config?: AxiosRequestConfig\n ): Promise<SearchInboxResponse> {\n let _params = { ...params };\n\n // default from timestamp, 15 minutes before starting this request\n if (params?.from_timestamp === undefined || params?.from_timestamp === null) {\n _params.from_timestamp = Math.floor(new Date().getTime() / 1000) - 15 * 60;\n }\n\n // by default wait for email\n if (params?.wait !== false) {\n _params.wait = true;\n }\n\n let _config = { ...config };\n\n if (!config?.maxRedirects) {\n _config.maxRedirects = 99999;\n }\n\n // by default, wait 5 minutes for emails before timing out\n if (_params.wait && !config?.timeout) {\n _config.timeout = 1000 * 60 * 5;\n }\n\n return (\n await this.axiosInstance.get(`api/emails/${namespace}/inbox`, {\n ..._config,\n params: _params,\n })\n ).data;\n }\n\n /**\n * Get the SMTP settings for a namespace.\n */\n async getSmtpSettings(namespace: string): Promise<SmtpSettings> {\n const result = await this.axiosInstance.get(`api/smtp/${namespace}`);\n return result.data;\n }\n\n async getAttachment(attachmentId: string): Promise<GetAttachmentResponse> {\n const result = await this.axiosInstance.get(`api/attachments/${attachmentId}`);\n return result.data;\n }\n\n /**\n * Download an attachment from an attachment ID.\n *\n * @example\n * Download an attachment from an email\n * ```typescript\n * const attachment = email.attachments[0];\n * const attachmentBuffer = await client.downloadAttachment(attachment.id);\n *\n * // save to file\n * fs.writeFileSync(attachment.filename, attachmentBuffer);\n * ```\n */\n async downloadAttachment(attachmentId: string): Promise<Buffer> {\n const result = await this.getAttachment(attachmentId);\n\n const response = await axios.get(result.data.download_url, { responseType: \"arraybuffer\" });\n return Buffer.from(response.data);\n }\n}\n"],"mappings":";;;;AAAA,OAAO,WAA0D;AASjE,OAAO,gBAAgB;AAEhB,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAAY,EAAE,QAAQ,SAAS,KAAK,GAAuE;AACzG,SAAK,gBAAgB,MAAM,OAAO;AAAA,MAChC,SAAS;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA,SAAS,WAAW;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEiB;AAAA,EAKjB,MAAM,iBAAkD;AACtD,YAAQ,MAAM,KAAK,cAAc,IAAI,gBAAgB,GAAG;AAAA,EAC1D;AAAA,EAkBA,MAAM,iBAAiB,WAAmB,QAA+C;AACvF,UAAM,eAAe,MAAM,KAAK,gBAAgB,SAAS;AAEzD,UAAM,YAAY,WAAW,gBAAgB;AAAA,MAC3C,MAAM,aAAa,KAAK;AAAA,MACxB,MAAM,aAAa,KAAK;AAAA,MACxB,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,MAAM,aAAa,KAAK;AAAA,QACxB,MAAM,aAAa,KAAK;AAAA,MAC1B;AAAA,IACF,CAAC;AAED,UAAM,EAAE,MAAM,IAAI,SAAS,MAAM,MAAM,SAAS,YAAY,IAAI;AAEhE,UAAM,UAAU,SAAS;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,cAAU,MAAM;AAAA,EAClB;AAAA,EAwBA,MAAM,YACJ,WACA,QACA,QAC8B;AAC9B,QAAI,UAAU,EAAE,GAAG,OAAO;AAG1B,QAAI,QAAQ,mBAAmB,UAAa,QAAQ,mBAAmB,MAAM;AAC3E,cAAQ,iBAAiB,KAAK,MAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,GAAI,IAAI,KAAK;AAAA,IAC1E;AAGA,QAAI,QAAQ,SAAS,OAAO;AAC1B,cAAQ,OAAO;AAAA,IACjB;AAEA,QAAI,UAAU,EAAE,GAAG,OAAO;AAE1B,QAAI,CAAC,QAAQ,cAAc;AACzB,cAAQ,eAAe;AAAA,IACzB;AAGA,QAAI,QAAQ,QAAQ,CAAC,QAAQ,SAAS;AACpC,cAAQ,UAAU,MAAO,KAAK;AAAA,IAChC;AAEA,YACE,MAAM,KAAK,cAAc,IAAI,cAAc,mBAAmB;AAAA,MAC5D,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC,GACD;AAAA,EACJ;AAAA,EAKA,MAAM,gBAAgB,WAA0C;AAC9D,UAAM,SAAS,MAAM,KAAK,cAAc,IAAI,YAAY,WAAW;AACnE,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,cAAc,cAAsD;AACxE,UAAM,SAAS,MAAM,KAAK,cAAc,IAAI,mBAAmB,cAAc;AAC7E,WAAO,OAAO;AAAA,EAChB;AAAA,EAeA,MAAM,mBAAmB,cAAuC;AAC9D,UAAM,SAAS,MAAM,KAAK,cAAc,YAAY;AAEpD,UAAM,WAAW,MAAM,MAAM,IAAI,OAAO,KAAK,cAAc,EAAE,cAAc,cAAc,CAAC;AAC1F,WAAO,OAAO,KAAK,SAAS,IAAI;AAAA,EAClC;AACF;AA1Ja;","names":[]}
1
+ {"version":3,"sources":["../src/mailisk.ts"],"sourcesContent":["import axios, { AxiosBasicCredentials, AxiosInstance, AxiosRequestConfig } from \"axios\";\nimport {\n GetAttachmentResponse,\n ListNamespacesResponse,\n ListSmsNumbersResponse,\n SearchInboxParams,\n SearchInboxResponse,\n SearchSmsMessagesParams,\n SearchSmsMessagesResponse,\n SendVirtualEmailParams,\n SendVirtualSmsParams,\n SmtpSettings,\n} from \"./mailisk.interfaces\";\nimport nodemailer from \"nodemailer\";\n\nexport class MailiskClient {\n constructor({ apiKey, baseUrl, auth }: { apiKey: string; baseUrl?: string; auth?: AxiosBasicCredentials }) {\n this.axiosInstance = axios.create({\n headers: {\n \"X-Api-Key\": apiKey,\n },\n baseURL: baseUrl || \"https://api.mailisk.com/\",\n auth,\n });\n }\n\n private readonly axiosInstance: AxiosInstance;\n\n /**\n * Search SMS messages sent to a phone number.\n *\n * @example\n * Search for SMS messages sent to a phone number\n * ```typescript\n * const { data: smsMessages } = await client.searchSmsMessages(\"1234567890\");\n * ```\n */\n async searchSmsMessages(\n phoneNumber: string,\n params?: SearchSmsMessagesParams,\n config?: AxiosRequestConfig\n ): Promise<SearchSmsMessagesResponse> {\n let _params: SearchSmsMessagesParams = { ...params };\n\n // default from timestamp, 15 minutes before starting this request\n if (params?.from_date === undefined || params?.from_date === null) {\n _params.from_date = new Date(Date.now() - 15 * 60 * 1000).toISOString();\n }\n\n // by default wait for sms\n if (params?.wait !== false) {\n _params.wait = true;\n }\n\n let _config = { ...config };\n\n if (config?.maxRedirects === undefined) {\n _config.maxRedirects = 99999;\n }\n\n // by default, wait 5 minutes for emails before timing out\n if (_params.wait && config?.timeout === undefined) {\n _config.timeout = 1000 * 60 * 5;\n }\n\n const requestParams = {\n ..._params,\n from_date: _params.from_date ?? undefined,\n to_date: _params.to_date ?? undefined,\n };\n\n return (\n await this.axiosInstance.get(`api/sms/${phoneNumber}/messages`, {\n ..._config,\n params: requestParams,\n })\n ).data;\n }\n\n /**\n * List all SMS phone numbers associated with the current account.\n *\n * @example\n * List all SMS phone numbers\n * ```typescript\n * const { data: smsNumbers } = await client.listSmsNumbers();\n * ```\n */\n async listSmsNumbers(): Promise<ListSmsNumbersResponse> {\n return (await this.axiosInstance.get(\"api/sms/numbers\")).data;\n }\n\n async sendVirtualSms(params: SendVirtualSmsParams): Promise<void> {\n return (await this.axiosInstance.post(\"api/sms/virtual\", params)).data;\n }\n\n /**\n * List all namespaces that belong to the current account (API key).\n */\n async listNamespaces(): Promise<ListNamespacesResponse> {\n return (await this.axiosInstance.get(\"api/namespaces\")).data;\n }\n\n /**\n * Send an email using the Virtual SMTP.\n *\n * These emails can only be sent to valid Mailisk namespaces, i.e. emails that end in @mynamespace.mailisk.net\n *\n * @example\n * For example, sending a test email:\n * ```typescript\n * client.sendVirtualEmail(namespace, {\n * from: \"test@example.com\",\n * to: `john@${namespace}.mailisk.net`,\n * subject: \"This is a test\",\n * text: \"Testing\",\n * });\n * ```\n */\n async sendVirtualEmail(namespace: string, params: SendVirtualEmailParams): Promise<void> {\n const smtpSettings = await this.getSmtpSettings(namespace);\n\n const transport = nodemailer.createTransport({\n host: smtpSettings.data.host,\n port: smtpSettings.data.port,\n secure: false,\n auth: {\n user: smtpSettings.data.username,\n pass: smtpSettings.data.password,\n },\n });\n\n const { from, to, subject, text, html, headers, attachments } = params;\n\n await transport.sendMail({\n from,\n to,\n subject,\n text,\n html,\n headers,\n attachments,\n });\n\n transport.close();\n }\n\n /**\n * Search inbox of a namespace.\n *\n * By default, this calls the api using the `wait` flag. This means the call won't timeout until at least one email is received or 5 minutes pass.\n * It also uses a default `from_timestamp` of **current timestamp - 15 minutes**. This means that older emails will be ignored.\n *\n * Both of these settings can be overriden by passing them in the `params` object.\n *\n * @example\n * Get the latest emails\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace);\n * ```\n *\n * @example\n * Get the latest emails for a specific email address\n * ```typescript\n * const { data: emails } = await client.searchInbox(namespace, {\n * to_addr_prefix: 'john@mynamespace.mailisk.net'\n * });\n * ```\n *\n * @example\n * Get the last 20 emails in the namespace\n * ```typescript\n * const { data: emails } = await mailisk.searchInbox(namespace, {\n * wait: false,\n * from_timestamp: 0,\n * limit: 20\n * });\n * ```\n */\n async searchInbox(\n namespace: string,\n params?: SearchInboxParams,\n config?: AxiosRequestConfig\n ): Promise<SearchInboxResponse> {\n let _params = { ...params };\n\n // default from timestamp, 15 minutes before starting this request\n if (params?.from_timestamp === undefined || params?.from_timestamp === null) {\n _params.from_timestamp = Math.floor(new Date().getTime() / 1000) - 15 * 60;\n }\n\n // by default wait for email\n if (params?.wait !== false) {\n _params.wait = true;\n }\n\n let _config = { ...config };\n\n if (config?.maxRedirects === undefined) {\n _config.maxRedirects = 99999;\n }\n\n // by default, wait 5 minutes for emails before timing out\n if (_params.wait && config?.timeout === undefined) {\n _config.timeout = 1000 * 60 * 5;\n }\n\n return (\n await this.axiosInstance.get(`api/emails/${namespace}/inbox`, {\n ..._config,\n params: _params,\n })\n ).data;\n }\n\n /**\n * Get the SMTP settings for a namespace.\n */\n async getSmtpSettings(namespace: string): Promise<SmtpSettings> {\n const result = await this.axiosInstance.get(`api/smtp/${namespace}`);\n return result.data;\n }\n\n async getAttachment(attachmentId: string): Promise<GetAttachmentResponse> {\n const result = await this.axiosInstance.get(`api/attachments/${attachmentId}`);\n return result.data;\n }\n\n /**\n * Download an attachment from an attachment ID.\n *\n * @example\n * Download an attachment from an email\n * ```typescript\n * const attachment = email.attachments[0];\n * const attachmentBuffer = await client.downloadAttachment(attachment.id);\n *\n * // save to file\n * fs.writeFileSync(attachment.filename, attachmentBuffer);\n * ```\n */\n async downloadAttachment(attachmentId: string): Promise<Buffer> {\n const result = await this.getAttachment(attachmentId);\n\n const response = await axios.get(result.data.download_url, { responseType: \"arraybuffer\" });\n return Buffer.from(response.data);\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mailisk",
3
- "version": "2.1.1",
3
+ "version": "2.2.2",
4
4
  "description": "Mailisk library for NodeJS",
5
5
  "keywords": [
6
6
  "mailisk",
@@ -26,7 +26,7 @@
26
26
  "jest-mock-axios": "^4.8.0",
27
27
  "ts-jest": "^29.2.6",
28
28
  "tsup": "^6.2.3",
29
- "typescript": "^4.8.4"
29
+ "typescript": "^4.9.5"
30
30
  },
31
31
  "dependencies": {
32
32
  "axios": "^1.1.2",
@@ -49,6 +49,42 @@ export interface Email {
49
49
  attachments?: EmailAttachment[];
50
50
  }
51
51
 
52
+ export interface SmsMessage {
53
+ /** Unique identifier for the message */
54
+ id: string;
55
+ /** Unique identifier for the SMS phone number */
56
+ sms_phone_number_id: string;
57
+ /** Body of the message */
58
+ body: string;
59
+ /** From number of the message */
60
+ from_number: string;
61
+ /** To number of the message */
62
+ to_number: string;
63
+ /** Provider message ID */
64
+ provider_message_id?: string;
65
+ /** Date and time the message was created */
66
+ created_at: string;
67
+ /** Direction of the message */
68
+ direction: "inbound" | "outbound";
69
+ }
70
+
71
+ export interface SmsNumber {
72
+ /** Unique identifier for the SMS number */
73
+ id: string;
74
+ /** Unique identifier for the organisation */
75
+ organisation_id: string;
76
+ /** Status of the SMS number */
77
+ status: "requested" | "active" | "disabled";
78
+ /** Country of the SMS number */
79
+ country: string;
80
+ /** SMS Phone number */
81
+ phone_number?: string;
82
+ /** Date and time the SMS number was created */
83
+ created_at: string;
84
+ /** Date and time the SMS number was updated */
85
+ updated_at: string;
86
+ }
87
+
52
88
  export interface SearchInboxParams {
53
89
  /**
54
90
  * The maximum number of emails that can be returned in this request, used alongside `offset` for pagination.
@@ -128,12 +164,8 @@ export interface GetAttachmentResponse {
128
164
  }
129
165
 
130
166
  export interface ListNamespacesResponse {
131
- data: [
132
- {
133
- id: string;
134
- namespace: string;
135
- }
136
- ];
167
+ total_count: number;
168
+ data: { id: string; namespace: string }[];
137
169
  }
138
170
 
139
171
  export interface SendVirtualEmailParams {
@@ -156,3 +188,56 @@ export interface SendVirtualEmailParams {
156
188
  /** Attachments to the email */
157
189
  attachments?: Attachment[];
158
190
  }
191
+
192
+ export interface SearchSmsMessagesParams {
193
+ /**
194
+ * The maximum number of SMS messages returned (1-100), used alongside `offset` for pagination.
195
+ */
196
+ limit?: number;
197
+ /**
198
+ * The number of SMS messages to skip/ignore, used alongside `limit` for pagination.
199
+ */
200
+ offset?: number;
201
+ /**
202
+ * Filter messages by body contents (case insensitive).
203
+ */
204
+ body?: string;
205
+ /**
206
+ * Filter messages by sender phone number prefix.
207
+ */
208
+ from_number?: string;
209
+ /**
210
+ * Filter messages created on or after this date.
211
+ * Provide an ISO 8601 timestamp string.
212
+ */
213
+ from_date?: string;
214
+ /**
215
+ * Filter messages created on or before this date.
216
+ * Provide an ISO 8601 timestamp string.
217
+ */
218
+ to_date?: string;
219
+ /**
220
+ * When true, keep the request open until at least one SMS is returned.
221
+ */
222
+ wait?: boolean;
223
+ }
224
+
225
+ export interface SearchSmsMessagesResponse {
226
+ total_count: number;
227
+ options: SearchSmsMessagesParams;
228
+ data: SmsMessage[];
229
+ }
230
+
231
+ export interface ListSmsNumbersResponse {
232
+ total_count: number;
233
+ data: SmsNumber[];
234
+ }
235
+
236
+ export interface SendVirtualSmsParams {
237
+ /** The phone number to send the SMS from */
238
+ from_number: string;
239
+ /** The phone number to send the SMS to */
240
+ to_number: string;
241
+ /** The body of the SMS message */
242
+ body: string;
243
+ }
package/src/mailisk.ts CHANGED
@@ -1,10 +1,14 @@
1
- import axios, { AxiosBasicCredentials, AxiosRequestConfig } from "axios";
1
+ import axios, { AxiosBasicCredentials, AxiosInstance, AxiosRequestConfig } from "axios";
2
2
  import {
3
3
  GetAttachmentResponse,
4
4
  ListNamespacesResponse,
5
+ ListSmsNumbersResponse,
5
6
  SearchInboxParams,
6
7
  SearchInboxResponse,
8
+ SearchSmsMessagesParams,
9
+ SearchSmsMessagesResponse,
7
10
  SendVirtualEmailParams,
11
+ SendVirtualSmsParams,
8
12
  SmtpSettings,
9
13
  } from "./mailisk.interfaces";
10
14
  import nodemailer from "nodemailer";
@@ -20,7 +24,75 @@ export class MailiskClient {
20
24
  });
21
25
  }
22
26
 
23
- private readonly axiosInstance;
27
+ private readonly axiosInstance: AxiosInstance;
28
+
29
+ /**
30
+ * Search SMS messages sent to a phone number.
31
+ *
32
+ * @example
33
+ * Search for SMS messages sent to a phone number
34
+ * ```typescript
35
+ * const { data: smsMessages } = await client.searchSmsMessages("1234567890");
36
+ * ```
37
+ */
38
+ async searchSmsMessages(
39
+ phoneNumber: string,
40
+ params?: SearchSmsMessagesParams,
41
+ config?: AxiosRequestConfig
42
+ ): Promise<SearchSmsMessagesResponse> {
43
+ let _params: SearchSmsMessagesParams = { ...params };
44
+
45
+ // default from timestamp, 15 minutes before starting this request
46
+ if (params?.from_date === undefined || params?.from_date === null) {
47
+ _params.from_date = new Date(Date.now() - 15 * 60 * 1000).toISOString();
48
+ }
49
+
50
+ // by default wait for sms
51
+ if (params?.wait !== false) {
52
+ _params.wait = true;
53
+ }
54
+
55
+ let _config = { ...config };
56
+
57
+ if (config?.maxRedirects === undefined) {
58
+ _config.maxRedirects = 99999;
59
+ }
60
+
61
+ // by default, wait 5 minutes for emails before timing out
62
+ if (_params.wait && config?.timeout === undefined) {
63
+ _config.timeout = 1000 * 60 * 5;
64
+ }
65
+
66
+ const requestParams = {
67
+ ..._params,
68
+ from_date: _params.from_date ?? undefined,
69
+ to_date: _params.to_date ?? undefined,
70
+ };
71
+
72
+ return (
73
+ await this.axiosInstance.get(`api/sms/${phoneNumber}/messages`, {
74
+ ..._config,
75
+ params: requestParams,
76
+ })
77
+ ).data;
78
+ }
79
+
80
+ /**
81
+ * List all SMS phone numbers associated with the current account.
82
+ *
83
+ * @example
84
+ * List all SMS phone numbers
85
+ * ```typescript
86
+ * const { data: smsNumbers } = await client.listSmsNumbers();
87
+ * ```
88
+ */
89
+ async listSmsNumbers(): Promise<ListSmsNumbersResponse> {
90
+ return (await this.axiosInstance.get("api/sms/numbers")).data;
91
+ }
92
+
93
+ async sendVirtualSms(params: SendVirtualSmsParams): Promise<void> {
94
+ return (await this.axiosInstance.post("api/sms/virtual", params)).data;
95
+ }
24
96
 
25
97
  /**
26
98
  * List all namespaces that belong to the current account (API key).
@@ -77,12 +149,12 @@ export class MailiskClient {
77
149
  * Search inbox of a namespace.
78
150
  *
79
151
  * By default, this calls the api using the `wait` flag. This means the call won't timeout until at least one email is received or 5 minutes pass.
80
- * It also uses a default `from_timestamp` of **current timestamp - 5 seconds**. This means that older emails will be ignored.
152
+ * It also uses a default `from_timestamp` of **current timestamp - 15 minutes**. This means that older emails will be ignored.
81
153
  *
82
154
  * Both of these settings can be overriden by passing them in the `params` object.
83
155
  *
84
156
  * @example
85
- * Get the latest emails in the namespace
157
+ * Get the latest emails
86
158
  * ```typescript
87
159
  * const { data: emails } = await client.searchInbox(namespace);
88
160
  * ```
@@ -91,7 +163,17 @@ export class MailiskClient {
91
163
  * Get the latest emails for a specific email address
92
164
  * ```typescript
93
165
  * const { data: emails } = await client.searchInbox(namespace, {
94
- * to_addr_prefix: 'john@mynamespace.mailisk.net'
166
+ * to_addr_prefix: 'john@mynamespace.mailisk.net'
167
+ * });
168
+ * ```
169
+ *
170
+ * @example
171
+ * Get the last 20 emails in the namespace
172
+ * ```typescript
173
+ * const { data: emails } = await mailisk.searchInbox(namespace, {
174
+ * wait: false,
175
+ * from_timestamp: 0,
176
+ * limit: 20
95
177
  * });
96
178
  * ```
97
179
  */
@@ -114,12 +196,12 @@ export class MailiskClient {
114
196
 
115
197
  let _config = { ...config };
116
198
 
117
- if (!config?.maxRedirects) {
199
+ if (config?.maxRedirects === undefined) {
118
200
  _config.maxRedirects = 99999;
119
201
  }
120
202
 
121
203
  // by default, wait 5 minutes for emails before timing out
122
- if (_params.wait && !config?.timeout) {
204
+ if (_params.wait && config?.timeout === undefined) {
123
205
  _config.timeout = 1000 * 60 * 5;
124
206
  }
125
207
 
@@ -1,9 +1,10 @@
1
1
  // Mock namespace response data
2
2
  export const mockNamespacesResponse = {
3
- namespaces: [
3
+ total_count: 1,
4
+ data: [
4
5
  {
5
- name: "test-namespace",
6
- created_at: new Date().toISOString(),
6
+ id: "0fde5afa-a8a8-41a4-9ca4-21d83efc37d8",
7
+ namespace: "test-namespace",
7
8
  expires_at: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
8
9
  },
9
10
  ],
@@ -11,39 +12,97 @@ export const mockNamespacesResponse = {
11
12
 
12
13
  // Mock email response data
13
14
  export const mockEmailsResponse = {
14
- emails: [
15
+ total_count: 1,
16
+ options: {
17
+ wait: true,
18
+ },
19
+ data: [
15
20
  {
16
- id: "email-123",
17
- from: { address: "sender@example.com", name: "Sender" },
18
- to: [{ address: "recipient@test-namespace.mailisk.net", name: "Recipient" }],
19
- subject: "Test Email",
20
- html: "<p>Test content</p>",
21
- text: "Test content",
22
- received_date: new Date().toISOString(),
23
- received_timestamp: Math.floor(Date.now() / 1000),
24
- expires_timestamp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,
21
+ id: "1763808382384-m-m-dEmYI7ic5",
22
+ from: {
23
+ address: "sender@example.com",
24
+ name: "Sender",
25
+ },
26
+ to: [
27
+ {
28
+ address: "recipient@test-namespace.mailisk.net",
29
+ name: "Recipient",
30
+ },
31
+ ],
32
+ subject: "test",
33
+ html: "false",
34
+ text: "test",
35
+ received_date: "2025-11-22T10:46:22.000Z",
36
+ received_timestamp: 1763808382,
37
+ expires_timestamp: 1764672382,
38
+ spam_score: null,
25
39
  },
26
40
  ],
27
- count: 1,
28
41
  };
29
42
 
30
43
  // Mock attachment response data
31
44
  export const mockAttachmentResponse = {
32
- id: "attachment-123",
33
- filename: "test.txt",
34
- content_type: "text/plain",
35
- size: 100,
36
- expires_at: "Fri, 23 Jun 2025 02:29:13 GMT",
37
- download_url: "https://example.com/attachment-123.txt",
45
+ data: {
46
+ id: "b04730be-9c13-4f23-a2b7-a4a9a943cd31",
47
+ filename: "Sample.png",
48
+ content_type: "image/png",
49
+ size: 140551,
50
+ expires_at: "2025-09-09T10:03:33.000Z",
51
+ download_url: "url",
52
+ },
38
53
  };
39
54
 
40
55
  // Mock SMTP settings response
41
56
  export const mockSmtpSettingsResponse = {
42
- host: "smtp.mailisk.com",
43
- port: 25,
44
- secure: false,
45
- auth: {
46
- user: "test-namespace",
47
- pass: "mock-password",
57
+ data: {
58
+ host: "smtp.mailisk.net",
59
+ port: 587,
60
+ username: "test-namespace",
61
+ password: "mock-password",
62
+ },
63
+ };
64
+
65
+ // Mock SMS messages response data
66
+ export const mockSmsMessagesResponse = {
67
+ total_count: 1,
68
+ options: {
69
+ limit: 20,
70
+ offset: 0,
48
71
  },
72
+ data: [
73
+ {
74
+ id: "37a2bc57-c2c7-4c08-a9dc-d143bc17643f",
75
+ sms_phone_number_id: "ba548be2-bff9-4e3f-a54b-e034c415e906",
76
+ body: "test newline \\n\\n test2",
77
+ from_number: "+18777804236",
78
+ to_number: "+19285639871",
79
+ provider_message_id: "SMf72eb72b6281a02e60a0114f38e34e36",
80
+ created_at: "2020-11-24T16:48:22.170Z",
81
+ direction: "inbound",
82
+ },
83
+ ],
84
+ };
85
+
86
+ // Mock SMS numbers response data
87
+ export const mockSmsNumbersResponse = {
88
+ total_count: 2,
89
+ data: [
90
+ {
91
+ id: "13c4551e-a5be-4959-9ea5-82931dcfc74d",
92
+ organisation_id: "c02bdb84-22df-4c18-85ba-2defdd04eccb",
93
+ status: "requested",
94
+ country: "US",
95
+ created_at: "2020-11-22T16:59:25.462Z",
96
+ updated_at: "2020-11-22T16:59:25.462Z",
97
+ },
98
+ {
99
+ id: "6bf073d6-d333-45c9-b009-c77f0cac7657",
100
+ organisation_id: "ddec2c7b-b087-45b6-a81d-b195f25d457f",
101
+ status: "active",
102
+ country: "US",
103
+ phone_number: "+19285639871",
104
+ created_at: "2020-11-22T16:41:40.329Z",
105
+ updated_at: "2020-11-22T16:41:40.329Z",
106
+ },
107
+ ],
49
108
  };
@@ -9,6 +9,8 @@ import {
9
9
  mockEmailsResponse,
10
10
  mockSmtpSettingsResponse,
11
11
  mockAttachmentResponse,
12
+ mockSmsMessagesResponse,
13
+ mockSmsNumbersResponse,
12
14
  } from "../mocks/axios-mocks";
13
15
 
14
16
  const setupMockAxios = () => {
@@ -132,7 +134,7 @@ describe("MailiskClient", () => {
132
134
  describe("downloadAttachment", () => {
133
135
  it("should download and return attachment data", async () => {
134
136
  const getAttachmentSpy = jest.spyOn(MailiskClient.prototype, "getAttachment");
135
- getAttachmentSpy.mockResolvedValueOnce({ data: mockAttachmentResponse });
137
+ getAttachmentSpy.mockResolvedValueOnce(mockAttachmentResponse);
136
138
 
137
139
  const mockBuffer = Buffer.from("test content");
138
140
  (axios.get as jest.Mock).mockResolvedValueOnce({ data: mockBuffer });
@@ -140,11 +142,145 @@ describe("MailiskClient", () => {
140
142
  const client = new MailiskClient({ apiKey: "test-key" });
141
143
  const result = await client.downloadAttachment("attachment-123");
142
144
 
143
- expect(axios.get).toHaveBeenCalledWith(mockAttachmentResponse.download_url, { responseType: "arraybuffer" });
145
+ expect(axios.get).toHaveBeenCalledWith(mockAttachmentResponse.data.download_url, { responseType: "arraybuffer" });
144
146
  expect(result).toEqual(mockBuffer);
145
147
  });
146
148
  });
147
149
 
150
+ describe("searchSmsMessages", () => {
151
+ it("should fetch and return SMS messages with default parameters", async () => {
152
+ const { mockGet } = setupMockAxios();
153
+ mockGet.mockResolvedValueOnce({ data: mockSmsMessagesResponse });
154
+
155
+ const client = new MailiskClient({ apiKey: "test-key" });
156
+ const result = await client.searchSmsMessages("1234567890");
157
+
158
+ expect(mockGet).toHaveBeenCalledWith("api/sms/1234567890/messages", {
159
+ maxRedirects: 99999,
160
+ timeout: 1000 * 60 * 5,
161
+ params: {
162
+ from_date: expect.any(String),
163
+ wait: true,
164
+ },
165
+ });
166
+
167
+ expect(result).toEqual(mockSmsMessagesResponse);
168
+ });
169
+
170
+ it("should use custom parameters if provided", async () => {
171
+ const { mockGet } = setupMockAxios();
172
+ mockGet.mockResolvedValueOnce({ data: mockSmsMessagesResponse });
173
+
174
+ const customParams = {
175
+ limit: 5,
176
+ offset: 2,
177
+ body: "verification",
178
+ from_number: "+18005550123",
179
+ from_date: "2023-01-01T00:00:00.000Z",
180
+ to_date: "2023-02-01T00:00:00.000Z",
181
+ wait: false,
182
+ };
183
+
184
+ const client = new MailiskClient({ apiKey: "test-key" });
185
+ const result = await client.searchSmsMessages("+1234567890", customParams);
186
+
187
+ const expectedParams = { ...customParams };
188
+
189
+ expect(mockGet).toHaveBeenCalledWith("api/sms/+1234567890/messages", {
190
+ maxRedirects: 99999,
191
+ params: expectedParams,
192
+ });
193
+
194
+ expect(result).toEqual(mockSmsMessagesResponse);
195
+ });
196
+
197
+ it("should use custom axios config if provided", async () => {
198
+ const { mockGet } = setupMockAxios();
199
+ mockGet.mockResolvedValueOnce({ data: mockSmsMessagesResponse });
200
+
201
+ const customConfig = {
202
+ timeout: 10000,
203
+ maxRedirects: 5,
204
+ };
205
+
206
+ const client = new MailiskClient({ apiKey: "test-key" });
207
+ const result = await client.searchSmsMessages("+1234567890", undefined, customConfig);
208
+
209
+ expect(mockGet).toHaveBeenCalledWith("api/sms/+1234567890/messages", {
210
+ ...customConfig,
211
+ params: {
212
+ from_date: expect.any(String),
213
+ wait: true,
214
+ },
215
+ });
216
+
217
+ expect(result).toEqual(mockSmsMessagesResponse);
218
+ });
219
+
220
+ it("should handle errors correctly", async () => {
221
+ const { mockGet } = setupMockAxios();
222
+ const error = new Error("Search SMS Error");
223
+ mockGet.mockRejectedValueOnce(error);
224
+
225
+ const client = new MailiskClient({ apiKey: "test-key" });
226
+
227
+ await expect(client.searchSmsMessages("+1234567890")).rejects.toThrow("Search SMS Error");
228
+ });
229
+ });
230
+
231
+ describe("listSmsNumbers", () => {
232
+ it("should fetch and return SMS numbers", async () => {
233
+ const { mockGet } = setupMockAxios();
234
+ mockGet.mockResolvedValueOnce({ data: mockSmsNumbersResponse });
235
+
236
+ const client = new MailiskClient({ apiKey: "test-key" });
237
+ const result = await client.listSmsNumbers();
238
+
239
+ expect(mockGet).toHaveBeenCalledWith("api/sms/numbers");
240
+ expect(result).toEqual(mockSmsNumbersResponse);
241
+ });
242
+
243
+ it("should handle errors correctly", async () => {
244
+ const { mockGet } = setupMockAxios();
245
+ const error = new Error("List SMS Numbers Error");
246
+ mockGet.mockRejectedValueOnce(error);
247
+
248
+ const client = new MailiskClient({ apiKey: "test-key" });
249
+
250
+ await expect(client.listSmsNumbers()).rejects.toThrow("List SMS Numbers Error");
251
+ });
252
+ });
253
+
254
+ describe("sendVirtualSms", () => {
255
+ it("should send an SMS through the API", async () => {
256
+ const { mockPost } = setupMockAxios();
257
+ mockPost.mockResolvedValueOnce({ data: {} });
258
+
259
+ const smsParams = {
260
+ from_number: "15551234567",
261
+ to_number: "15557654321",
262
+ body: "Test message",
263
+ };
264
+
265
+ const client = new MailiskClient({ apiKey: "test-key" });
266
+ await client.sendVirtualSms(smsParams);
267
+
268
+ expect(mockPost).toHaveBeenCalledWith("api/sms/virtual", smsParams);
269
+ });
270
+
271
+ it("should handle errors when sending SMS", async () => {
272
+ const { mockPost } = setupMockAxios();
273
+ const error = new Error("Send SMS Error");
274
+ mockPost.mockRejectedValueOnce(error);
275
+
276
+ const client = new MailiskClient({ apiKey: "test-key" });
277
+
278
+ await expect(
279
+ client.sendVirtualSms({ from_number: "+15551234567", to_number: "+15557654321", body: "Test message" })
280
+ ).rejects.toThrow("Send SMS Error");
281
+ });
282
+ });
283
+
148
284
  describe("searchInbox", () => {
149
285
  it("should fetch and return emails with default parameters", async () => {
150
286
  const { mockGet } = setupMockAxios();