mailisk 2.2.3 → 2.3.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/README.md +97 -0
- package/dist/index.d.mts +199 -1
- package/dist/index.d.ts +199 -1
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +123 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/mailisk.interfaces.ts +109 -0
- package/src/mailisk.ts +144 -2
- package/tests/mocks/axios-mocks.ts +31 -0
- package/tests/unit/mailisk.test.ts +153 -0
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, 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/mailisk.ts"],"sourcesContent":["export * from \"./mailisk\";\nexport * from \"./mailisk.interfaces\";\n","import axios, { AxiosBasicCredentials, AxiosInstance, AxiosRequestConfig } from \"axios\";\nimport {\n CreateBase32SecretKeyTotpDeviceParams,\n CreateCustomTotpDeviceParams,\n CreateOtpAuthUrlTotpDeviceParams,\n CreateTotpDeviceParams,\n GetAttachmentResponse,\n ListNamespacesResponse,\n ListSmsNumbersResponse,\n ListTotpDevicesParams,\n ListTotpDevicesResponse,\n SearchInboxParams,\n SearchInboxResponse,\n SearchSmsMessagesParams,\n SearchSmsMessagesResponse,\n SendVirtualEmailParams,\n SendVirtualSmsParams,\n SmtpSettings,\n TotpDevice,\n TotpOtpResponse,\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 saved TOTP devices.\n *\n * @example\n * List saved TOTP devices for an issuer and username\n * ```typescript\n * const { items: devices } = await client.listTotpDevices({\n * issuer: \"GitHub\",\n * username: \"qa@example.com\",\n * });\n * ```\n */\n async listTotpDevices(params?: ListTotpDevicesParams): Promise<ListTotpDevicesResponse> {\n const requestParams: ListTotpDevicesParams = {\n ...params,\n username: params?.username?.trim(),\n issuer: params?.issuer?.trim(),\n };\n\n return (\n await this.axiosInstance.get(\"api/devices\", {\n params: requestParams,\n })\n ).data;\n }\n\n /**\n * Create a saved TOTP device from a Base32 shared secret using default TOTP settings.\n *\n * @example\n * Create a saved TOTP device from a shared secret\n * ```typescript\n * const device = await client.createTotpDevice({\n * name: \"GitHub staging\",\n * sharedSecret: \"JBSWY3DPEHPK3PXP\",\n * });\n * ```\n */\n async createTotpDevice(params: CreateTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices\", params)).data;\n }\n\n /**\n * Create a saved TOTP device with custom settings.\n *\n * @example\n * Create a saved TOTP device with custom settings\n * ```typescript\n * const device = await client.createCustomTotpDevice({\n * name: \"GitHub staging\",\n * secret: \"JBSWY3DPEHPK3PXP\",\n * username: \"qa@example.com\",\n * issuer: \"GitHub\",\n * digits: 6,\n * period: 30,\n * algorithm: \"SHA1\",\n * });\n * ```\n */\n async createCustomTotpDevice(params: CreateCustomTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices/custom\", params)).data;\n }\n\n /**\n * Create a saved TOTP device from a Base32 secret key.\n *\n * @example\n * Create a saved TOTP device from a Base32 secret key\n * ```typescript\n * const device = await client.createTotpDeviceFromBase32SecretKey({\n * base32SecretKey: \"JBSWY3DPEHPK3PXP\",\n * username: \"qa@example.com\",\n * issuer: \"GitHub\",\n * });\n * ```\n */\n async createTotpDeviceFromBase32SecretKey(params: CreateBase32SecretKeyTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices/base32-secret-key\", params)).data;\n }\n\n /**\n * Create a saved TOTP device from an otpauth://totp URL.\n *\n * @example\n * Create a saved TOTP device from an otpauth URL\n * ```typescript\n * const device = await client.createTotpDeviceFromOtpAuthUrl({\n * otpAuthUrl: \"otpauth://totp/GitHub:qa@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub\",\n * });\n * ```\n */\n async createTotpDeviceFromOtpAuthUrl(params: CreateOtpAuthUrlTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices/otpauth-url\", params)).data;\n }\n\n /**\n * Generate a TOTP code from a shared secret without saving a device.\n *\n * @example\n * Generate a TOTP code from a shared secret\n * ```typescript\n * const { code } = await client.getTotpOtpBySharedSecret(\"JBSWY3DPEHPK3PXP\");\n * ```\n */\n async getTotpOtpBySharedSecret(sharedSecret: string): Promise<TotpOtpResponse> {\n return (await this.axiosInstance.post(\"api/devices/otp\", { sharedSecret })).data;\n }\n\n /**\n * Generate a TOTP code for a saved device.\n *\n * @example\n * Generate a TOTP code for a saved device\n * ```typescript\n * const { code } = await client.getTotpOtpByDeviceId(device.id);\n * ```\n */\n async getTotpOtpByDeviceId(deviceId: string): Promise<TotpOtpResponse> {\n return (await this.axiosInstance.get(`api/devices/${deviceId}/otp`)).data;\n }\n\n /**\n * Delete a saved TOTP device.\n *\n * @example\n * Delete a saved TOTP device\n * ```typescript\n * await client.deleteTotpDevice(device.id);\n * ```\n */\n async deleteTotpDevice(deviceId: string): Promise<void> {\n await this.axiosInstance.delete(`api/devices/${deviceId}`);\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
|
@@ -67,6 +67,129 @@ var MailiskClient = class {
|
|
|
67
67
|
async sendVirtualSms(params) {
|
|
68
68
|
return (await this.axiosInstance.post("api/sms/virtual", params)).data;
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* List saved TOTP devices.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* List saved TOTP devices for an issuer and username
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const { items: devices } = await client.listTotpDevices({
|
|
77
|
+
* issuer: "GitHub",
|
|
78
|
+
* username: "qa@example.com",
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
async listTotpDevices(params) {
|
|
83
|
+
const requestParams = {
|
|
84
|
+
...params,
|
|
85
|
+
username: params?.username?.trim(),
|
|
86
|
+
issuer: params?.issuer?.trim()
|
|
87
|
+
};
|
|
88
|
+
return (await this.axiosInstance.get("api/devices", {
|
|
89
|
+
params: requestParams
|
|
90
|
+
})).data;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create a saved TOTP device from a Base32 shared secret using default TOTP settings.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* Create a saved TOTP device from a shared secret
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const device = await client.createTotpDevice({
|
|
99
|
+
* name: "GitHub staging",
|
|
100
|
+
* sharedSecret: "JBSWY3DPEHPK3PXP",
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
async createTotpDevice(params) {
|
|
105
|
+
return (await this.axiosInstance.post("api/devices", params)).data;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create a saved TOTP device with custom settings.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* Create a saved TOTP device with custom settings
|
|
112
|
+
* ```typescript
|
|
113
|
+
* const device = await client.createCustomTotpDevice({
|
|
114
|
+
* name: "GitHub staging",
|
|
115
|
+
* secret: "JBSWY3DPEHPK3PXP",
|
|
116
|
+
* username: "qa@example.com",
|
|
117
|
+
* issuer: "GitHub",
|
|
118
|
+
* digits: 6,
|
|
119
|
+
* period: 30,
|
|
120
|
+
* algorithm: "SHA1",
|
|
121
|
+
* });
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
async createCustomTotpDevice(params) {
|
|
125
|
+
return (await this.axiosInstance.post("api/devices/custom", params)).data;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create a saved TOTP device from a Base32 secret key.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* Create a saved TOTP device from a Base32 secret key
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const device = await client.createTotpDeviceFromBase32SecretKey({
|
|
134
|
+
* base32SecretKey: "JBSWY3DPEHPK3PXP",
|
|
135
|
+
* username: "qa@example.com",
|
|
136
|
+
* issuer: "GitHub",
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
async createTotpDeviceFromBase32SecretKey(params) {
|
|
141
|
+
return (await this.axiosInstance.post("api/devices/base32-secret-key", params)).data;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create a saved TOTP device from an otpauth://totp URL.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* Create a saved TOTP device from an otpauth URL
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const device = await client.createTotpDeviceFromOtpAuthUrl({
|
|
150
|
+
* otpAuthUrl: "otpauth://totp/GitHub:qa@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub",
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
async createTotpDeviceFromOtpAuthUrl(params) {
|
|
155
|
+
return (await this.axiosInstance.post("api/devices/otpauth-url", params)).data;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Generate a TOTP code from a shared secret without saving a device.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* Generate a TOTP code from a shared secret
|
|
162
|
+
* ```typescript
|
|
163
|
+
* const { code } = await client.getTotpOtpBySharedSecret("JBSWY3DPEHPK3PXP");
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
async getTotpOtpBySharedSecret(sharedSecret) {
|
|
167
|
+
return (await this.axiosInstance.post("api/devices/otp", { sharedSecret })).data;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Generate a TOTP code for a saved device.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* Generate a TOTP code for a saved device
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const { code } = await client.getTotpOtpByDeviceId(device.id);
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
async getTotpOtpByDeviceId(deviceId) {
|
|
179
|
+
return (await this.axiosInstance.get(`api/devices/${deviceId}/otp`)).data;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Delete a saved TOTP device.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* Delete a saved TOTP device
|
|
186
|
+
* ```typescript
|
|
187
|
+
* await client.deleteTotpDevice(device.id);
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
async deleteTotpDevice(deviceId) {
|
|
191
|
+
await this.axiosInstance.delete(`api/devices/${deviceId}`);
|
|
192
|
+
}
|
|
70
193
|
/**
|
|
71
194
|
* List all namespaces that belong to the current account (API key).
|
|
72
195
|
*/
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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":[]}
|
|
1
|
+
{"version":3,"sources":["../src/mailisk.ts"],"sourcesContent":["import axios, { AxiosBasicCredentials, AxiosInstance, AxiosRequestConfig } from \"axios\";\nimport {\n CreateBase32SecretKeyTotpDeviceParams,\n CreateCustomTotpDeviceParams,\n CreateOtpAuthUrlTotpDeviceParams,\n CreateTotpDeviceParams,\n GetAttachmentResponse,\n ListNamespacesResponse,\n ListSmsNumbersResponse,\n ListTotpDevicesParams,\n ListTotpDevicesResponse,\n SearchInboxParams,\n SearchInboxResponse,\n SearchSmsMessagesParams,\n SearchSmsMessagesResponse,\n SendVirtualEmailParams,\n SendVirtualSmsParams,\n SmtpSettings,\n TotpDevice,\n TotpOtpResponse,\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 saved TOTP devices.\n *\n * @example\n * List saved TOTP devices for an issuer and username\n * ```typescript\n * const { items: devices } = await client.listTotpDevices({\n * issuer: \"GitHub\",\n * username: \"qa@example.com\",\n * });\n * ```\n */\n async listTotpDevices(params?: ListTotpDevicesParams): Promise<ListTotpDevicesResponse> {\n const requestParams: ListTotpDevicesParams = {\n ...params,\n username: params?.username?.trim(),\n issuer: params?.issuer?.trim(),\n };\n\n return (\n await this.axiosInstance.get(\"api/devices\", {\n params: requestParams,\n })\n ).data;\n }\n\n /**\n * Create a saved TOTP device from a Base32 shared secret using default TOTP settings.\n *\n * @example\n * Create a saved TOTP device from a shared secret\n * ```typescript\n * const device = await client.createTotpDevice({\n * name: \"GitHub staging\",\n * sharedSecret: \"JBSWY3DPEHPK3PXP\",\n * });\n * ```\n */\n async createTotpDevice(params: CreateTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices\", params)).data;\n }\n\n /**\n * Create a saved TOTP device with custom settings.\n *\n * @example\n * Create a saved TOTP device with custom settings\n * ```typescript\n * const device = await client.createCustomTotpDevice({\n * name: \"GitHub staging\",\n * secret: \"JBSWY3DPEHPK3PXP\",\n * username: \"qa@example.com\",\n * issuer: \"GitHub\",\n * digits: 6,\n * period: 30,\n * algorithm: \"SHA1\",\n * });\n * ```\n */\n async createCustomTotpDevice(params: CreateCustomTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices/custom\", params)).data;\n }\n\n /**\n * Create a saved TOTP device from a Base32 secret key.\n *\n * @example\n * Create a saved TOTP device from a Base32 secret key\n * ```typescript\n * const device = await client.createTotpDeviceFromBase32SecretKey({\n * base32SecretKey: \"JBSWY3DPEHPK3PXP\",\n * username: \"qa@example.com\",\n * issuer: \"GitHub\",\n * });\n * ```\n */\n async createTotpDeviceFromBase32SecretKey(params: CreateBase32SecretKeyTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices/base32-secret-key\", params)).data;\n }\n\n /**\n * Create a saved TOTP device from an otpauth://totp URL.\n *\n * @example\n * Create a saved TOTP device from an otpauth URL\n * ```typescript\n * const device = await client.createTotpDeviceFromOtpAuthUrl({\n * otpAuthUrl: \"otpauth://totp/GitHub:qa@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub\",\n * });\n * ```\n */\n async createTotpDeviceFromOtpAuthUrl(params: CreateOtpAuthUrlTotpDeviceParams): Promise<TotpDevice> {\n return (await this.axiosInstance.post(\"api/devices/otpauth-url\", params)).data;\n }\n\n /**\n * Generate a TOTP code from a shared secret without saving a device.\n *\n * @example\n * Generate a TOTP code from a shared secret\n * ```typescript\n * const { code } = await client.getTotpOtpBySharedSecret(\"JBSWY3DPEHPK3PXP\");\n * ```\n */\n async getTotpOtpBySharedSecret(sharedSecret: string): Promise<TotpOtpResponse> {\n return (await this.axiosInstance.post(\"api/devices/otp\", { sharedSecret })).data;\n }\n\n /**\n * Generate a TOTP code for a saved device.\n *\n * @example\n * Generate a TOTP code for a saved device\n * ```typescript\n * const { code } = await client.getTotpOtpByDeviceId(device.id);\n * ```\n */\n async getTotpOtpByDeviceId(deviceId: string): Promise<TotpOtpResponse> {\n return (await this.axiosInstance.get(`api/devices/${deviceId}/otp`)).data;\n }\n\n /**\n * Delete a saved TOTP device.\n *\n * @example\n * Delete a saved TOTP device\n * ```typescript\n * await client.deleteTotpDevice(device.id);\n * ```\n */\n async deleteTotpDevice(deviceId: string): Promise<void> {\n await this.axiosInstance.delete(`api/devices/${deviceId}`);\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.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Mailisk library for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mailisk",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"typescript": "^4.9.5"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"axios": "^1.
|
|
35
|
+
"axios": "^1.15.2",
|
|
36
36
|
"nodemailer": "^8.0.4"
|
|
37
37
|
}
|
|
38
38
|
}
|
package/src/index.ts
CHANGED
|
@@ -241,3 +241,112 @@ export interface SendVirtualSmsParams {
|
|
|
241
241
|
/** The body of the SMS message */
|
|
242
242
|
body: string;
|
|
243
243
|
}
|
|
244
|
+
|
|
245
|
+
export type TotpAlgorithm = "SHA1" | "SHA256" | "SHA512";
|
|
246
|
+
|
|
247
|
+
export type KnownTotpDeviceSource = "shared_secret" | "custom" | "base32_secret_key" | "otpauth_url";
|
|
248
|
+
|
|
249
|
+
export type TotpDeviceSource = KnownTotpDeviceSource | (string & {});
|
|
250
|
+
|
|
251
|
+
export interface TotpDevice {
|
|
252
|
+
id: string;
|
|
253
|
+
organisation_id: string;
|
|
254
|
+
name: string;
|
|
255
|
+
username?: string | null;
|
|
256
|
+
issuer?: string | null;
|
|
257
|
+
digits: number;
|
|
258
|
+
period: number;
|
|
259
|
+
algorithm: TotpAlgorithm;
|
|
260
|
+
source: TotpDeviceSource;
|
|
261
|
+
expiresAt?: string | null;
|
|
262
|
+
created_at: string;
|
|
263
|
+
updated_at: string;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export interface ListTotpDevicesParams {
|
|
267
|
+
/** The maximum number of saved TOTP devices returned (1-100), used alongside `offset` for pagination. */
|
|
268
|
+
limit?: number;
|
|
269
|
+
/** The number of saved TOTP devices to skip/ignore, used alongside `limit` for pagination. Must be >= 0. */
|
|
270
|
+
offset?: number;
|
|
271
|
+
/** Case-insensitive partial username match. Trimmed before sending. */
|
|
272
|
+
username?: string;
|
|
273
|
+
/** Case-insensitive partial issuer match. Trimmed before sending. */
|
|
274
|
+
issuer?: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export interface ListTotpDevicesResponse {
|
|
278
|
+
total_count: number;
|
|
279
|
+
options: ListTotpDevicesParams;
|
|
280
|
+
items: TotpDevice[];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface CreateTotpDeviceParams {
|
|
284
|
+
/** Base32 shared secret. Uses default TOTP settings. */
|
|
285
|
+
sharedSecret: string;
|
|
286
|
+
/** Optional saved-device display name. Max 120 characters. */
|
|
287
|
+
name?: string;
|
|
288
|
+
/** Future ISO timestamp after which the saved device expires. */
|
|
289
|
+
expiresAt?: string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface CreateCustomTotpDeviceParams {
|
|
293
|
+
/** Base32 shared secret. */
|
|
294
|
+
secret: string;
|
|
295
|
+
/** Optional saved-device display name. Max 120 characters. */
|
|
296
|
+
name?: string;
|
|
297
|
+
/** Account label. Max 240 characters. */
|
|
298
|
+
username?: string;
|
|
299
|
+
/** Issuer/app label. Max 240 characters. */
|
|
300
|
+
issuer?: string;
|
|
301
|
+
/** Number of OTP digits. */
|
|
302
|
+
digits?: 6 | 8;
|
|
303
|
+
/** OTP period in seconds. Must be an integer from 10 to 300. */
|
|
304
|
+
period?: number;
|
|
305
|
+
/** Hashing algorithm. */
|
|
306
|
+
algorithm?: TotpAlgorithm;
|
|
307
|
+
/** Future ISO timestamp after which the saved device expires. */
|
|
308
|
+
expiresAt?: string;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export interface CreateBase32SecretKeyTotpDeviceParams {
|
|
312
|
+
/** Base32 shared secret key. */
|
|
313
|
+
base32SecretKey: string;
|
|
314
|
+
/** Optional saved-device display name. Max 120 characters. */
|
|
315
|
+
name?: string;
|
|
316
|
+
/** Account label. Max 240 characters. */
|
|
317
|
+
username?: string;
|
|
318
|
+
/** Issuer/app label. Max 240 characters. */
|
|
319
|
+
issuer?: string;
|
|
320
|
+
/** Number of OTP digits. */
|
|
321
|
+
digits?: 6 | 8;
|
|
322
|
+
/** OTP period in seconds. Must be an integer from 10 to 300. */
|
|
323
|
+
period?: number;
|
|
324
|
+
/** Hashing algorithm. */
|
|
325
|
+
algorithm?: TotpAlgorithm;
|
|
326
|
+
/** Future ISO timestamp after which the saved device expires. */
|
|
327
|
+
expiresAt?: string;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export interface CreateOtpAuthUrlTotpDeviceParams {
|
|
331
|
+
/** otpauth://totp URL with a secret query parameter. */
|
|
332
|
+
otpAuthUrl: string;
|
|
333
|
+
/** Optional saved-device display name. Max 120 characters. */
|
|
334
|
+
name?: string;
|
|
335
|
+
/** Account label, used when missing from the URL label. Max 240 characters. */
|
|
336
|
+
username?: string;
|
|
337
|
+
/** Issuer/app label, used when missing from the URL. Max 240 characters. */
|
|
338
|
+
issuer?: string;
|
|
339
|
+
/** Number of OTP digits, used when missing from the URL. */
|
|
340
|
+
digits?: 6 | 8;
|
|
341
|
+
/** OTP period in seconds, used when missing from the URL. Must be an integer from 10 to 300. */
|
|
342
|
+
period?: number;
|
|
343
|
+
/** Hashing algorithm, used when missing from the URL. */
|
|
344
|
+
algorithm?: TotpAlgorithm;
|
|
345
|
+
/** Future ISO timestamp after which the saved device expires. */
|
|
346
|
+
expiresAt?: string;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export interface TotpOtpResponse {
|
|
350
|
+
code: string;
|
|
351
|
+
expires: string;
|
|
352
|
+
}
|
package/src/mailisk.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import axios, { AxiosBasicCredentials, AxiosInstance, AxiosRequestConfig } from "axios";
|
|
2
2
|
import {
|
|
3
|
+
CreateBase32SecretKeyTotpDeviceParams,
|
|
4
|
+
CreateCustomTotpDeviceParams,
|
|
5
|
+
CreateOtpAuthUrlTotpDeviceParams,
|
|
6
|
+
CreateTotpDeviceParams,
|
|
3
7
|
GetAttachmentResponse,
|
|
4
8
|
ListNamespacesResponse,
|
|
5
9
|
ListSmsNumbersResponse,
|
|
10
|
+
ListTotpDevicesParams,
|
|
11
|
+
ListTotpDevicesResponse,
|
|
6
12
|
SearchInboxParams,
|
|
7
13
|
SearchInboxResponse,
|
|
8
14
|
SearchSmsMessagesParams,
|
|
@@ -10,6 +16,8 @@ import {
|
|
|
10
16
|
SendVirtualEmailParams,
|
|
11
17
|
SendVirtualSmsParams,
|
|
12
18
|
SmtpSettings,
|
|
19
|
+
TotpDevice,
|
|
20
|
+
TotpOtpResponse,
|
|
13
21
|
} from "./mailisk.interfaces";
|
|
14
22
|
import nodemailer from "nodemailer";
|
|
15
23
|
|
|
@@ -38,7 +46,7 @@ export class MailiskClient {
|
|
|
38
46
|
async searchSmsMessages(
|
|
39
47
|
phoneNumber: string,
|
|
40
48
|
params?: SearchSmsMessagesParams,
|
|
41
|
-
config?: AxiosRequestConfig
|
|
49
|
+
config?: AxiosRequestConfig,
|
|
42
50
|
): Promise<SearchSmsMessagesResponse> {
|
|
43
51
|
let _params: SearchSmsMessagesParams = { ...params };
|
|
44
52
|
|
|
@@ -94,6 +102,140 @@ export class MailiskClient {
|
|
|
94
102
|
return (await this.axiosInstance.post("api/sms/virtual", params)).data;
|
|
95
103
|
}
|
|
96
104
|
|
|
105
|
+
/**
|
|
106
|
+
* List saved TOTP devices.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* List saved TOTP devices for an issuer and username
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const { items: devices } = await client.listTotpDevices({
|
|
112
|
+
* issuer: "GitHub",
|
|
113
|
+
* username: "qa@example.com",
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
async listTotpDevices(params?: ListTotpDevicesParams): Promise<ListTotpDevicesResponse> {
|
|
118
|
+
const requestParams: ListTotpDevicesParams = {
|
|
119
|
+
...params,
|
|
120
|
+
username: params?.username?.trim(),
|
|
121
|
+
issuer: params?.issuer?.trim(),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
await this.axiosInstance.get("api/devices", {
|
|
126
|
+
params: requestParams,
|
|
127
|
+
})
|
|
128
|
+
).data;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Create a saved TOTP device from a Base32 shared secret using default TOTP settings.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* Create a saved TOTP device from a shared secret
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const device = await client.createTotpDevice({
|
|
138
|
+
* name: "GitHub staging",
|
|
139
|
+
* sharedSecret: "JBSWY3DPEHPK3PXP",
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
async createTotpDevice(params: CreateTotpDeviceParams): Promise<TotpDevice> {
|
|
144
|
+
return (await this.axiosInstance.post("api/devices", params)).data;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Create a saved TOTP device with custom settings.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* Create a saved TOTP device with custom settings
|
|
152
|
+
* ```typescript
|
|
153
|
+
* const device = await client.createCustomTotpDevice({
|
|
154
|
+
* name: "GitHub staging",
|
|
155
|
+
* secret: "JBSWY3DPEHPK3PXP",
|
|
156
|
+
* username: "qa@example.com",
|
|
157
|
+
* issuer: "GitHub",
|
|
158
|
+
* digits: 6,
|
|
159
|
+
* period: 30,
|
|
160
|
+
* algorithm: "SHA1",
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
async createCustomTotpDevice(params: CreateCustomTotpDeviceParams): Promise<TotpDevice> {
|
|
165
|
+
return (await this.axiosInstance.post("api/devices/custom", params)).data;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Create a saved TOTP device from a Base32 secret key.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* Create a saved TOTP device from a Base32 secret key
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const device = await client.createTotpDeviceFromBase32SecretKey({
|
|
175
|
+
* base32SecretKey: "JBSWY3DPEHPK3PXP",
|
|
176
|
+
* username: "qa@example.com",
|
|
177
|
+
* issuer: "GitHub",
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
async createTotpDeviceFromBase32SecretKey(params: CreateBase32SecretKeyTotpDeviceParams): Promise<TotpDevice> {
|
|
182
|
+
return (await this.axiosInstance.post("api/devices/base32-secret-key", params)).data;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Create a saved TOTP device from an otpauth://totp URL.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* Create a saved TOTP device from an otpauth URL
|
|
190
|
+
* ```typescript
|
|
191
|
+
* const device = await client.createTotpDeviceFromOtpAuthUrl({
|
|
192
|
+
* otpAuthUrl: "otpauth://totp/GitHub:qa@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub",
|
|
193
|
+
* });
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
async createTotpDeviceFromOtpAuthUrl(params: CreateOtpAuthUrlTotpDeviceParams): Promise<TotpDevice> {
|
|
197
|
+
return (await this.axiosInstance.post("api/devices/otpauth-url", params)).data;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Generate a TOTP code from a shared secret without saving a device.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* Generate a TOTP code from a shared secret
|
|
205
|
+
* ```typescript
|
|
206
|
+
* const { code } = await client.getTotpOtpBySharedSecret("JBSWY3DPEHPK3PXP");
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
async getTotpOtpBySharedSecret(sharedSecret: string): Promise<TotpOtpResponse> {
|
|
210
|
+
return (await this.axiosInstance.post("api/devices/otp", { sharedSecret })).data;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Generate a TOTP code for a saved device.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* Generate a TOTP code for a saved device
|
|
218
|
+
* ```typescript
|
|
219
|
+
* const { code } = await client.getTotpOtpByDeviceId(device.id);
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
async getTotpOtpByDeviceId(deviceId: string): Promise<TotpOtpResponse> {
|
|
223
|
+
return (await this.axiosInstance.get(`api/devices/${deviceId}/otp`)).data;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Delete a saved TOTP device.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* Delete a saved TOTP device
|
|
231
|
+
* ```typescript
|
|
232
|
+
* await client.deleteTotpDevice(device.id);
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
async deleteTotpDevice(deviceId: string): Promise<void> {
|
|
236
|
+
await this.axiosInstance.delete(`api/devices/${deviceId}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
97
239
|
/**
|
|
98
240
|
* List all namespaces that belong to the current account (API key).
|
|
99
241
|
*/
|
|
@@ -180,7 +322,7 @@ export class MailiskClient {
|
|
|
180
322
|
async searchInbox(
|
|
181
323
|
namespace: string,
|
|
182
324
|
params?: SearchInboxParams,
|
|
183
|
-
config?: AxiosRequestConfig
|
|
325
|
+
config?: AxiosRequestConfig,
|
|
184
326
|
): Promise<SearchInboxResponse> {
|
|
185
327
|
let _params = { ...params };
|
|
186
328
|
|
|
@@ -106,3 +106,34 @@ export const mockSmsNumbersResponse = {
|
|
|
106
106
|
},
|
|
107
107
|
],
|
|
108
108
|
};
|
|
109
|
+
|
|
110
|
+
export const mockTotpDevice = {
|
|
111
|
+
id: "9b1f6ec0-b90d-4bd8-8dd0-f6b2d5138273",
|
|
112
|
+
organisation_id: "7f0a9c32-66b2-4e25-a4cf-1f77db8f7f3b",
|
|
113
|
+
name: "GitHub staging",
|
|
114
|
+
username: "qa@example.com",
|
|
115
|
+
issuer: "GitHub",
|
|
116
|
+
digits: 6,
|
|
117
|
+
period: 30,
|
|
118
|
+
algorithm: "SHA1",
|
|
119
|
+
source: "custom",
|
|
120
|
+
expiresAt: null,
|
|
121
|
+
created_at: "2026-05-18T12:00:00.000Z",
|
|
122
|
+
updated_at: "2026-05-18T12:00:00.000Z",
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const mockTotpDevicesResponse = {
|
|
126
|
+
total_count: 1,
|
|
127
|
+
options: {
|
|
128
|
+
limit: 20,
|
|
129
|
+
offset: 0,
|
|
130
|
+
issuer: "GitHub",
|
|
131
|
+
username: "qa@example.com",
|
|
132
|
+
},
|
|
133
|
+
items: [mockTotpDevice],
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const mockTotpOtpResponse = {
|
|
137
|
+
code: "123456",
|
|
138
|
+
expires: "2026-05-18T12:00:30.000Z",
|
|
139
|
+
};
|