resend 1.1.0 → 2.0.0-canary.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/build/package.json +13 -16
- package/build/src/__snapshots__/resend.spec.js.snap +3 -0
- package/build/src/api-keys/api-keys.d.ts +2 -2
- package/build/src/api-keys/api-keys.spec.js +69 -34
- package/build/src/batch/batch.d.ts +8 -0
- package/build/src/batch/batch.js +36 -0
- package/build/src/batch/batch.spec.d.ts +1 -0
- package/build/src/batch/batch.spec.js +92 -0
- package/build/src/batch/interfaces/create-batch-options.interface.d.ts +14 -0
- package/build/src/batch/interfaces/create-batch-options.interface.js +2 -0
- package/build/src/batch/interfaces/index.d.ts +1 -0
- package/build/src/batch/interfaces/index.js +17 -0
- package/build/src/domains/domains.d.ts +1 -1
- package/build/src/domains/domains.spec.js +46 -30
- package/build/src/domains/interfaces/create-domain-options.interface.d.ts +5 -2
- package/build/src/domains/interfaces/get-domain.interface.d.ts +5 -2
- package/build/src/emails/emails.d.ts +1 -1
- package/build/src/emails/emails.spec.js +15 -9
- package/build/src/emails/interfaces/create-email-options.interface.d.ts +28 -22
- package/build/src/error.d.ts +8 -0
- package/build/src/error.js +23 -0
- package/build/src/guards.d.ts +9 -0
- package/build/src/guards.js +39 -0
- package/build/src/interfaces.d.ts +10 -5
- package/build/src/interfaces.js +6 -1
- package/build/src/resend.d.ts +9 -6
- package/build/src/resend.js +10 -20
- package/build/src/resend.spec.js +33 -0
- package/package.json +13 -16
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resend",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-canary.0",
|
|
4
4
|
"description": "Node.js library for the Resend API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/src/index.d.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=18"
|
|
12
12
|
},
|
|
13
|
-
"packageManager": "yarn@3.6.
|
|
13
|
+
"packageManager": "yarn@3.6.4",
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc -p .",
|
|
16
16
|
"test": "jest",
|
|
@@ -31,23 +31,20 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/resendlabs/resend-node#readme",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@react-email/render": "0.0.
|
|
35
|
-
"type-fest": "3.13.0"
|
|
34
|
+
"@react-email/render": "0.0.8"
|
|
36
35
|
},
|
|
37
36
|
"devDependencies": {
|
|
38
|
-
"@types/jest": "29.5.
|
|
39
|
-
"@types/node": "18.
|
|
40
|
-
"@types/react": "18.2.
|
|
41
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
42
|
-
"@typescript-eslint/parser": "6.
|
|
43
|
-
"eslint": "8.
|
|
44
|
-
"
|
|
45
|
-
"jest": "29.6.2",
|
|
37
|
+
"@types/jest": "29.5.6",
|
|
38
|
+
"@types/node": "18.18.7",
|
|
39
|
+
"@types/react": "18.2.33",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "6.9.0",
|
|
41
|
+
"@typescript-eslint/parser": "6.9.0",
|
|
42
|
+
"eslint": "8.52.0",
|
|
43
|
+
"jest": "29.7.0",
|
|
46
44
|
"jest-fetch-mock": "3.0.3",
|
|
47
|
-
"prettier": "3.0.
|
|
48
|
-
"prettier-2": "npm:prettier@2",
|
|
49
|
-
"supertest": "6.3.3",
|
|
45
|
+
"prettier": "3.0.3",
|
|
50
46
|
"ts-jest": "29.1.1",
|
|
51
|
-
"
|
|
47
|
+
"ts-node": "10.9.1",
|
|
48
|
+
"typescript": "5.2.2"
|
|
52
49
|
}
|
|
53
50
|
}
|
|
@@ -3,7 +3,7 @@ import { CreateApiKeyOptions, CreateApiKeyRequestOptions, CreateApiKeyResponse,
|
|
|
3
3
|
export declare class ApiKeys {
|
|
4
4
|
private readonly resend;
|
|
5
5
|
constructor(resend: Resend);
|
|
6
|
-
create(payload: CreateApiKeyOptions, options?: CreateApiKeyRequestOptions): Promise<CreateApiKeyResponse>;
|
|
7
|
-
list(): Promise<ListApiKeysResponse>;
|
|
6
|
+
create(payload: CreateApiKeyOptions, options?: CreateApiKeyRequestOptions): Promise<import("..").ErrorResponse | CreateApiKeyResponse>;
|
|
7
|
+
list(): Promise<import("..").ErrorResponse | ListApiKeysResponse>;
|
|
8
8
|
remove(id: string): Promise<void>;
|
|
9
9
|
}
|
|
@@ -36,11 +36,14 @@ describe('API Keys', () => {
|
|
|
36
36
|
`);
|
|
37
37
|
}));
|
|
38
38
|
it('throws error when missing name', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
const errorResponse = {
|
|
40
|
+
error: {
|
|
41
|
+
statusCode: 422,
|
|
42
|
+
name: 'missing_required_field',
|
|
43
|
+
message: 'Missing "name" field',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
44
47
|
status: 422,
|
|
45
48
|
headers: {
|
|
46
49
|
'content-type': 'application/json',
|
|
@@ -48,12 +51,14 @@ describe('API Keys', () => {
|
|
|
48
51
|
},
|
|
49
52
|
});
|
|
50
53
|
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
const result = resend.apiKeys.create({ name: '' });
|
|
55
|
+
yield expect(result).resolves.toMatchInlineSnapshot(`
|
|
53
56
|
{
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
"error": {
|
|
58
|
+
"message": "Missing "name" field",
|
|
59
|
+
"name": "missing_required_field",
|
|
60
|
+
"statusCode": 422,
|
|
61
|
+
},
|
|
57
62
|
}
|
|
58
63
|
`);
|
|
59
64
|
}));
|
|
@@ -100,11 +105,14 @@ describe('API Keys', () => {
|
|
|
100
105
|
`);
|
|
101
106
|
}));
|
|
102
107
|
it('throws error with wrong access', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
const errorResponse = {
|
|
109
|
+
error: {
|
|
110
|
+
statusCode: 422,
|
|
111
|
+
name: 'invalid_access',
|
|
112
|
+
message: 'Access must be "full_access" | "sending_access"',
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
108
116
|
status: 422,
|
|
109
117
|
headers: {
|
|
110
118
|
'content-type': 'application/json',
|
|
@@ -115,7 +123,15 @@ describe('API Keys', () => {
|
|
|
115
123
|
yield expect(resend.apiKeys.create({
|
|
116
124
|
name: 'Test',
|
|
117
125
|
permission: 'wrong_access',
|
|
118
|
-
})).resolves.
|
|
126
|
+
})).resolves.toMatchInlineSnapshot(`
|
|
127
|
+
{
|
|
128
|
+
"error": {
|
|
129
|
+
"message": "Access must be "full_access" | "sending_access"",
|
|
130
|
+
"name": "invalid_access",
|
|
131
|
+
"statusCode": 422,
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
`);
|
|
119
135
|
}));
|
|
120
136
|
});
|
|
121
137
|
describe('restricted by domain', () => {
|
|
@@ -143,11 +159,14 @@ describe('API Keys', () => {
|
|
|
143
159
|
`);
|
|
144
160
|
}));
|
|
145
161
|
it('throws error with wrong access', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
162
|
+
const errorResponse = {
|
|
163
|
+
error: {
|
|
164
|
+
name: 'application_error',
|
|
165
|
+
message: 'Something went wrong',
|
|
166
|
+
statusCode: 500,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
151
170
|
status: 500,
|
|
152
171
|
headers: {
|
|
153
172
|
'content-type': 'application/json',
|
|
@@ -159,7 +178,15 @@ describe('API Keys', () => {
|
|
|
159
178
|
name: 'Test',
|
|
160
179
|
permission: 'sending_access',
|
|
161
180
|
domain_id: '1234',
|
|
162
|
-
})).resolves.
|
|
181
|
+
})).resolves.toMatchInlineSnapshot(`
|
|
182
|
+
{
|
|
183
|
+
"error": {
|
|
184
|
+
"message": "Something went wrong",
|
|
185
|
+
"name": "application_error",
|
|
186
|
+
"statusCode": 500,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
`);
|
|
163
190
|
}));
|
|
164
191
|
});
|
|
165
192
|
});
|
|
@@ -217,11 +244,14 @@ describe('API Keys', () => {
|
|
|
217
244
|
yield expect(resend.apiKeys.remove('5262504e-8ed7-4fac-bd16-0d4be94bc9f2')).resolves.toMatchInlineSnapshot('undefined');
|
|
218
245
|
}));
|
|
219
246
|
it('throws error when missing id', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
247
|
+
const errorResponse = {
|
|
248
|
+
error: {
|
|
249
|
+
name: 'application_error',
|
|
250
|
+
message: 'Something went wrong',
|
|
251
|
+
statusCode: 500,
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
225
255
|
status: 500,
|
|
226
256
|
headers: {
|
|
227
257
|
'content-type': 'application/json',
|
|
@@ -229,14 +259,18 @@ describe('API Keys', () => {
|
|
|
229
259
|
},
|
|
230
260
|
});
|
|
231
261
|
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
232
|
-
|
|
262
|
+
const result = resend.apiKeys.remove('');
|
|
263
|
+
yield expect(result).resolves.toMatchInlineSnapshot('undefined');
|
|
233
264
|
}));
|
|
234
265
|
it('throws error when wrong id', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
266
|
+
const errorResponse = {
|
|
267
|
+
error: {
|
|
268
|
+
name: 'not_found',
|
|
269
|
+
message: 'API key not found',
|
|
270
|
+
statusCode: 404,
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
240
274
|
status: 404,
|
|
241
275
|
headers: {
|
|
242
276
|
'content-type': 'application/json',
|
|
@@ -244,7 +278,8 @@ describe('API Keys', () => {
|
|
|
244
278
|
},
|
|
245
279
|
});
|
|
246
280
|
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
247
|
-
|
|
281
|
+
const result = resend.apiKeys.remove('34bd250e-615a-400c-be11-5912572ee15b');
|
|
282
|
+
yield expect(result).resolves.toMatchInlineSnapshot('undefined');
|
|
248
283
|
}));
|
|
249
284
|
});
|
|
250
285
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Resend } from '../resend';
|
|
2
|
+
import { CreateBatchOptions, CreateBatchRequestOptions, CreateBatchResponse } from './interfaces';
|
|
3
|
+
export declare class Batch {
|
|
4
|
+
private readonly resend;
|
|
5
|
+
constructor(resend: Resend);
|
|
6
|
+
send(payload: CreateBatchOptions, options?: CreateBatchRequestOptions): Promise<CreateBatchResponse>;
|
|
7
|
+
create(payload: CreateBatchOptions, options?: CreateBatchRequestOptions): Promise<CreateBatchResponse>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Batch = void 0;
|
|
13
|
+
const render_1 = require("@react-email/render");
|
|
14
|
+
class Batch {
|
|
15
|
+
constructor(resend) {
|
|
16
|
+
this.resend = resend;
|
|
17
|
+
}
|
|
18
|
+
send(payload, options = {}) {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
return this.create(payload, options);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
create(payload, options = {}) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
for (const email of payload) {
|
|
26
|
+
if (email.react) {
|
|
27
|
+
email.html = (0, render_1.render)(email.react);
|
|
28
|
+
delete email.react;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const data = yield this.resend.post('/emails/batch', payload, options);
|
|
32
|
+
return data;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.Batch = Batch;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const jest_fetch_mock_1 = require("jest-fetch-mock");
|
|
13
|
+
const resend_1 = require("../resend");
|
|
14
|
+
(0, jest_fetch_mock_1.enableFetchMocks)();
|
|
15
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
16
|
+
describe('Batch', () => {
|
|
17
|
+
afterEach(() => fetchMock.resetMocks());
|
|
18
|
+
describe('create', () => {
|
|
19
|
+
it('sends multiple emails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
const payload = [
|
|
21
|
+
{
|
|
22
|
+
from: 'bu@resend.com',
|
|
23
|
+
to: 'zeno@resend.com',
|
|
24
|
+
subject: 'Hello World',
|
|
25
|
+
html: '<h1>Hello world</h1>',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
from: 'vitor@resend.com',
|
|
29
|
+
to: 'zeno@resend.com',
|
|
30
|
+
subject: 'Olá mundo',
|
|
31
|
+
html: '<h1>olá mundo</h1>',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
from: 'bu@resend.com',
|
|
35
|
+
to: 'vitor@resend.com',
|
|
36
|
+
subject: 'Hi there',
|
|
37
|
+
html: '<h1>Hi there</h1>',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
fetchMock.mockOnce(JSON.stringify({
|
|
41
|
+
data: [{ id: '1234' }, { id: '4567' }, { id: '4242' }],
|
|
42
|
+
}), {
|
|
43
|
+
status: 200,
|
|
44
|
+
headers: {
|
|
45
|
+
'content-type': 'application/json',
|
|
46
|
+
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
const data = yield resend.batch.create(payload);
|
|
50
|
+
expect(data).toMatchObject({
|
|
51
|
+
data: [{ id: '1234' }, { id: '4567' }, { id: '4242' }],
|
|
52
|
+
});
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
55
|
+
describe('send', () => {
|
|
56
|
+
it('sends multiple emails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
|
+
const payload = [
|
|
58
|
+
{
|
|
59
|
+
from: 'bu@resend.com',
|
|
60
|
+
to: 'zeno@resend.com',
|
|
61
|
+
subject: 'Hello World',
|
|
62
|
+
html: '<h1>Hello world</h1>',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
from: 'vitor@resend.com',
|
|
66
|
+
to: 'zeno@resend.com',
|
|
67
|
+
subject: 'Olá mundo',
|
|
68
|
+
html: '<h1>olá mundo</h1>',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
from: 'bu@resend.com',
|
|
72
|
+
to: 'vitor@resend.com',
|
|
73
|
+
subject: 'Hi there',
|
|
74
|
+
html: '<h1>Hi there</h1>',
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
fetchMock.mockOnce(JSON.stringify({
|
|
78
|
+
data: [{ id: '1234' }, { id: '4567' }, { id: '4242' }],
|
|
79
|
+
}), {
|
|
80
|
+
status: 200,
|
|
81
|
+
headers: {
|
|
82
|
+
'content-type': 'application/json',
|
|
83
|
+
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
const data = yield resend.batch.send(payload);
|
|
87
|
+
expect(data).toMatchObject({
|
|
88
|
+
data: [{ id: '1234' }, { id: '4567' }, { id: '4242' }],
|
|
89
|
+
});
|
|
90
|
+
}));
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PostOptions } from '../../common/interfaces';
|
|
2
|
+
import { CreateEmailOptions } from '../../emails/interfaces/create-email-options.interface';
|
|
3
|
+
import { ErrorResponse } from '../../interfaces';
|
|
4
|
+
export type CreateBatchOptions = CreateEmailOptions[];
|
|
5
|
+
export interface CreateBatchRequestOptions extends PostOptions {
|
|
6
|
+
}
|
|
7
|
+
interface CreateBatchSuccessResponse {
|
|
8
|
+
data: {
|
|
9
|
+
/** The ID of the newly created email. */
|
|
10
|
+
id: string;
|
|
11
|
+
}[];
|
|
12
|
+
}
|
|
13
|
+
export type CreateBatchResponse = CreateBatchSuccessResponse | ErrorResponse;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './create-batch-options.interface';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./create-batch-options.interface"), exports);
|
|
@@ -4,7 +4,7 @@ export declare class Domains {
|
|
|
4
4
|
private readonly resend;
|
|
5
5
|
constructor(resend: Resend);
|
|
6
6
|
create(payload: CreateDomainOptions, options?: CreateDomainRequestOptions): Promise<CreateDomainResponse>;
|
|
7
|
-
list(): Promise<ListDomainsResponse>;
|
|
7
|
+
list(): Promise<import("..").ErrorResponse | ListDomainsResponse>;
|
|
8
8
|
get(id: string): Promise<GetDomainResponse>;
|
|
9
9
|
remove(id: string): Promise<void>;
|
|
10
10
|
verify(id: string): Promise<void>;
|
|
@@ -128,11 +128,14 @@ describe('Domains', () => {
|
|
|
128
128
|
`);
|
|
129
129
|
}));
|
|
130
130
|
it('throws error when missing name', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
131
|
+
const errorResponse = {
|
|
132
|
+
error: {
|
|
133
|
+
statusCode: 422,
|
|
134
|
+
name: 'missing_required_field',
|
|
135
|
+
message: 'Missing "name" field',
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
136
139
|
status: 422,
|
|
137
140
|
headers: {
|
|
138
141
|
'content-type': 'application/json',
|
|
@@ -140,14 +143,16 @@ describe('Domains', () => {
|
|
|
140
143
|
},
|
|
141
144
|
});
|
|
142
145
|
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
const result = resend.domains.create({ name: '' });
|
|
147
|
+
yield expect(result).resolves.toMatchInlineSnapshot(`
|
|
148
|
+
{
|
|
149
|
+
"error": {
|
|
146
150
|
"message": "Missing "name" field",
|
|
147
151
|
"name": "missing_required_field",
|
|
148
152
|
"statusCode": 422,
|
|
149
|
-
}
|
|
150
|
-
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
`);
|
|
151
156
|
}));
|
|
152
157
|
describe('with region', () => {
|
|
153
158
|
it('creates a domain with region', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -256,11 +261,14 @@ describe('Domains', () => {
|
|
|
256
261
|
`);
|
|
257
262
|
}));
|
|
258
263
|
it('throws error with wrong region', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
+
const errorResponse = {
|
|
265
|
+
error: {
|
|
266
|
+
statusCode: 422,
|
|
267
|
+
name: 'invalid_region',
|
|
268
|
+
message: 'Region must be "us-east-1" | "eu-west-1" | "sa-east-1"',
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
264
272
|
status: 422,
|
|
265
273
|
headers: {
|
|
266
274
|
'content-type': 'application/json',
|
|
@@ -268,14 +276,17 @@ describe('Domains', () => {
|
|
|
268
276
|
},
|
|
269
277
|
});
|
|
270
278
|
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
271
|
-
|
|
279
|
+
const result = resend.domains.create({
|
|
272
280
|
name: 'resend.com',
|
|
273
281
|
region: 'remote',
|
|
274
|
-
})
|
|
282
|
+
});
|
|
283
|
+
yield expect(result).resolves.toMatchInlineSnapshot(`
|
|
275
284
|
{
|
|
276
|
-
"
|
|
277
|
-
|
|
278
|
-
|
|
285
|
+
"error": {
|
|
286
|
+
"message": "Region must be "us-east-1" | "eu-west-1" | "sa-east-1"",
|
|
287
|
+
"name": "invalid_region",
|
|
288
|
+
"statusCode": 422,
|
|
289
|
+
},
|
|
279
290
|
}
|
|
280
291
|
`);
|
|
281
292
|
}));
|
|
@@ -333,11 +344,14 @@ describe('Domains', () => {
|
|
|
333
344
|
describe('get', () => {
|
|
334
345
|
describe('when domain not found', () => {
|
|
335
346
|
it('returns error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
347
|
+
const errorResponse = {
|
|
348
|
+
error: {
|
|
349
|
+
name: 'not_found',
|
|
350
|
+
message: 'Domain not found',
|
|
351
|
+
statusCode: 404,
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
341
355
|
status: 404,
|
|
342
356
|
headers: {
|
|
343
357
|
'content-type': 'application/json',
|
|
@@ -345,12 +359,14 @@ describe('Domains', () => {
|
|
|
345
359
|
},
|
|
346
360
|
});
|
|
347
361
|
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
348
|
-
|
|
349
|
-
|
|
362
|
+
const result = resend.domains.get('1234');
|
|
363
|
+
yield expect(result).resolves.toMatchInlineSnapshot(`
|
|
350
364
|
{
|
|
351
|
-
"
|
|
352
|
-
|
|
353
|
-
|
|
365
|
+
"error": {
|
|
366
|
+
"message": "Domain not found",
|
|
367
|
+
"name": "not_found",
|
|
368
|
+
"statusCode": 404,
|
|
369
|
+
},
|
|
354
370
|
}
|
|
355
371
|
`);
|
|
356
372
|
}));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PostOptions } from '../../common/interfaces';
|
|
2
|
+
import { ErrorResponse } from '../../interfaces';
|
|
2
3
|
import { DomainRegion, DomainStatus } from './domain';
|
|
3
4
|
export interface CreateDomainOptions {
|
|
4
5
|
name: string;
|
|
@@ -28,11 +29,13 @@ export interface DomainDkimRecord {
|
|
|
28
29
|
priority?: number;
|
|
29
30
|
proxy_status?: 'enable' | 'disable';
|
|
30
31
|
}
|
|
31
|
-
|
|
32
|
+
interface CreateDomainResponseSuccess {
|
|
32
33
|
name: string;
|
|
33
34
|
id: string;
|
|
34
35
|
status: DomainStatus;
|
|
35
36
|
created_at: string;
|
|
36
37
|
records: (DomainSpfRecord | DomainDkimRecord)[];
|
|
37
38
|
region: DomainRegion;
|
|
38
|
-
}
|
|
39
|
+
}
|
|
40
|
+
export type CreateDomainResponse = CreateDomainResponseSuccess | ErrorResponse;
|
|
41
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { ErrorResponse } from '../../interfaces';
|
|
1
2
|
import { DomainRecords, DomainRegion, DomainStatus } from './domain';
|
|
2
|
-
|
|
3
|
+
interface GetDomainResponseSuccess {
|
|
3
4
|
object: 'domain';
|
|
4
5
|
id: string;
|
|
5
6
|
name: string;
|
|
@@ -7,4 +8,6 @@ export type GetDomainResponse = {
|
|
|
7
8
|
region: DomainRegion;
|
|
8
9
|
status: DomainStatus;
|
|
9
10
|
records: DomainRecords[];
|
|
10
|
-
}
|
|
11
|
+
}
|
|
12
|
+
export type GetDomainResponse = GetDomainResponseSuccess | ErrorResponse;
|
|
13
|
+
export {};
|
|
@@ -5,5 +5,5 @@ export declare class Emails {
|
|
|
5
5
|
constructor(resend: Resend);
|
|
6
6
|
send(payload: CreateEmailOptions, options?: CreateEmailRequestOptions): Promise<CreateEmailResponse>;
|
|
7
7
|
create(payload: CreateEmailOptions, options?: CreateEmailRequestOptions): Promise<CreateEmailResponse>;
|
|
8
|
-
get(id: string): Promise<GetEmailResponse>;
|
|
8
|
+
get(id: string): Promise<import("..").ErrorResponse | GetEmailResponse>;
|
|
9
9
|
}
|
|
@@ -68,22 +68,28 @@ describe('Emails', () => {
|
|
|
68
68
|
describe('get', () => {
|
|
69
69
|
describe('when email not found', () => {
|
|
70
70
|
it('returns error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
const errorResponse = {
|
|
72
|
+
error: {
|
|
73
|
+
name: 'not_found',
|
|
74
|
+
message: 'Email not found',
|
|
75
|
+
statusCode: 404,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
76
79
|
status: 404,
|
|
77
80
|
headers: {
|
|
78
81
|
'content-type': 'application/json',
|
|
79
82
|
Authorization: 'Bearer re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop',
|
|
80
83
|
},
|
|
81
84
|
});
|
|
82
|
-
|
|
85
|
+
const result = resend.emails.get('1234');
|
|
86
|
+
yield expect(result).resolves.toMatchInlineSnapshot(`
|
|
83
87
|
{
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
"error": {
|
|
89
|
+
"message": "Email not found",
|
|
90
|
+
"name": "not_found",
|
|
91
|
+
"statusCode": 404,
|
|
92
|
+
},
|
|
87
93
|
}
|
|
88
94
|
`);
|
|
89
95
|
}));
|
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { PostOptions } from '../../common/interfaces';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { ErrorResponse } from '../../interfaces';
|
|
5
|
+
type RequireAtLeastOne<T> = {
|
|
6
|
+
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>;
|
|
7
|
+
}[keyof T];
|
|
8
|
+
interface EmailRenderOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The React component used to write the message.
|
|
11
|
+
*
|
|
12
|
+
* @link https://resend.com/api-reference/emails/send-email#body-parameters
|
|
13
|
+
*/
|
|
14
|
+
react?: React.ReactElement | React.ReactNode | null;
|
|
15
|
+
/**
|
|
16
|
+
* The HTML version of the message.
|
|
17
|
+
*
|
|
18
|
+
* @link https://resend.com/api-reference/emails/send-email#body-parameters
|
|
19
|
+
*/
|
|
20
|
+
html?: string;
|
|
21
|
+
/**
|
|
22
|
+
* The plain text version of the message.
|
|
23
|
+
*
|
|
24
|
+
* @link https://resend.com/api-reference/emails/send-email#body-parameters
|
|
25
|
+
*/
|
|
26
|
+
text?: string;
|
|
27
|
+
}
|
|
28
|
+
interface CreateEmailBaseOptions extends EmailRenderOptions {
|
|
6
29
|
/**
|
|
7
30
|
* Filename and content of attachments (max 40mb per email)
|
|
8
31
|
*
|
|
@@ -33,24 +56,6 @@ interface CreateEmailBaseOptions {
|
|
|
33
56
|
* @link https://resend.com/docs/api-reference/emails/send-email#body-parameters
|
|
34
57
|
*/
|
|
35
58
|
headers?: Record<string, string>;
|
|
36
|
-
/**
|
|
37
|
-
* The React component used to write the message.
|
|
38
|
-
*
|
|
39
|
-
* @link https://resend.com/docs/api-reference/emails/send-email#body-parameters
|
|
40
|
-
*/
|
|
41
|
-
react?: React.ReactElement | React.ReactNode | null;
|
|
42
|
-
/**
|
|
43
|
-
* The HTML version of the message.
|
|
44
|
-
*
|
|
45
|
-
* @link https://resend.com/docs/api-reference/emails/send-email#body-parameters
|
|
46
|
-
*/
|
|
47
|
-
html?: string;
|
|
48
|
-
/**
|
|
49
|
-
* The plain text version of the message.
|
|
50
|
-
*
|
|
51
|
-
* @link https://resend.com/docs/api-reference/emails/send-email#body-parameters
|
|
52
|
-
*/
|
|
53
|
-
text?: string;
|
|
54
59
|
/**
|
|
55
60
|
* Reply-to email address. For multiple addresses, send as an array of strings.
|
|
56
61
|
*
|
|
@@ -76,13 +81,14 @@ interface CreateEmailBaseOptions {
|
|
|
76
81
|
*/
|
|
77
82
|
to: string | string[];
|
|
78
83
|
}
|
|
79
|
-
export type CreateEmailOptions = RequireAtLeastOne<
|
|
84
|
+
export type CreateEmailOptions = RequireAtLeastOne<EmailRenderOptions> & CreateEmailBaseOptions;
|
|
80
85
|
export interface CreateEmailRequestOptions extends PostOptions {
|
|
81
86
|
}
|
|
82
|
-
|
|
87
|
+
interface CreateEmailSuccessResponse {
|
|
83
88
|
/** The ID of the newly created email. */
|
|
84
89
|
id: string;
|
|
85
90
|
}
|
|
91
|
+
export type CreateEmailResponse = CreateEmailSuccessResponse | ErrorResponse;
|
|
86
92
|
interface Attachment {
|
|
87
93
|
/** Content of an attached file. */
|
|
88
94
|
content?: string | Buffer;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ErrorResponse, RESEND_ERROR_CODE_KEY, RESEND_ERROR_CODE_NUMBER } from './interfaces';
|
|
2
|
+
export declare class ResendError extends Error {
|
|
3
|
+
readonly statusCode: RESEND_ERROR_CODE_NUMBER | number;
|
|
4
|
+
readonly name: RESEND_ERROR_CODE_KEY;
|
|
5
|
+
constructor(message: string, name: RESEND_ERROR_CODE_KEY, statusCode: RESEND_ERROR_CODE_NUMBER | number);
|
|
6
|
+
static fromResponse(response: ErrorResponse): ResendError;
|
|
7
|
+
toString(): string;
|
|
8
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResendError = void 0;
|
|
4
|
+
class ResendError extends Error {
|
|
5
|
+
constructor(message, name, statusCode) {
|
|
6
|
+
super();
|
|
7
|
+
this.message = message;
|
|
8
|
+
this.name = name;
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
}
|
|
11
|
+
static fromResponse(response) {
|
|
12
|
+
const { error } = response;
|
|
13
|
+
return new ResendError(error.message, error.name, error.statusCode);
|
|
14
|
+
}
|
|
15
|
+
toString() {
|
|
16
|
+
return JSON.stringify({
|
|
17
|
+
message: this.message,
|
|
18
|
+
name: this.name,
|
|
19
|
+
statusCode: this.statusCode,
|
|
20
|
+
}, null, 2);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.ResendError = ResendError;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ErrorResponse } from './interfaces';
|
|
2
|
+
export declare const isResendErrorResponse: (response: unknown) => response is ErrorResponse;
|
|
3
|
+
/**
|
|
4
|
+
* Consider whether to use this stricter version of the type guard.
|
|
5
|
+
*
|
|
6
|
+
* Right now, it's not used as there is a risk that an API error will not be
|
|
7
|
+
* caught due to the API being ahead of the current types.
|
|
8
|
+
*/
|
|
9
|
+
export declare const isResendErrorResponseStrict: (response: unknown) => response is ErrorResponse;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isResendErrorResponseStrict = exports.isResendErrorResponse = void 0;
|
|
4
|
+
const interfaces_1 = require("./interfaces");
|
|
5
|
+
const isResendErrorResponse = (response) => {
|
|
6
|
+
if (typeof response !== 'object' || response === null) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const { error } = response;
|
|
10
|
+
if (typeof error !== 'object' || error === null) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const { message, statusCode, name } = error;
|
|
14
|
+
return (typeof message === 'string' &&
|
|
15
|
+
typeof statusCode === 'number' &&
|
|
16
|
+
typeof name === 'string');
|
|
17
|
+
};
|
|
18
|
+
exports.isResendErrorResponse = isResendErrorResponse;
|
|
19
|
+
/**
|
|
20
|
+
* Consider whether to use this stricter version of the type guard.
|
|
21
|
+
*
|
|
22
|
+
* Right now, it's not used as there is a risk that an API error will not be
|
|
23
|
+
* caught due to the API being ahead of the current types.
|
|
24
|
+
*/
|
|
25
|
+
const isResendErrorResponseStrict = (response) => {
|
|
26
|
+
if (typeof response !== 'object' || response === null) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const { error } = response;
|
|
30
|
+
if (typeof error !== 'object' || error === null) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const { message, statusCode, name } = error;
|
|
34
|
+
return (typeof message === 'string' &&
|
|
35
|
+
typeof statusCode === 'number' &&
|
|
36
|
+
typeof name === 'string' &&
|
|
37
|
+
name in interfaces_1.RESEND_ERROR_CODES_BY_KEY);
|
|
38
|
+
};
|
|
39
|
+
exports.isResendErrorResponseStrict = isResendErrorResponseStrict;
|
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
export declare const RESEND_ERROR_CODES_BY_KEY: {
|
|
2
|
-
readonly
|
|
2
|
+
readonly missing_required_field: 422;
|
|
3
|
+
readonly invalid_access: 422;
|
|
4
|
+
readonly invalid_parameter: 422;
|
|
5
|
+
readonly invalid_region: 422;
|
|
3
6
|
readonly rate_limit_exceeded: 429;
|
|
4
7
|
readonly missing_api_key: 401;
|
|
5
8
|
readonly invalid_api_Key: 403;
|
|
6
9
|
readonly invalid_from_address: 403;
|
|
10
|
+
readonly validation_error: 403;
|
|
7
11
|
readonly not_found: 404;
|
|
8
12
|
readonly method_not_allowed: 405;
|
|
13
|
+
readonly application_error: 500;
|
|
9
14
|
readonly internal_server_error: 500;
|
|
10
15
|
};
|
|
11
16
|
type ValueOf<TObj> = TObj[keyof TObj];
|
|
12
17
|
export type RESEND_ERROR_CODE_NUMBER = ValueOf<typeof RESEND_ERROR_CODES_BY_KEY>;
|
|
13
18
|
export type RESEND_ERROR_CODE_KEY = keyof typeof RESEND_ERROR_CODES_BY_KEY;
|
|
14
|
-
interface ErrorResponse {
|
|
19
|
+
export interface ErrorResponse {
|
|
15
20
|
error: {
|
|
16
21
|
message: string;
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
statusCode: RESEND_ERROR_CODE_NUMBER | number;
|
|
23
|
+
name: RESEND_ERROR_CODE_KEY;
|
|
19
24
|
};
|
|
20
25
|
}
|
|
21
|
-
export { ErrorResponse };
|
|
22
26
|
export type Tag = {
|
|
23
27
|
name: string;
|
|
24
28
|
value: string;
|
|
25
29
|
};
|
|
30
|
+
export {};
|
package/build/src/interfaces.js
CHANGED
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RESEND_ERROR_CODES_BY_KEY = void 0;
|
|
4
4
|
exports.RESEND_ERROR_CODES_BY_KEY = {
|
|
5
|
-
|
|
5
|
+
missing_required_field: 422,
|
|
6
|
+
invalid_access: 422,
|
|
7
|
+
invalid_parameter: 422,
|
|
8
|
+
invalid_region: 422,
|
|
6
9
|
rate_limit_exceeded: 429,
|
|
7
10
|
missing_api_key: 401,
|
|
8
11
|
invalid_api_Key: 403,
|
|
9
12
|
invalid_from_address: 403,
|
|
13
|
+
validation_error: 403,
|
|
10
14
|
not_found: 404,
|
|
11
15
|
method_not_allowed: 405,
|
|
16
|
+
application_error: 500,
|
|
12
17
|
internal_server_error: 500,
|
|
13
18
|
};
|
package/build/src/resend.d.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import { GetOptions, PostOptions, PutOptions } from './common/interfaces';
|
|
2
1
|
import { ApiKeys } from './api-keys/api-keys';
|
|
2
|
+
import { Batch } from './batch/batch';
|
|
3
|
+
import { GetOptions, PostOptions, PutOptions } from './common/interfaces';
|
|
3
4
|
import { Domains } from './domains/domains';
|
|
4
5
|
import { Emails } from './emails/emails';
|
|
5
6
|
import { CreateEmailOptions, CreateEmailResponse } from './emails/interfaces';
|
|
7
|
+
import { ErrorResponse } from './interfaces';
|
|
6
8
|
export declare class Resend {
|
|
7
9
|
readonly key?: string | undefined;
|
|
8
10
|
private readonly headers;
|
|
9
11
|
readonly apiKeys: ApiKeys;
|
|
10
12
|
readonly domains: Domains;
|
|
11
13
|
readonly emails: Emails;
|
|
14
|
+
readonly batch: Batch;
|
|
12
15
|
constructor(key?: string | undefined);
|
|
13
|
-
fetchRequest(path: string, options?: {}): Promise<
|
|
14
|
-
post<T>(path: string, entity?: any, options?: PostOptions): Promise<T>;
|
|
15
|
-
get<T>(path: string, options?: GetOptions): Promise<T>;
|
|
16
|
-
put<T>(path: string, entity: any, options?: PutOptions): Promise<T>;
|
|
17
|
-
delete<T>(path: string, query?: any): Promise<T>;
|
|
16
|
+
fetchRequest<T>(path: string, options?: {}): Promise<T | ErrorResponse>;
|
|
17
|
+
post<T>(path: string, entity?: any, options?: PostOptions): Promise<ErrorResponse | T>;
|
|
18
|
+
get<T>(path: string, options?: GetOptions): Promise<ErrorResponse | T>;
|
|
19
|
+
put<T>(path: string, entity: any, options?: PutOptions): Promise<ErrorResponse | T>;
|
|
20
|
+
delete<T>(path: string, query?: any): Promise<ErrorResponse | T>;
|
|
18
21
|
sendEmail(data: CreateEmailOptions): Promise<CreateEmailResponse>;
|
|
19
22
|
}
|
package/build/src/resend.js
CHANGED
|
@@ -10,11 +10,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.Resend = void 0;
|
|
13
|
-
const render_1 = require("@react-email/render");
|
|
14
13
|
const package_json_1 = require("../package.json");
|
|
15
14
|
const api_keys_1 = require("./api-keys/api-keys");
|
|
15
|
+
const batch_1 = require("./batch/batch");
|
|
16
16
|
const domains_1 = require("./domains/domains");
|
|
17
17
|
const emails_1 = require("./emails/emails");
|
|
18
|
+
const guards_1 = require("./guards");
|
|
18
19
|
const baseUrl = process.env.RESEND_BASE_URL || 'https://api.resend.com';
|
|
19
20
|
const userAgent = process.env.RESEND_USER_AGENT || `resend-node:${package_json_1.version}`;
|
|
20
21
|
class Resend {
|
|
@@ -23,6 +24,7 @@ class Resend {
|
|
|
23
24
|
this.apiKeys = new api_keys_1.ApiKeys(this);
|
|
24
25
|
this.domains = new domains_1.Domains(this);
|
|
25
26
|
this.emails = new emails_1.Emails(this);
|
|
27
|
+
this.batch = new batch_1.Batch(this);
|
|
26
28
|
if (!key) {
|
|
27
29
|
this.key = process.env.RESEND_API_KEY;
|
|
28
30
|
if (!this.key) {
|
|
@@ -40,7 +42,12 @@ class Resend {
|
|
|
40
42
|
const response = yield fetch(`${baseUrl}${path}`, options);
|
|
41
43
|
if (!response.ok) {
|
|
42
44
|
const error = yield response.json();
|
|
43
|
-
|
|
45
|
+
if ((0, guards_1.isResendErrorResponse)(error)) {
|
|
46
|
+
return error;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
error,
|
|
50
|
+
};
|
|
44
51
|
}
|
|
45
52
|
return yield response.json();
|
|
46
53
|
});
|
|
@@ -75,24 +82,7 @@ class Resend {
|
|
|
75
82
|
}
|
|
76
83
|
sendEmail(data) {
|
|
77
84
|
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
-
|
|
79
|
-
if (data.react) {
|
|
80
|
-
data.html = (0, render_1.render)(data.react);
|
|
81
|
-
delete data.react;
|
|
82
|
-
}
|
|
83
|
-
const response = yield this.post(path, {
|
|
84
|
-
from: data.from,
|
|
85
|
-
to: data.to,
|
|
86
|
-
bcc: data.bcc,
|
|
87
|
-
cc: data.cc,
|
|
88
|
-
reply_to: data.reply_to,
|
|
89
|
-
subject: data.subject,
|
|
90
|
-
text: data.text,
|
|
91
|
-
html: data.html,
|
|
92
|
-
attachments: data.attachments,
|
|
93
|
-
tags: data.tags,
|
|
94
|
-
});
|
|
95
|
-
return response;
|
|
85
|
+
return this.emails.create(data);
|
|
96
86
|
});
|
|
97
87
|
}
|
|
98
88
|
}
|
package/build/src/resend.spec.js
CHANGED
|
@@ -216,4 +216,37 @@ describe('Resend', () => {
|
|
|
216
216
|
}
|
|
217
217
|
`);
|
|
218
218
|
}));
|
|
219
|
+
it('throws an error when an ErrorResponse is returned', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
220
|
+
const payload = {
|
|
221
|
+
from: 'resend.com',
|
|
222
|
+
to: 'bu@resend.com',
|
|
223
|
+
reply_to: ['foo@resend.com', 'bar@resend.com'],
|
|
224
|
+
subject: 'Hello World',
|
|
225
|
+
text: 'Hello world',
|
|
226
|
+
};
|
|
227
|
+
const errorResponse = {
|
|
228
|
+
error: {
|
|
229
|
+
statusCode: 422,
|
|
230
|
+
name: 'invalid_parameter',
|
|
231
|
+
message: 'Invalid `from` field. The email address needs to follow the `email@example.com` or `Name <email@example.com>` format',
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
fetchMock.mockOnce(JSON.stringify(errorResponse), {
|
|
235
|
+
status: 422,
|
|
236
|
+
headers: {
|
|
237
|
+
'content-type': 'application/json',
|
|
238
|
+
Authorization: 'Bearer re_924b3rjh2387fbewf823',
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
const result = resend.emails.send(payload);
|
|
242
|
+
yield expect(result).resolves.toMatchInlineSnapshot(`
|
|
243
|
+
{
|
|
244
|
+
"error": {
|
|
245
|
+
"message": "Invalid \`from\` field. The email address needs to follow the \`email@example.com\` or \`Name <email@example.com>\` format",
|
|
246
|
+
"name": "invalid_parameter",
|
|
247
|
+
"statusCode": 422,
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
`);
|
|
251
|
+
}));
|
|
219
252
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resend",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-canary.0",
|
|
4
4
|
"description": "Node.js library for the Resend API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/src/index.d.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=18"
|
|
12
12
|
},
|
|
13
|
-
"packageManager": "yarn@3.6.
|
|
13
|
+
"packageManager": "yarn@3.6.4",
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc -p .",
|
|
16
16
|
"test": "jest",
|
|
@@ -31,23 +31,20 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/resendlabs/resend-node#readme",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@react-email/render": "0.0.
|
|
35
|
-
"type-fest": "3.13.0"
|
|
34
|
+
"@react-email/render": "0.0.8"
|
|
36
35
|
},
|
|
37
36
|
"devDependencies": {
|
|
38
|
-
"@types/jest": "29.5.
|
|
39
|
-
"@types/node": "18.
|
|
40
|
-
"@types/react": "18.2.
|
|
41
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
42
|
-
"@typescript-eslint/parser": "6.
|
|
43
|
-
"eslint": "8.
|
|
44
|
-
"
|
|
45
|
-
"jest": "29.6.2",
|
|
37
|
+
"@types/jest": "29.5.6",
|
|
38
|
+
"@types/node": "18.18.7",
|
|
39
|
+
"@types/react": "18.2.33",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "6.9.0",
|
|
41
|
+
"@typescript-eslint/parser": "6.9.0",
|
|
42
|
+
"eslint": "8.52.0",
|
|
43
|
+
"jest": "29.7.0",
|
|
46
44
|
"jest-fetch-mock": "3.0.3",
|
|
47
|
-
"prettier": "3.0.
|
|
48
|
-
"prettier-2": "npm:prettier@2",
|
|
49
|
-
"supertest": "6.3.3",
|
|
45
|
+
"prettier": "3.0.3",
|
|
50
46
|
"ts-jest": "29.1.1",
|
|
51
|
-
"
|
|
47
|
+
"ts-node": "10.9.1",
|
|
48
|
+
"typescript": "5.2.2"
|
|
52
49
|
}
|
|
53
50
|
}
|