Skip to content

Commit 06dba00

Browse files
lucasfcostagabrielmfern
authored andcommitted
feat: move attachment inbound methods to be nested (#667)
1 parent ed2e3c3 commit 06dba00

File tree

9 files changed

+98
-180
lines changed

9 files changed

+98
-180
lines changed

src/attachments/attachments.ts

Lines changed: 4 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,10 @@
11
import type { Resend } from '../resend';
2-
import type {
3-
GetAttachmentApiResponse,
4-
GetAttachmentOptions,
5-
GetAttachmentResponse,
6-
GetAttachmentResponseSuccess,
7-
} from './interfaces/get-attachment.interface';
8-
import type {
9-
ListAttachmentsApiResponse,
10-
ListAttachmentsOptions,
11-
ListAttachmentsResponse,
12-
} from './interfaces/list-attachments.interface';
2+
import { Receiving } from './receiving/receiving';
133

144
export class Attachments {
15-
constructor(private readonly resend: Resend) {}
5+
readonly receiving: Receiving;
166

17-
async get(options: GetAttachmentOptions): Promise<GetAttachmentResponse> {
18-
const { inboundId, id } = options;
19-
20-
const data = await this.resend.get<GetAttachmentApiResponse>(
21-
`/emails/inbound/${inboundId}/attachments/${id}`,
22-
);
23-
24-
if (data.error) {
25-
return {
26-
data: null,
27-
error: data.error,
28-
};
29-
}
30-
31-
const apiResponse = data.data;
32-
33-
const transformedData: GetAttachmentResponseSuccess = {
34-
object: apiResponse.object,
35-
data: {
36-
id: apiResponse.data.id,
37-
filename: apiResponse.data.filename,
38-
contentType: apiResponse.data.content_type,
39-
contentDisposition: apiResponse.data.content_disposition,
40-
contentId: apiResponse.data.content_id,
41-
content: apiResponse.data.content,
42-
},
43-
};
44-
45-
return {
46-
data: transformedData,
47-
error: null,
48-
};
49-
}
50-
51-
async list(
52-
options: ListAttachmentsOptions,
53-
): Promise<ListAttachmentsResponse> {
54-
const { inboundId } = options;
55-
56-
const data = await this.resend.get<ListAttachmentsApiResponse>(
57-
`/emails/inbound/${inboundId}/attachments`,
58-
);
59-
60-
if (data.error) {
61-
return {
62-
data: null,
63-
error: data.error,
64-
};
65-
}
66-
67-
const apiResponse = data.data;
68-
69-
// Transform snake_case to camelCase and return array directly
70-
const transformedData = apiResponse.data.map((attachment) => ({
71-
id: attachment.id,
72-
filename: attachment.filename,
73-
contentType: attachment.content_type,
74-
contentDisposition: attachment.content_disposition,
75-
contentId: attachment.content_id,
76-
content: attachment.content,
77-
}));
78-
79-
return {
80-
data: transformedData,
81-
error: null,
82-
};
7+
constructor(resend: Resend) {
8+
this.receiving = new Receiving(resend);
839
}
8410
}

src/attachments/interfaces/list-attachments.interface.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export interface InboundAttachment {
22
id: string;
33
filename?: string;
4-
contentType: string;
5-
contentDisposition: 'inline' | 'attachment';
6-
contentId?: string;
4+
content_type: string;
5+
content_disposition: 'inline' | 'attachment';
6+
content_id?: string;
77
content: string; // base64
88
}

src/attachments/interfaces/get-attachment.interface.ts renamed to src/attachments/receiving/interfaces/get-attachment.interface.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import type { ErrorResponse } from '../../interfaces';
1+
import type { ErrorResponse } from '../../../interfaces';
22
import type { InboundAttachment } from './attachment';
33

44
export interface GetAttachmentOptions {
5-
inboundId: string;
5+
emailId: string;
66
id: string;
77
}
88

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { ErrorResponse } from '../../../interfaces';
2+
import type { InboundAttachment } from './attachment';
3+
4+
export interface ListAttachmentsOptions {
5+
emailId: string;
6+
}
7+
8+
export interface ListAttachmentsResponseSuccess {
9+
object: 'attachment';
10+
data: InboundAttachment[];
11+
}
12+
13+
export type ListAttachmentsResponse =
14+
| {
15+
data: ListAttachmentsResponseSuccess;
16+
error: null;
17+
}
18+
| {
19+
data: null;
20+
error: ErrorResponse;
21+
};

src/attachments/attachments.spec.ts renamed to src/attachments/receiving/receiving.spec.ts

Lines changed: 30 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import type { ErrorResponse } from '../interfaces';
2-
import { Resend } from '../resend';
1+
import type { ErrorResponse } from '../../interfaces';
2+
import { Resend } from '../../resend';
33

44
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
55

6-
describe('Attachments', () => {
6+
describe('Receiving', () => {
77
afterEach(() => fetchMock.resetMocks());
88

99
describe('get', () => {
@@ -22,8 +22,8 @@ describe('Attachments', () => {
2222
},
2323
});
2424

25-
const result = await resend.attachments.get({
26-
inboundId: '61cda979-919d-4b9d-9638-c148b93ff410',
25+
const result = await resend.attachments.receiving.get({
26+
emailId: '61cda979-919d-4b9d-9638-c148b93ff410',
2727
id: 'att_123',
2828
});
2929

@@ -61,8 +61,8 @@ describe('Attachments', () => {
6161
},
6262
});
6363

64-
const result = await resend.attachments.get({
65-
inboundId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
64+
const result = await resend.attachments.receiving.get({
65+
emailId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
6666
id: 'att_123',
6767
});
6868

@@ -71,9 +71,9 @@ describe('Attachments', () => {
7171
"data": {
7272
"data": {
7373
"content": "base64encodedcontent==",
74-
"contentDisposition": "attachment",
75-
"contentId": "cid_123",
76-
"contentType": "application/pdf",
74+
"content_disposition": "attachment",
75+
"content_id": "cid_123",
76+
"content_type": "application/pdf",
7777
"filename": "document.pdf",
7878
"id": "att_123",
7979
},
@@ -106,8 +106,8 @@ describe('Attachments', () => {
106106
},
107107
});
108108

109-
const result = await resend.attachments.get({
110-
inboundId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
109+
const result = await resend.attachments.receiving.get({
110+
emailId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
111111
id: 'att_456',
112112
});
113113

@@ -116,9 +116,9 @@ describe('Attachments', () => {
116116
"data": {
117117
"data": {
118118
"content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
119-
"contentDisposition": "inline",
120-
"contentId": "cid_456",
121-
"contentType": "image/png",
119+
"content_disposition": "inline",
120+
"content_id": "cid_456",
121+
"content_type": "image/png",
122122
"filename": "image.png",
123123
"id": "att_456",
124124
},
@@ -150,8 +150,8 @@ describe('Attachments', () => {
150150
},
151151
});
152152

153-
const result = await resend.attachments.get({
154-
inboundId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
153+
const result = await resend.attachments.receiving.get({
154+
emailId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
155155
id: 'att_789',
156156
});
157157

@@ -160,10 +160,8 @@ describe('Attachments', () => {
160160
"data": {
161161
"data": {
162162
"content": "base64content",
163-
"contentDisposition": "attachment",
164-
"contentId": undefined,
165-
"contentType": "text/plain",
166-
"filename": undefined,
163+
"content_disposition": "attachment",
164+
"content_type": "text/plain",
167165
"id": "att_789",
168166
},
169167
"object": "attachment",
@@ -180,7 +178,7 @@ describe('Attachments', () => {
180178
it('returns error', async () => {
181179
const response: ErrorResponse = {
182180
name: 'not_found',
183-
message: 'Inbound email not found',
181+
message: 'Email not found',
184182
};
185183

186184
fetchMock.mockOnce(JSON.stringify(response), {
@@ -191,24 +189,16 @@ describe('Attachments', () => {
191189
},
192190
});
193191

194-
const result = await resend.attachments.list({
195-
inboundId: '61cda979-919d-4b9d-9638-c148b93ff410',
192+
const result = await resend.attachments.receiving.list({
193+
emailId: '61cda979-919d-4b9d-9638-c148b93ff410',
196194
});
197195

198-
expect(result).toMatchInlineSnapshot(`
199-
{
200-
"data": null,
201-
"error": {
202-
"message": "Inbound email not found",
203-
"name": "not_found",
204-
},
205-
}
206-
`);
196+
expect(result).toEqual({ data: null, error: response });
207197
});
208198
});
209199

210200
describe('when attachments found', () => {
211-
it('returns multiple attachments with transformed fields', async () => {
201+
it('returns multiple attachments', async () => {
212202
const apiResponse = {
213203
object: 'attachment' as const,
214204
data: [
@@ -239,33 +229,11 @@ describe('Attachments', () => {
239229
},
240230
});
241231

242-
const result = await resend.attachments.list({
243-
inboundId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
232+
const result = await resend.attachments.receiving.list({
233+
emailId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
244234
});
245235

246-
expect(result).toMatchInlineSnapshot(`
247-
{
248-
"data": [
249-
{
250-
"content": "base64encodedcontent==",
251-
"contentDisposition": "attachment",
252-
"contentId": "cid_123",
253-
"contentType": "application/pdf",
254-
"filename": "document.pdf",
255-
"id": "att_123",
256-
},
257-
{
258-
"content": "imagebase64==",
259-
"contentDisposition": "inline",
260-
"contentId": "cid_456",
261-
"contentType": "image/png",
262-
"filename": "image.png",
263-
"id": "att_456",
264-
},
265-
],
266-
"error": null,
267-
}
268-
`);
236+
expect(result).toEqual({ data: apiResponse, error: null });
269237
});
270238

271239
it('returns empty array when no attachments', async () => {
@@ -282,16 +250,11 @@ describe('Attachments', () => {
282250
},
283251
});
284252

285-
const result = await resend.attachments.list({
286-
inboundId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
253+
const result = await resend.attachments.receiving.list({
254+
emailId: '67d9bcdb-5a02-42d7-8da9-0d6feea18cff',
287255
});
288256

289-
expect(result).toMatchInlineSnapshot(`
290-
{
291-
"data": [],
292-
"error": null,
293-
}
294-
`);
257+
expect(result).toEqual({ data: apiResponse, error: null });
295258
});
296259
});
297260
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { Resend } from '../../resend';
2+
import type {
3+
GetAttachmentOptions,
4+
GetAttachmentResponse,
5+
GetAttachmentResponseSuccess,
6+
} from './interfaces/get-attachment.interface';
7+
import type {
8+
ListAttachmentsOptions,
9+
ListAttachmentsResponse,
10+
ListAttachmentsResponseSuccess,
11+
} from './interfaces/list-attachments.interface';
12+
13+
export class Receiving {
14+
constructor(private readonly resend: Resend) {}
15+
16+
async get(options: GetAttachmentOptions): Promise<GetAttachmentResponse> {
17+
const { emailId, id } = options;
18+
19+
const data = await this.resend.get<GetAttachmentResponseSuccess>(
20+
`/emails/inbound/${emailId}/attachments/${id}`,
21+
);
22+
23+
return data;
24+
}
25+
26+
async list(
27+
options: ListAttachmentsOptions,
28+
): Promise<ListAttachmentsResponse> {
29+
const { emailId } = options;
30+
31+
const data = await this.resend.get<ListAttachmentsResponseSuccess>(
32+
`/emails/inbound/${emailId}/attachments`,
33+
);
34+
35+
return data;
36+
}
37+
}

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export * from './api-keys/interfaces';
2-
export * from './attachments/interfaces';
2+
export * from './attachments/receiving/interfaces';
33
export * from './audiences/interfaces';
44
export * from './batch/interfaces';
55
export * from './broadcasts/interfaces';

0 commit comments

Comments
 (0)