resend 0.12.1 → 0.13.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 +7 -7
- package/build/src/api-keys/api-keys.js +2 -2
- package/build/src/api-keys/api-keys.spec.js +194 -1
- package/build/src/api-keys/interfaces/create-api-key-options.interface.d.ts +2 -0
- package/build/src/domains/domains.d.ts +1 -0
- package/build/src/domains/domains.js +7 -1
- package/build/src/domains/domains.spec.d.ts +1 -0
- package/build/src/domains/domains.spec.js +340 -0
- package/build/src/domains/interfaces/create-domain-options.interface.d.ts +6 -7
- package/build/src/resend.d.ts +1 -1
- package/build/src/resend.js +5 -6
- package/build/src/resend.spec.js +55 -5
- package/package.json +7 -7
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.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",
|
|
@@ -27,19 +27,19 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/resend-inc/resend-node#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@react-email/render": "0.0.
|
|
31
|
-
"axios": "1.3.
|
|
30
|
+
"@react-email/render": "0.0.7",
|
|
31
|
+
"axios": "1.3.5"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/jest": "29.5.0",
|
|
35
35
|
"@types/node": "18.15.6",
|
|
36
|
-
"@types/react": "18.0.
|
|
37
|
-
"axios-mock-adapter": "1.21.
|
|
36
|
+
"@types/react": "18.0.32",
|
|
37
|
+
"axios-mock-adapter": "1.21.4",
|
|
38
38
|
"jest": "29.5.0",
|
|
39
39
|
"prettier": "2.8.7",
|
|
40
40
|
"supertest": "6.3.3",
|
|
41
|
-
"ts-jest": "29.0
|
|
41
|
+
"ts-jest": "29.1.0",
|
|
42
42
|
"tslint": "6.1.3",
|
|
43
|
-
"typescript": "5.0.
|
|
43
|
+
"typescript": "5.0.4"
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -16,8 +16,8 @@ class ApiKeys {
|
|
|
16
16
|
}
|
|
17
17
|
create(payload, options = {}) {
|
|
18
18
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
-
const
|
|
20
|
-
return
|
|
19
|
+
const data = yield this.resend.post('/api-keys', payload, options);
|
|
20
|
+
return data;
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
list() {
|
|
@@ -17,10 +17,13 @@ const axios_mock_adapter_1 = __importDefault(require("axios-mock-adapter"));
|
|
|
17
17
|
const resend_1 = require("../resend");
|
|
18
18
|
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
19
19
|
describe('API Keys', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
mock.resetHistory();
|
|
22
|
+
});
|
|
20
23
|
describe('create', () => {
|
|
21
24
|
it('creates an api key', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
25
|
mock.onPost('/api-keys', { name: 'Test' }).replyOnce(201, {
|
|
23
|
-
|
|
26
|
+
token: 're_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk',
|
|
24
27
|
});
|
|
25
28
|
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
26
29
|
yield expect(resend.apiKeys.create({ name: 'Test' })).resolves
|
|
@@ -31,5 +34,195 @@ describe('API Keys', () => {
|
|
|
31
34
|
`);
|
|
32
35
|
expect(mock.history.post.length).toBe(1);
|
|
33
36
|
}));
|
|
37
|
+
it('throws error when missing name', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
38
|
+
mock.onPost('/api-keys').replyOnce(422, {
|
|
39
|
+
statusCode: 422,
|
|
40
|
+
name: 'missing_required_field',
|
|
41
|
+
message: 'Missing "name" field',
|
|
42
|
+
});
|
|
43
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
44
|
+
yield expect(resend.apiKeys.create({ name: '' })).rejects
|
|
45
|
+
.toMatchInlineSnapshot(`
|
|
46
|
+
{
|
|
47
|
+
"message": "Missing "name" field",
|
|
48
|
+
"name": "missing_required_field",
|
|
49
|
+
"statusCode": 422,
|
|
50
|
+
}
|
|
51
|
+
`);
|
|
52
|
+
expect(mock.history.post.length).toBe(1);
|
|
53
|
+
}));
|
|
54
|
+
describe('with access', () => {
|
|
55
|
+
it('creates api key with access `full_access`', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
|
+
mock
|
|
57
|
+
.onPost('/api-keys', { name: 'Test', permission: 'full_access' })
|
|
58
|
+
.replyOnce(201, {
|
|
59
|
+
token: 're_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk',
|
|
60
|
+
});
|
|
61
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
62
|
+
yield expect(resend.apiKeys.create({ name: 'Test', permission: 'full_access' })).resolves.toMatchInlineSnapshot(`
|
|
63
|
+
{
|
|
64
|
+
"token": "re_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk",
|
|
65
|
+
}
|
|
66
|
+
`);
|
|
67
|
+
expect(mock.history.post.length).toBe(1);
|
|
68
|
+
}));
|
|
69
|
+
it('creates api key with access `sending_access`', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
|
+
mock
|
|
71
|
+
.onPost('/api-keys', {
|
|
72
|
+
name: 'Test',
|
|
73
|
+
permission: 'sending_access',
|
|
74
|
+
})
|
|
75
|
+
.replyOnce(201, {
|
|
76
|
+
token: 're_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk',
|
|
77
|
+
});
|
|
78
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
79
|
+
yield expect(resend.apiKeys.create({
|
|
80
|
+
name: 'Test',
|
|
81
|
+
permission: 'sending_access',
|
|
82
|
+
})).resolves.toMatchInlineSnapshot(`
|
|
83
|
+
{
|
|
84
|
+
"token": "re_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk",
|
|
85
|
+
}
|
|
86
|
+
`);
|
|
87
|
+
expect(mock.history.post.length).toBe(1);
|
|
88
|
+
}));
|
|
89
|
+
it('throws error with wrong access', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
|
+
mock
|
|
91
|
+
.onPost('/api-keys', { name: 'Test', permission: 'wrong_access' })
|
|
92
|
+
.replyOnce(422, {
|
|
93
|
+
statusCode: 422,
|
|
94
|
+
name: 'invalid_access',
|
|
95
|
+
message: 'Access must be "full_access" | "sending_access"',
|
|
96
|
+
});
|
|
97
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
98
|
+
yield expect(resend.apiKeys.create({
|
|
99
|
+
name: 'Test',
|
|
100
|
+
permission: 'wrong_access',
|
|
101
|
+
})).rejects.toThrowErrorMatchingInlineSnapshot(`"Access must be "full_access" | "sending_access""`);
|
|
102
|
+
expect(mock.history.post.length).toBe(1);
|
|
103
|
+
}));
|
|
104
|
+
});
|
|
105
|
+
describe('restricted by domain', () => {
|
|
106
|
+
it('creates api key restricted by domain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
107
|
+
mock
|
|
108
|
+
.onPost('/api-keys', {
|
|
109
|
+
name: 'Test',
|
|
110
|
+
permission: 'sending_access',
|
|
111
|
+
domain_id: '7dfcf219-9900-4169-86f3-801e6d9b935e',
|
|
112
|
+
})
|
|
113
|
+
.replyOnce(201, {
|
|
114
|
+
token: 're_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk',
|
|
115
|
+
});
|
|
116
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
117
|
+
yield expect(resend.apiKeys.create({
|
|
118
|
+
name: 'Test',
|
|
119
|
+
permission: 'sending_access',
|
|
120
|
+
domain_id: '7dfcf219-9900-4169-86f3-801e6d9b935e',
|
|
121
|
+
})).resolves.toMatchInlineSnapshot(`
|
|
122
|
+
{
|
|
123
|
+
"token": "re_PKr4RCko_Lhm9ost2YjNCctnPjbLw8Nqk",
|
|
124
|
+
}
|
|
125
|
+
`);
|
|
126
|
+
expect(mock.history.post.length).toBe(1);
|
|
127
|
+
}));
|
|
128
|
+
it('throws error with wrong access', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
129
|
+
mock
|
|
130
|
+
.onPost('/api-keys', {
|
|
131
|
+
name: 'Test',
|
|
132
|
+
permission: 'sending_access',
|
|
133
|
+
domain_id: '1234',
|
|
134
|
+
})
|
|
135
|
+
.replyOnce(500, {
|
|
136
|
+
name: 'application_error',
|
|
137
|
+
message: 'Something went wrong',
|
|
138
|
+
statusCode: 500,
|
|
139
|
+
});
|
|
140
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
141
|
+
yield expect(resend.apiKeys.create({
|
|
142
|
+
name: 'Test',
|
|
143
|
+
permission: 'sending_access',
|
|
144
|
+
domain_id: '1234',
|
|
145
|
+
})).rejects.toThrowErrorMatchingInlineSnapshot(`"Something went wrong"`);
|
|
146
|
+
expect(mock.history.post.length).toBe(1);
|
|
147
|
+
}));
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
describe('list', () => {
|
|
151
|
+
it('lists api keys', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
152
|
+
mock.onGet('/api-keys').replyOnce(200, {
|
|
153
|
+
data: [
|
|
154
|
+
{
|
|
155
|
+
id: '5262504e-8ed7-4fac-bd16-0d4be94bc9f2',
|
|
156
|
+
name: 'My API Key 1',
|
|
157
|
+
created_at: '2023-04-07T20:29:10.666968+00:00',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: '98c37b35-1473-4afe-a627-78e975a36fab',
|
|
161
|
+
name: 'My API Key 2',
|
|
162
|
+
created_at: '2023-04-06T23:09:49.093947+00:00',
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
});
|
|
166
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
167
|
+
yield expect(resend.apiKeys.list()).resolves.toMatchInlineSnapshot(`
|
|
168
|
+
[
|
|
169
|
+
{
|
|
170
|
+
"created_at": "2023-04-07T20:29:10.666968+00:00",
|
|
171
|
+
"id": "5262504e-8ed7-4fac-bd16-0d4be94bc9f2",
|
|
172
|
+
"name": "My API Key 1",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"created_at": "2023-04-06T23:09:49.093947+00:00",
|
|
176
|
+
"id": "98c37b35-1473-4afe-a627-78e975a36fab",
|
|
177
|
+
"name": "My API Key 2",
|
|
178
|
+
},
|
|
179
|
+
]
|
|
180
|
+
`);
|
|
181
|
+
expect(mock.history.get.length).toBe(1);
|
|
182
|
+
}));
|
|
183
|
+
});
|
|
184
|
+
describe('remove', () => {
|
|
185
|
+
it('removes an api key', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
186
|
+
mock
|
|
187
|
+
.onDelete('/api-keys/5262504e-8ed7-4fac-bd16-0d4be94bc9f2')
|
|
188
|
+
.replyOnce(200);
|
|
189
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
190
|
+
yield expect(resend.apiKeys.remove('5262504e-8ed7-4fac-bd16-0d4be94bc9f2')).resolves.toMatchInlineSnapshot(`undefined`);
|
|
191
|
+
expect(mock.history.delete.length).toBe(1);
|
|
192
|
+
}));
|
|
193
|
+
it('throws error when missing id', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
194
|
+
mock.onDelete('/api-keys/').replyOnce(500, {
|
|
195
|
+
name: 'application_error',
|
|
196
|
+
message: 'Something went wrong',
|
|
197
|
+
statusCode: 500,
|
|
198
|
+
});
|
|
199
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
200
|
+
yield expect(resend.apiKeys.remove('')).rejects.toMatchInlineSnapshot(`
|
|
201
|
+
{
|
|
202
|
+
"message": "Something went wrong",
|
|
203
|
+
"name": "application_error",
|
|
204
|
+
"statusCode": 500,
|
|
205
|
+
}
|
|
206
|
+
`);
|
|
207
|
+
expect(mock.history.delete.length).toBe(1);
|
|
208
|
+
}));
|
|
209
|
+
it('throws error when wrong id', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
210
|
+
mock
|
|
211
|
+
.onDelete('/api-keys/34bd250e-615a-400c-be11-5912572ee15b')
|
|
212
|
+
.replyOnce(500, {
|
|
213
|
+
name: 'not_found',
|
|
214
|
+
message: 'API key not found',
|
|
215
|
+
statusCode: 404,
|
|
216
|
+
});
|
|
217
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
218
|
+
yield expect(resend.apiKeys.remove('34bd250e-615a-400c-be11-5912572ee15b')).rejects.toMatchInlineSnapshot(`
|
|
219
|
+
{
|
|
220
|
+
"message": "API key not found",
|
|
221
|
+
"name": "not_found",
|
|
222
|
+
"statusCode": 404,
|
|
223
|
+
}
|
|
224
|
+
`);
|
|
225
|
+
expect(mock.history.delete.length).toBe(1);
|
|
226
|
+
}));
|
|
34
227
|
});
|
|
35
228
|
});
|
|
@@ -4,6 +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<void>;
|
|
7
8
|
remove(id: string): Promise<void>;
|
|
8
9
|
verify(id: string): Promise<void>;
|
|
9
10
|
}
|
|
@@ -16,7 +16,13 @@ class Domains {
|
|
|
16
16
|
}
|
|
17
17
|
create(payload, options = {}) {
|
|
18
18
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
-
const
|
|
19
|
+
const data = yield this.resend.post('/domains', payload, options);
|
|
20
|
+
return data;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
list() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const { data } = yield this.resend.get('/domains');
|
|
20
26
|
return data;
|
|
21
27
|
});
|
|
22
28
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,340 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const axios_1 = __importDefault(require("axios"));
|
|
16
|
+
const axios_mock_adapter_1 = __importDefault(require("axios-mock-adapter"));
|
|
17
|
+
const resend_1 = require("../resend");
|
|
18
|
+
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
19
|
+
describe('Domains', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
mock.resetHistory();
|
|
22
|
+
});
|
|
23
|
+
describe('create', () => {
|
|
24
|
+
it('creates a domain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
mock.onPost('/domains', { name: 'resend.com' }).replyOnce(201, {
|
|
26
|
+
id: '3d4a472d-bc6d-4dd2-aa9d-d3d50ce87222',
|
|
27
|
+
name: 'resend.com',
|
|
28
|
+
created_at: '2023-04-07T22:48:33.420498+00:00',
|
|
29
|
+
status: 'not_started',
|
|
30
|
+
records: [
|
|
31
|
+
{
|
|
32
|
+
record: 'SPF',
|
|
33
|
+
name: 'bounces',
|
|
34
|
+
type: 'MX',
|
|
35
|
+
ttl: 'Auto',
|
|
36
|
+
status: 'not_started',
|
|
37
|
+
value: `feedback-smtp.us-east-1.com`,
|
|
38
|
+
priority: 10,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
record: 'SPF',
|
|
42
|
+
name: 'bounces',
|
|
43
|
+
value: '"v=spf1 include:com ~all"',
|
|
44
|
+
type: 'TXT',
|
|
45
|
+
ttl: 'Auto',
|
|
46
|
+
status: 'not_started',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
record: 'DKIM',
|
|
50
|
+
name: 'nu22pfdfqaxdybogtw3ebaokmalv5mxg._domainkey',
|
|
51
|
+
value: 'nu22pfdfqaxdybogtw3ebaokmalv5mxg.dkim.com.',
|
|
52
|
+
type: 'CNAME',
|
|
53
|
+
status: 'not_started',
|
|
54
|
+
ttl: 'Auto',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
record: 'DKIM',
|
|
58
|
+
name: 'qklz5ozk742hhql3vmekdu3pr4f5ggsj._domainkey',
|
|
59
|
+
value: 'qklz5ozk742hhql3vmekdu3pr4f5ggsj.dkim.com.',
|
|
60
|
+
type: 'CNAME',
|
|
61
|
+
status: 'not_started',
|
|
62
|
+
ttl: 'Auto',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
record: 'DKIM',
|
|
66
|
+
name: 'eeaemodxoao5hxwjvhywx4bo5mswjw6v._domainkey',
|
|
67
|
+
value: 'eeaemodxoao5hxwjvhywx4bo5mswjw6v.dkim.com.',
|
|
68
|
+
type: 'CNAME',
|
|
69
|
+
status: 'not_started',
|
|
70
|
+
ttl: 'Auto',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
region: 'us-east-1',
|
|
74
|
+
});
|
|
75
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
76
|
+
yield expect(resend.domains.create({ name: 'resend.com' })).resolves
|
|
77
|
+
.toMatchInlineSnapshot(`
|
|
78
|
+
{
|
|
79
|
+
"created_at": "2023-04-07T22:48:33.420498+00:00",
|
|
80
|
+
"id": "3d4a472d-bc6d-4dd2-aa9d-d3d50ce87222",
|
|
81
|
+
"name": "resend.com",
|
|
82
|
+
"records": [
|
|
83
|
+
{
|
|
84
|
+
"name": "bounces",
|
|
85
|
+
"priority": 10,
|
|
86
|
+
"record": "SPF",
|
|
87
|
+
"status": "not_started",
|
|
88
|
+
"ttl": "Auto",
|
|
89
|
+
"type": "MX",
|
|
90
|
+
"value": "feedback-smtp.us-east-1.com",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "bounces",
|
|
94
|
+
"record": "SPF",
|
|
95
|
+
"status": "not_started",
|
|
96
|
+
"ttl": "Auto",
|
|
97
|
+
"type": "TXT",
|
|
98
|
+
"value": ""v=spf1 include:com ~all"",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "nu22pfdfqaxdybogtw3ebaokmalv5mxg._domainkey",
|
|
102
|
+
"record": "DKIM",
|
|
103
|
+
"status": "not_started",
|
|
104
|
+
"ttl": "Auto",
|
|
105
|
+
"type": "CNAME",
|
|
106
|
+
"value": "nu22pfdfqaxdybogtw3ebaokmalv5mxg.dkim.com.",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "qklz5ozk742hhql3vmekdu3pr4f5ggsj._domainkey",
|
|
110
|
+
"record": "DKIM",
|
|
111
|
+
"status": "not_started",
|
|
112
|
+
"ttl": "Auto",
|
|
113
|
+
"type": "CNAME",
|
|
114
|
+
"value": "qklz5ozk742hhql3vmekdu3pr4f5ggsj.dkim.com.",
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "eeaemodxoao5hxwjvhywx4bo5mswjw6v._domainkey",
|
|
118
|
+
"record": "DKIM",
|
|
119
|
+
"status": "not_started",
|
|
120
|
+
"ttl": "Auto",
|
|
121
|
+
"type": "CNAME",
|
|
122
|
+
"value": "eeaemodxoao5hxwjvhywx4bo5mswjw6v.dkim.com.",
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
"region": "us-east-1",
|
|
126
|
+
"status": "not_started",
|
|
127
|
+
}
|
|
128
|
+
`);
|
|
129
|
+
expect(mock.history.post.length).toBe(1);
|
|
130
|
+
}));
|
|
131
|
+
it('throws error when missing name', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
132
|
+
mock.onPost('/domains').replyOnce(422, {
|
|
133
|
+
statusCode: 422,
|
|
134
|
+
name: 'missing_required_field',
|
|
135
|
+
message: 'Missing "name" field',
|
|
136
|
+
});
|
|
137
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
138
|
+
yield expect(resend.domains.create({ name: '' })).rejects
|
|
139
|
+
.toMatchInlineSnapshot(`
|
|
140
|
+
{
|
|
141
|
+
"message": "Missing "name" field",
|
|
142
|
+
"name": "missing_required_field",
|
|
143
|
+
"statusCode": 422,
|
|
144
|
+
}
|
|
145
|
+
`);
|
|
146
|
+
expect(mock.history.post.length).toBe(1);
|
|
147
|
+
}));
|
|
148
|
+
describe('with region', () => {
|
|
149
|
+
it('creates a domain with region', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
150
|
+
mock
|
|
151
|
+
.onPost('/domains', { name: 'resend.com', region: 'eu-west-1' })
|
|
152
|
+
.replyOnce(201, {
|
|
153
|
+
id: '3d4a472d-bc6d-4dd2-aa9d-d3d50ce87222',
|
|
154
|
+
name: 'resend.com',
|
|
155
|
+
created_at: '2023-04-07T22:48:33.420498+00:00',
|
|
156
|
+
status: 'not_started',
|
|
157
|
+
records: [
|
|
158
|
+
{
|
|
159
|
+
record: 'SPF',
|
|
160
|
+
name: 'bounces',
|
|
161
|
+
type: 'MX',
|
|
162
|
+
ttl: 'Auto',
|
|
163
|
+
status: 'not_started',
|
|
164
|
+
value: `feedback-smtp.eu-west-1.com`,
|
|
165
|
+
priority: 10,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
record: 'SPF',
|
|
169
|
+
name: 'bounces',
|
|
170
|
+
value: '"v=spf1 include:com ~all"',
|
|
171
|
+
type: 'TXT',
|
|
172
|
+
ttl: 'Auto',
|
|
173
|
+
status: 'not_started',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
record: 'DKIM',
|
|
177
|
+
name: 'nu22pfdfqaxdybogtw3ebaokmalv5mxg._domainkey',
|
|
178
|
+
value: 'nu22pfdfqaxdybogtw3ebaokmalv5mxg.dkim.com.',
|
|
179
|
+
type: 'CNAME',
|
|
180
|
+
status: 'not_started',
|
|
181
|
+
ttl: 'Auto',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
record: 'DKIM',
|
|
185
|
+
name: 'qklz5ozk742hhql3vmekdu3pr4f5ggsj._domainkey',
|
|
186
|
+
value: 'qklz5ozk742hhql3vmekdu3pr4f5ggsj.dkim.com.',
|
|
187
|
+
type: 'CNAME',
|
|
188
|
+
status: 'not_started',
|
|
189
|
+
ttl: 'Auto',
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
record: 'DKIM',
|
|
193
|
+
name: 'eeaemodxoao5hxwjvhywx4bo5mswjw6v._domainkey',
|
|
194
|
+
value: 'eeaemodxoao5hxwjvhywx4bo5mswjw6v.dkim.com.',
|
|
195
|
+
type: 'CNAME',
|
|
196
|
+
status: 'not_started',
|
|
197
|
+
ttl: 'Auto',
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
region: 'eu-west-1',
|
|
201
|
+
});
|
|
202
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
203
|
+
yield expect(resend.domains.create({ name: 'resend.com', region: 'eu-west-1' })).resolves.toMatchInlineSnapshot(`
|
|
204
|
+
{
|
|
205
|
+
"created_at": "2023-04-07T22:48:33.420498+00:00",
|
|
206
|
+
"id": "3d4a472d-bc6d-4dd2-aa9d-d3d50ce87222",
|
|
207
|
+
"name": "resend.com",
|
|
208
|
+
"records": [
|
|
209
|
+
{
|
|
210
|
+
"name": "bounces",
|
|
211
|
+
"priority": 10,
|
|
212
|
+
"record": "SPF",
|
|
213
|
+
"status": "not_started",
|
|
214
|
+
"ttl": "Auto",
|
|
215
|
+
"type": "MX",
|
|
216
|
+
"value": "feedback-smtp.eu-west-1.com",
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"name": "bounces",
|
|
220
|
+
"record": "SPF",
|
|
221
|
+
"status": "not_started",
|
|
222
|
+
"ttl": "Auto",
|
|
223
|
+
"type": "TXT",
|
|
224
|
+
"value": ""v=spf1 include:com ~all"",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"name": "nu22pfdfqaxdybogtw3ebaokmalv5mxg._domainkey",
|
|
228
|
+
"record": "DKIM",
|
|
229
|
+
"status": "not_started",
|
|
230
|
+
"ttl": "Auto",
|
|
231
|
+
"type": "CNAME",
|
|
232
|
+
"value": "nu22pfdfqaxdybogtw3ebaokmalv5mxg.dkim.com.",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"name": "qklz5ozk742hhql3vmekdu3pr4f5ggsj._domainkey",
|
|
236
|
+
"record": "DKIM",
|
|
237
|
+
"status": "not_started",
|
|
238
|
+
"ttl": "Auto",
|
|
239
|
+
"type": "CNAME",
|
|
240
|
+
"value": "qklz5ozk742hhql3vmekdu3pr4f5ggsj.dkim.com.",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"name": "eeaemodxoao5hxwjvhywx4bo5mswjw6v._domainkey",
|
|
244
|
+
"record": "DKIM",
|
|
245
|
+
"status": "not_started",
|
|
246
|
+
"ttl": "Auto",
|
|
247
|
+
"type": "CNAME",
|
|
248
|
+
"value": "eeaemodxoao5hxwjvhywx4bo5mswjw6v.dkim.com.",
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
"region": "eu-west-1",
|
|
252
|
+
"status": "not_started",
|
|
253
|
+
}
|
|
254
|
+
`);
|
|
255
|
+
expect(mock.history.post.length).toBe(1);
|
|
256
|
+
}));
|
|
257
|
+
it('throws error with wrong region', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
258
|
+
mock.onPost('/domains').replyOnce(422, {
|
|
259
|
+
statusCode: 422,
|
|
260
|
+
name: 'invalid_region',
|
|
261
|
+
message: 'Region must be "us-east-1" | "eu-west-1" | "sa-east-1"',
|
|
262
|
+
});
|
|
263
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
264
|
+
yield expect(resend.domains.create({
|
|
265
|
+
name: 'resend.com',
|
|
266
|
+
region: 'remote',
|
|
267
|
+
})).rejects.toMatchInlineSnapshot(`
|
|
268
|
+
{
|
|
269
|
+
"message": "Region must be "us-east-1" | "eu-west-1" | "sa-east-1"",
|
|
270
|
+
"name": "invalid_region",
|
|
271
|
+
"statusCode": 422,
|
|
272
|
+
}
|
|
273
|
+
`);
|
|
274
|
+
expect(mock.history.post.length).toBe(1);
|
|
275
|
+
}));
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
describe('list', () => {
|
|
279
|
+
it('lists domains', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
280
|
+
mock.onGet('/domains').replyOnce(200, {
|
|
281
|
+
data: [
|
|
282
|
+
{
|
|
283
|
+
id: 'b6d24b8e-af0b-4c3c-be0c-359bbd97381e',
|
|
284
|
+
name: 'resend.com',
|
|
285
|
+
status: 'not_started',
|
|
286
|
+
created_at: '2023-04-07T23:13:52.669661+00:00',
|
|
287
|
+
region: 'eu-west-1',
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
id: 'ac7503ac-e027-4aea-94b3-b0acd46f65f9',
|
|
291
|
+
name: 'react.email',
|
|
292
|
+
status: 'not_started',
|
|
293
|
+
created_at: '2023-04-07T23:13:20.417116+00:00',
|
|
294
|
+
region: 'us-east-1',
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
});
|
|
298
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
299
|
+
yield expect(resend.domains.list()).resolves.toMatchInlineSnapshot(`
|
|
300
|
+
[
|
|
301
|
+
{
|
|
302
|
+
"created_at": "2023-04-07T23:13:52.669661+00:00",
|
|
303
|
+
"id": "b6d24b8e-af0b-4c3c-be0c-359bbd97381e",
|
|
304
|
+
"name": "resend.com",
|
|
305
|
+
"region": "eu-west-1",
|
|
306
|
+
"status": "not_started",
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"created_at": "2023-04-07T23:13:20.417116+00:00",
|
|
310
|
+
"id": "ac7503ac-e027-4aea-94b3-b0acd46f65f9",
|
|
311
|
+
"name": "react.email",
|
|
312
|
+
"region": "us-east-1",
|
|
313
|
+
"status": "not_started",
|
|
314
|
+
},
|
|
315
|
+
]
|
|
316
|
+
`);
|
|
317
|
+
expect(mock.history.get.length).toBe(1);
|
|
318
|
+
}));
|
|
319
|
+
});
|
|
320
|
+
describe('verify', () => {
|
|
321
|
+
it('verifies a domain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
322
|
+
mock
|
|
323
|
+
.onPost('/domains/5262504e-8ed7-4fac-bd16-0d4be94bc9f2/verify')
|
|
324
|
+
.replyOnce(200);
|
|
325
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
326
|
+
yield expect(resend.domains.verify('5262504e-8ed7-4fac-bd16-0d4be94bc9f2')).resolves.toMatchInlineSnapshot(`undefined`);
|
|
327
|
+
expect(mock.history.post.length).toBe(1);
|
|
328
|
+
}));
|
|
329
|
+
});
|
|
330
|
+
describe('remove', () => {
|
|
331
|
+
it('removes a domain', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
332
|
+
mock
|
|
333
|
+
.onDelete('/domains/5262504e-8ed7-4fac-bd16-0d4be94bc9f2')
|
|
334
|
+
.replyOnce(200);
|
|
335
|
+
const resend = new resend_1.Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
|
|
336
|
+
yield expect(resend.domains.remove('5262504e-8ed7-4fac-bd16-0d4be94bc9f2')).resolves.toMatchInlineSnapshot(`undefined`);
|
|
337
|
+
expect(mock.history.delete.length).toBe(1);
|
|
338
|
+
}));
|
|
339
|
+
});
|
|
340
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PostOptions } from '../../common/interfaces';
|
|
2
2
|
export type DomainRegion = 'us-east-1' | 'eu-west-1' | 'sa-east-1';
|
|
3
3
|
export interface CreateDomainOptions {
|
|
4
|
-
|
|
4
|
+
name: string;
|
|
5
5
|
region?: DomainRegion;
|
|
6
6
|
}
|
|
7
7
|
export interface CreateDomainRequestOptions extends PostOptions {
|
|
@@ -15,9 +15,9 @@ export interface DomainSpfRecord {
|
|
|
15
15
|
type: 'MX' | 'TXT';
|
|
16
16
|
ttl: string;
|
|
17
17
|
status: DomainStatus;
|
|
18
|
-
|
|
18
|
+
routing_policy?: string;
|
|
19
19
|
priority?: number;
|
|
20
|
-
|
|
20
|
+
proxy_status?: 'enable' | 'disable';
|
|
21
21
|
}
|
|
22
22
|
export interface DomainDkimRecord {
|
|
23
23
|
record: 'DKIM';
|
|
@@ -26,16 +26,15 @@ export interface DomainDkimRecord {
|
|
|
26
26
|
type: 'CNAME';
|
|
27
27
|
ttl: string;
|
|
28
28
|
status: DomainStatus;
|
|
29
|
-
|
|
29
|
+
routing_policy?: string;
|
|
30
30
|
priority?: number;
|
|
31
|
-
|
|
31
|
+
proxy_status?: 'enable' | 'disable';
|
|
32
32
|
}
|
|
33
33
|
export type CreateDomainResponse = {
|
|
34
34
|
name: string;
|
|
35
35
|
id: string;
|
|
36
|
-
dnsProvider: DomainNameservers;
|
|
37
36
|
status: DomainStatus;
|
|
38
|
-
|
|
37
|
+
created_at: string;
|
|
39
38
|
records: (DomainSpfRecord | DomainDkimRecord)[];
|
|
40
39
|
region: DomainRegion;
|
|
41
40
|
};
|
package/build/src/resend.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare class Resend {
|
|
|
11
11
|
readonly apiKeys: ApiKeys;
|
|
12
12
|
readonly domains: Domains;
|
|
13
13
|
constructor(key?: string | undefined);
|
|
14
|
-
post(path: string, entity?: any, options?: PostOptions): Promise<
|
|
14
|
+
post<T>(path: string, entity?: any, options?: PostOptions): Promise<T>;
|
|
15
15
|
get(path: string, options?: GetOptions): Promise<AxiosResponse>;
|
|
16
16
|
put(path: string, entity: any, options?: PutOptions): Promise<AxiosResponse>;
|
|
17
17
|
delete(path: string, query?: any): Promise<AxiosResponse>;
|
package/build/src/resend.js
CHANGED
|
@@ -42,6 +42,9 @@ class Resend {
|
|
|
42
42
|
maxBodyLength: Infinity,
|
|
43
43
|
});
|
|
44
44
|
this.request.interceptors.response.use((response) => {
|
|
45
|
+
if (response.data) {
|
|
46
|
+
return response.data;
|
|
47
|
+
}
|
|
45
48
|
return response;
|
|
46
49
|
}, (error) => {
|
|
47
50
|
var _a, _b, _c;
|
|
@@ -114,7 +117,7 @@ class Resend {
|
|
|
114
117
|
data.html = (0, render_1.render)(data.react);
|
|
115
118
|
delete data.react;
|
|
116
119
|
}
|
|
117
|
-
const
|
|
120
|
+
const response = yield this.post(path, {
|
|
118
121
|
from: data.from,
|
|
119
122
|
to: data.to,
|
|
120
123
|
bcc: data.bcc,
|
|
@@ -125,12 +128,8 @@ class Resend {
|
|
|
125
128
|
html: data.html,
|
|
126
129
|
attachments: data.attachments,
|
|
127
130
|
tags: data.tags,
|
|
128
|
-
};
|
|
129
|
-
const response = yield this.request(path, {
|
|
130
|
-
method: 'POST',
|
|
131
|
-
data: requestData,
|
|
132
131
|
});
|
|
133
|
-
return response
|
|
132
|
+
return response;
|
|
134
133
|
}
|
|
135
134
|
catch (error) {
|
|
136
135
|
throw error;
|
package/build/src/resend.spec.js
CHANGED
|
@@ -35,7 +35,14 @@ describe('Resend', () => {
|
|
|
35
35
|
created_at: '123',
|
|
36
36
|
});
|
|
37
37
|
const data = yield resend.sendEmail(payload);
|
|
38
|
-
expect(data).
|
|
38
|
+
expect(data).toMatchInlineSnapshot(`
|
|
39
|
+
{
|
|
40
|
+
"created_at": "123",
|
|
41
|
+
"from": "bu@resend.com",
|
|
42
|
+
"id": "1234",
|
|
43
|
+
"to": "zeno@resend.com",
|
|
44
|
+
}
|
|
45
|
+
`);
|
|
39
46
|
}));
|
|
40
47
|
it('sends email with multiple recipients', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
48
|
const payload = {
|
|
@@ -50,7 +57,17 @@ describe('Resend', () => {
|
|
|
50
57
|
created_at: '123',
|
|
51
58
|
});
|
|
52
59
|
const data = yield resend.sendEmail(payload);
|
|
53
|
-
expect(data).
|
|
60
|
+
expect(data).toMatchInlineSnapshot(`
|
|
61
|
+
{
|
|
62
|
+
"created_at": "123",
|
|
63
|
+
"from": "admin@resend.com",
|
|
64
|
+
"id": "1234",
|
|
65
|
+
"to": [
|
|
66
|
+
"bu@resend.com",
|
|
67
|
+
"zeno@resend.com",
|
|
68
|
+
],
|
|
69
|
+
}
|
|
70
|
+
`);
|
|
54
71
|
}));
|
|
55
72
|
it('sends email with multiple bcc recipients', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
73
|
const payload = {
|
|
@@ -67,7 +84,18 @@ describe('Resend', () => {
|
|
|
67
84
|
created_at: '123',
|
|
68
85
|
});
|
|
69
86
|
const data = yield resend.sendEmail(payload);
|
|
70
|
-
expect(data).
|
|
87
|
+
expect(data).toMatchInlineSnapshot(`
|
|
88
|
+
{
|
|
89
|
+
"bcc": [
|
|
90
|
+
"foo@resend.com",
|
|
91
|
+
"bar@resend.com",
|
|
92
|
+
],
|
|
93
|
+
"created_at": "123",
|
|
94
|
+
"from": "admin@resend.com",
|
|
95
|
+
"id": "1234",
|
|
96
|
+
"to": "bu@resend.com",
|
|
97
|
+
}
|
|
98
|
+
`);
|
|
71
99
|
}));
|
|
72
100
|
it('sends email with multiple cc recipients', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
101
|
const payload = {
|
|
@@ -84,7 +112,18 @@ describe('Resend', () => {
|
|
|
84
112
|
created_at: '123',
|
|
85
113
|
});
|
|
86
114
|
const data = yield resend.sendEmail(payload);
|
|
87
|
-
expect(data).
|
|
115
|
+
expect(data).toMatchInlineSnapshot(`
|
|
116
|
+
{
|
|
117
|
+
"cc": [
|
|
118
|
+
"foo@resend.com",
|
|
119
|
+
"bar@resend.com",
|
|
120
|
+
],
|
|
121
|
+
"created_at": "123",
|
|
122
|
+
"from": "admin@resend.com",
|
|
123
|
+
"id": "1234",
|
|
124
|
+
"to": "bu@resend.com",
|
|
125
|
+
}
|
|
126
|
+
`);
|
|
88
127
|
}));
|
|
89
128
|
it('sends email with multiple replyTo emails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
129
|
const apiPayload = {
|
|
@@ -107,6 +146,17 @@ describe('Resend', () => {
|
|
|
107
146
|
subject: 'Hello World',
|
|
108
147
|
};
|
|
109
148
|
const data = yield resend.sendEmail(payload);
|
|
110
|
-
expect(data).
|
|
149
|
+
expect(data).toMatchInlineSnapshot(`
|
|
150
|
+
{
|
|
151
|
+
"created_at": "123",
|
|
152
|
+
"from": "admin@resend.com",
|
|
153
|
+
"id": "1234",
|
|
154
|
+
"reply_to": [
|
|
155
|
+
"foo@resend.com",
|
|
156
|
+
"bar@resend.com",
|
|
157
|
+
],
|
|
158
|
+
"to": "bu@resend.com",
|
|
159
|
+
}
|
|
160
|
+
`);
|
|
111
161
|
}));
|
|
112
162
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.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",
|
|
@@ -27,19 +27,19 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/resend-inc/resend-node#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@react-email/render": "0.0.
|
|
31
|
-
"axios": "1.3.
|
|
30
|
+
"@react-email/render": "0.0.7",
|
|
31
|
+
"axios": "1.3.5"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/jest": "29.5.0",
|
|
35
35
|
"@types/node": "18.15.6",
|
|
36
|
-
"@types/react": "18.0.
|
|
37
|
-
"axios-mock-adapter": "1.21.
|
|
36
|
+
"@types/react": "18.0.32",
|
|
37
|
+
"axios-mock-adapter": "1.21.4",
|
|
38
38
|
"jest": "29.5.0",
|
|
39
39
|
"prettier": "2.8.7",
|
|
40
40
|
"supertest": "6.3.3",
|
|
41
|
-
"ts-jest": "29.0
|
|
41
|
+
"ts-jest": "29.1.0",
|
|
42
42
|
"tslint": "6.1.3",
|
|
43
|
-
"typescript": "5.0.
|
|
43
|
+
"typescript": "5.0.4"
|
|
44
44
|
}
|
|
45
45
|
}
|