@internxt/sdk 1.17.3 → 1.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  import { ApiSecurity, ApiUrl, AppDetails } from '../shared';
2
- import { MailboxResponse, EmailListResponse, EmailResponse, EmailCreatedResponse, SendEmailRequest, DraftEmailRequest, UpdateEmailRequest, ListEmailsQuery, EmailDomainsResponse, SetupMailAccountPayload, SearchFiltersQuery, MailAccountKeysResponse, MailAccountResponse, LookupRecipientKeysResponse, EncryptedKeystore, KeystoreType, RecipientWithPublicKey, HybridEncryptedEmail, EmailPublicParameters, PwdProtectedEmail } from './types';
2
+ import { RequestCanceler } from '../shared/http/client';
3
+ import { MailboxResponse, EmailListResponse, EmailResponse, EmailCreatedResponse, SendEmailRequest, DraftEmailRequest, UpdateEmailRequest, ListEmailsQuery, EmailDomainsResponse, SetupMailAccountPayload, SearchFiltersQuery, MailAccountKeysResponse, MailAccountResponse, LookupRecipientKeysResponse, EncryptedKeystore, KeystoreType, RecipientWithPublicKey, HybridEncryptedEmail, EmailPublicParameters, PwdProtectedEmail, UploadAttachmentResponse, DownloadAttachmentResponse, DownloadAttachmentPayload } from './types';
3
4
  export declare class MailApi {
4
5
  private readonly client;
5
6
  private readonly appDetails;
@@ -133,6 +134,32 @@ export declare class MailApi {
133
134
  * @returns The public, encrypted private and recovery keys plus the salt
134
135
  */
135
136
  getMailAccountKeys(address?: string): Promise<MailAccountKeysResponse>;
137
+ /**
138
+ * Uploading an attachment to the S3 so we can attach it to an email
139
+ * @param file - File to upload
140
+ * @returns
141
+ * - `blobId` - The blob id of the attachment
142
+ * - `name` - The name of the attachment
143
+ * - `type` - The content type of the attachment
144
+ * - `size` - The size of the attachment
145
+ *
146
+ */
147
+ uploadAttachment(file: File): {
148
+ promise: Promise<UploadAttachmentResponse>;
149
+ requestCanceler: RequestCanceler;
150
+ };
151
+ /**
152
+ * Downloads an attachment of the given email as raw bytes, together with the
153
+ * metadata exposed by the response headers (filename, content type and
154
+ * content length). The caller decides how to consume the bytes (write them
155
+ * to disk, wrap them in a `Blob`, etc.).
156
+ *
157
+ * @param id - The id of the email that owns the attachment
158
+ * @param blobId - The blob id of the attachment
159
+ * @param query - Optional `name` and `type` overrides forwarded to the backend
160
+ * @returns The attachment bytes plus filename, content type and length
161
+ */
162
+ downloadAttachment(id: string, blobId: string, query?: DownloadAttachmentPayload): Promise<DownloadAttachmentResponse>;
136
163
  /**
137
164
  * Returns the needed headers for the module requests
138
165
  * @private
@@ -177,6 +177,43 @@ class MailApi {
177
177
  const params = address ? { address } : {};
178
178
  return this.client.getWithParams('/users/me/mail-account/keys', params, this.headers());
179
179
  }
180
+ /**
181
+ * Uploading an attachment to the S3 so we can attach it to an email
182
+ * @param file - File to upload
183
+ * @returns
184
+ * - `blobId` - The blob id of the attachment
185
+ * - `name` - The name of the attachment
186
+ * - `type` - The content type of the attachment
187
+ * - `size` - The size of the attachment
188
+ *
189
+ */
190
+ uploadAttachment(file) {
191
+ const formData = new FormData();
192
+ formData.append('attachments', file, file.name);
193
+ return this.client.postFormCancellable('/email/attachment', formData, this.headers());
194
+ }
195
+ /**
196
+ * Downloads an attachment of the given email as raw bytes, together with the
197
+ * metadata exposed by the response headers (filename, content type and
198
+ * content length). The caller decides how to consume the bytes (write them
199
+ * to disk, wrap them in a `Blob`, etc.).
200
+ *
201
+ * @param id - The id of the email that owns the attachment
202
+ * @param blobId - The blob id of the attachment
203
+ * @param query - Optional `name` and `type` overrides forwarded to the backend
204
+ * @returns The attachment bytes plus filename, content type and length
205
+ */
206
+ async downloadAttachment(id, blobId, query = {}) {
207
+ const { data, headers } = await this.client.getBinary(`/email/${id}/attachment/${blobId}`, query, this.headers());
208
+ const contentLengthHeader = headers['content-length'];
209
+ const contentLength = contentLengthHeader ? Number(contentLengthHeader) : undefined;
210
+ return {
211
+ data,
212
+ contentType: headers['content-type'] ?? 'application/octet-stream',
213
+ contentLength: Number.isFinite(contentLength) ? contentLength : undefined,
214
+ fileName: parseContentDispositionFilename(headers['content-disposition']),
215
+ };
216
+ }
180
217
  /**
181
218
  * Returns the needed headers for the module requests
182
219
  * @private
@@ -192,3 +229,18 @@ class MailApi {
192
229
  }
193
230
  }
194
231
  exports.MailApi = MailApi;
232
+ function parseContentDispositionFilename(header) {
233
+ if (!header)
234
+ return undefined;
235
+ const utf8Match = /filename\*\s*=\s*(?:UTF-8|utf-8)''([^;]+)/i.exec(header);
236
+ if (utf8Match) {
237
+ try {
238
+ return decodeURIComponent(utf8Match[1].trim());
239
+ }
240
+ catch {
241
+ return utf8Match[1].trim();
242
+ }
243
+ }
244
+ const asciiMatch = /filename\s*=\s*"?([^";]+)"?/i.exec(header);
245
+ return asciiMatch ? asciiMatch[1].trim() : undefined;
246
+ }
@@ -187,6 +187,46 @@ export interface paths {
187
187
  patch?: never;
188
188
  trace?: never;
189
189
  };
190
+ '/email/attachment': {
191
+ parameters: {
192
+ query?: never;
193
+ header?: never;
194
+ path?: never;
195
+ cookie?: never;
196
+ };
197
+ get?: never;
198
+ put?: never;
199
+ /**
200
+ * Upload an attachment
201
+ * @description Uploads an attachment and get the info to attach it to an user email.
202
+ */
203
+ post: operations['EmailController_uploadAttachment'];
204
+ delete?: never;
205
+ options?: never;
206
+ head?: never;
207
+ patch?: never;
208
+ trace?: never;
209
+ };
210
+ '/email/{id}/attachment/{blobId}': {
211
+ parameters: {
212
+ query?: never;
213
+ header?: never;
214
+ path?: never;
215
+ cookie?: never;
216
+ };
217
+ /**
218
+ * Download an attachment
219
+ * @description Streams the bytes of an attachment from the given email. Optional `name` and `type` query params set the response filename and content-type.
220
+ */
221
+ get: operations['EmailController_downloadAttachment'];
222
+ put?: never;
223
+ post?: never;
224
+ delete?: never;
225
+ options?: never;
226
+ head?: never;
227
+ patch?: never;
228
+ trace?: never;
229
+ };
190
230
  '/users/me/mail-account': {
191
231
  parameters: {
192
232
  query?: never;
@@ -428,6 +468,19 @@ export interface components {
428
468
  /** @description Filter by attachment presence */
429
469
  hasAttachment?: boolean;
430
470
  };
471
+ EmailAttachmentDto: {
472
+ /** @example T1a2b3c… */
473
+ blobId: string;
474
+ /** @example photo.jpg */
475
+ name: string;
476
+ /** @example image/jpeg */
477
+ type: string;
478
+ /**
479
+ * @description Size in bytes
480
+ * @example 4096
481
+ */
482
+ size: number;
483
+ };
431
484
  EmailResponseDto: {
432
485
  /** @example Ma1f09b… */
433
486
  id: string;
@@ -470,6 +523,7 @@ export interface components {
470
523
  textBody: string | null;
471
524
  /** @example <p>Hi team, here are the notes…</p> */
472
525
  htmlBody: string | null;
526
+ attachments: components['schemas']['EmailAttachmentDto'][];
473
527
  };
474
528
  LookupRecipientKeysRequestDto: {
475
529
  /**
@@ -500,6 +554,19 @@ export interface components {
500
554
  /** @description De-identified wrapped keys, one per recipient */
501
555
  wrappedKeys: components['schemas']['EncryptedWrappedKeyDto'][];
502
556
  };
557
+ AttachmentRefDto: {
558
+ /** @example T1a2b3c… */
559
+ blobId: string;
560
+ /** @example photo.jpg */
561
+ name: string;
562
+ /** @example image/jpeg */
563
+ type: string;
564
+ /**
565
+ * @description Size in bytes
566
+ * @example 4096
567
+ */
568
+ size: number;
569
+ };
503
570
  SendEmailRequestDto: {
504
571
  /** @description Primary recipients (at least one required) */
505
572
  to: components['schemas']['EmailAddressDto'][];
@@ -518,6 +585,8 @@ export interface components {
518
585
  */
519
586
  htmlBody?: string;
520
587
  encryption?: components['schemas']['EncryptionBlockDto'];
588
+ /** @description Attachments to include, referenced by blobId previously obtained from POST /email/attachment */
589
+ attachments?: components['schemas']['AttachmentRefDto'][];
521
590
  };
522
591
  EmailCreatedResponseDto: {
523
592
  /**
@@ -536,6 +605,21 @@ export interface components {
536
605
  textBody?: string;
537
606
  /** @example <p>Still working on this…</p> */
538
607
  htmlBody?: string;
608
+ /** @description Attachments to include, referenced by blobId previously obtained from POST /email/attachment */
609
+ attachments?: components['schemas']['AttachmentRefDto'][];
610
+ };
611
+ UploadAttachmentResponseDto: {
612
+ /** @example T1a2b3c… */
613
+ blobId: string;
614
+ /**
615
+ * @description Size in bytes
616
+ * @example 4096
617
+ */
618
+ size: number;
619
+ /** @example image/jpeg */
620
+ type: string;
621
+ /** @example photo.jpg */
622
+ name: string;
539
623
  };
540
624
  UpdateEmailRequestDto: {
541
625
  /**
@@ -897,6 +981,51 @@ export interface operations {
897
981
  };
898
982
  };
899
983
  };
984
+ EmailController_uploadAttachment: {
985
+ parameters: {
986
+ query?: never;
987
+ header?: never;
988
+ path?: never;
989
+ cookie?: never;
990
+ };
991
+ requestBody?: never;
992
+ responses: {
993
+ /** @description Upload attachment successfully */
994
+ 200: {
995
+ headers: {
996
+ [name: string]: unknown;
997
+ };
998
+ content: {
999
+ 'application/json': components['schemas']['UploadAttachmentResponseDto'];
1000
+ };
1001
+ };
1002
+ };
1003
+ };
1004
+ EmailController_downloadAttachment: {
1005
+ parameters: {
1006
+ query?: {
1007
+ type?: unknown;
1008
+ name?: unknown;
1009
+ };
1010
+ header?: never;
1011
+ path: {
1012
+ /** @description Email ID */
1013
+ id: string;
1014
+ /** @description Attachment blob ID */
1015
+ blobId: string;
1016
+ };
1017
+ cookie?: never;
1018
+ };
1019
+ requestBody?: never;
1020
+ responses: {
1021
+ 200: {
1022
+ headers: {
1023
+ [name: string]: unknown;
1024
+ };
1025
+ content?: never;
1026
+ };
1027
+ };
1028
+ };
900
1029
  UserController_getMailAccount: {
901
1030
  parameters: {
902
1031
  query?: never;
@@ -16,6 +16,15 @@ export type EmailAddress = components['schemas']['EmailAddressDto'];
16
16
  export type ListEmailsQuery = operations['EmailController_list']['parameters']['query'];
17
17
  export type SearchFiltersQuery = operations['EmailController_search']['requestBody']['content']['application/json'];
18
18
  export type EmailDomainsResponse = components['schemas']['MailDomainDto'][];
19
+ export type UploadAttachmentResponse = components['schemas']['UploadAttachmentResponseDto'];
20
+ export type DownloadAttachmentPayload = operations['EmailController_downloadAttachment']['parameters']['query'];
21
+ export type AttachmentRef = components['schemas']['EmailAttachmentDto'];
22
+ export type DownloadAttachmentResponse = {
23
+ data: ArrayBuffer;
24
+ contentType: string;
25
+ contentLength?: number;
26
+ fileName?: string;
27
+ };
19
28
  export type SetupMailAccountPayload = {
20
29
  address: string;
21
30
  domain: string;
@@ -47,6 +47,21 @@ export declare class HttpClient {
47
47
  * @param headers
48
48
  */
49
49
  getWithParams<Response>(url: URL, params: Parameters, headers: Headers): Promise<Response>;
50
+ /**
51
+ * Requests a GET that returns raw binary bytes together with the response
52
+ * headers. Useful for endpoints that stream files where the caller needs
53
+ * `Content-Type`, `Content-Length` or `Content-Disposition`.
54
+ *
55
+ * Bypasses the response interceptor so headers are preserved.
56
+ *
57
+ * @param url
58
+ * @param params
59
+ * @param headers
60
+ */
61
+ getBinary(url: URL, params: Parameters, headers: Headers): Promise<{
62
+ data: ArrayBuffer;
63
+ headers: Record<string, string>;
64
+ }>;
50
65
  /**
51
66
  * Requests a GET with option to cancel
52
67
  * @param url
@@ -77,6 +92,16 @@ export declare class HttpClient {
77
92
  * @param headers
78
93
  */
79
94
  postForm<Response>(url: URL, params: Parameters, headers: Headers): Promise<Response>;
95
+ /**
96
+ * Requests a POST FORM with option to cancel
97
+ * @param url
98
+ * @param params
99
+ * @param headers
100
+ */
101
+ postFormCancellable<Response>(url: URL, params: Parameters, headers: Headers): {
102
+ promise: Promise<Response>;
103
+ requestCanceler: RequestCanceler;
104
+ };
80
105
  /**
81
106
  * Requests a POST with option to cancel
82
107
  * @param url
@@ -72,6 +72,38 @@ class HttpClient {
72
72
  async getWithParams(url, params, headers) {
73
73
  return await this.execute(() => this.axios.get(url, { params, headers }));
74
74
  }
75
+ /**
76
+ * Requests a GET that returns raw binary bytes together with the response
77
+ * headers. Useful for endpoints that stream files where the caller needs
78
+ * `Content-Type`, `Content-Length` or `Content-Disposition`.
79
+ *
80
+ * Bypasses the response interceptor so headers are preserved.
81
+ *
82
+ * @param url
83
+ * @param params
84
+ * @param headers
85
+ */
86
+ async getBinary(url, params, headers) {
87
+ return await this.execute(async () => {
88
+ try {
89
+ const response = await axios_1.default.get(url, {
90
+ baseURL: this.axios.defaults.baseURL,
91
+ params,
92
+ headers,
93
+ responseType: 'arraybuffer',
94
+ transformResponse: (raw) => raw,
95
+ });
96
+ return {
97
+ data: response.data,
98
+ headers: response.headers,
99
+ };
100
+ }
101
+ catch (error) {
102
+ this.normalizeError(error);
103
+ throw error;
104
+ }
105
+ });
106
+ }
75
107
  /**
76
108
  * Requests a GET with option to cancel
77
109
  * @param url
@@ -120,6 +152,22 @@ class HttpClient {
120
152
  async postForm(url, params, headers) {
121
153
  return await this.execute(() => this.axios.postForm(url, params, { headers }));
122
154
  }
155
+ /**
156
+ * Requests a POST FORM with option to cancel
157
+ * @param url
158
+ * @param params
159
+ * @param headers
160
+ */
161
+ postFormCancellable(url, params, headers) {
162
+ let currentCancel = () => { };
163
+ const requestCanceler = { cancel: (message) => currentCancel(message) };
164
+ const promise = this.execute(() => {
165
+ const source = axios_1.default.CancelToken.source();
166
+ currentCancel = source.cancel;
167
+ return this.axios.postForm(url, params, { headers, cancelToken: source.token });
168
+ });
169
+ return { promise, requestCanceler };
170
+ }
123
171
  /**
124
172
  * Requests a POST with option to cancel
125
173
  * @param url
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@internxt/sdk",
3
3
  "author": "Internxt <hello@internxt.com>",
4
- "version": "1.17.3",
4
+ "version": "1.17.4",
5
5
  "description": "An sdk for interacting with Internxt's services",
6
6
  "repository": {
7
7
  "type": "git",