@unsent/sdk 0.25.5 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -2
- package/dist/index.d.mts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +21 -13
- package/dist/index.mjs +21 -13
- package/package.json +24 -5
package/README.md
CHANGED
|
@@ -60,8 +60,8 @@ const { data, error } = await client.emails.send({
|
|
|
60
60
|
to: "hello@acme.com",
|
|
61
61
|
from: "hello@company.com",
|
|
62
62
|
subject: "unsent email",
|
|
63
|
-
html: "<p>unsent is the best
|
|
64
|
-
text: "unsent is the best
|
|
63
|
+
html: "<p>unsent is the best email service provider to send emails</p>",
|
|
64
|
+
text: "unsent is the best email service provider to send emails",
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
if (error) {
|
|
@@ -143,6 +143,60 @@ if (error) {
|
|
|
143
143
|
}
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
+
#### Idempotency Keys
|
|
147
|
+
|
|
148
|
+
Safely retry email sends with an idempotency key to prevent duplicate sends. This is especially useful for critical emails like signup confirmations or password resets.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// Safely retry sends with an idempotency key
|
|
152
|
+
const { data, error } = await client.emails.send(
|
|
153
|
+
{
|
|
154
|
+
to: "hello@acme.com",
|
|
155
|
+
from: "hello@company.com",
|
|
156
|
+
subject: "unsent email",
|
|
157
|
+
html: "<p>unsent is the best open source product to send emails</p>",
|
|
158
|
+
},
|
|
159
|
+
{ idempotencyKey: "signup-123" },
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
if (error) {
|
|
163
|
+
console.error("Error:", error);
|
|
164
|
+
} else {
|
|
165
|
+
console.log("Email sent! ID:", data.id);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Idempotency keys also work for batch sends:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// Works for bulk sends too
|
|
173
|
+
const { data, error } = await client.emails.batch(
|
|
174
|
+
[
|
|
175
|
+
{
|
|
176
|
+
to: "a@example.com",
|
|
177
|
+
from: "hello@company.com",
|
|
178
|
+
subject: "Welcome",
|
|
179
|
+
html: "<p>Hello A</p>",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
to: "b@example.com",
|
|
183
|
+
from: "hello@company.com",
|
|
184
|
+
subject: "Welcome",
|
|
185
|
+
html: "<p>Hello B</p>",
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
{ idempotencyKey: "bulk-welcome-1" },
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
if (error) {
|
|
192
|
+
console.error("Error:", error);
|
|
193
|
+
} else {
|
|
194
|
+
console.log(`Sent ${data.length} emails`);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
> **Note:** Reusing the same idempotency key with a different payload will return HTTP 409 (Conflict). This ensures that retries are safe and prevents accidental duplicate sends with modified content.
|
|
199
|
+
|
|
146
200
|
### Managing Emails
|
|
147
201
|
|
|
148
202
|
#### Get Email Details
|
|
@@ -400,3 +454,9 @@ if (result.data) {
|
|
|
400
454
|
## License
|
|
401
455
|
|
|
402
456
|
MIT
|
|
457
|
+
|
|
458
|
+
## Support
|
|
459
|
+
|
|
460
|
+
- [Documentation](https://docs.unsent.dev)
|
|
461
|
+
- [GitHub Issues](https://github.com/souravsspace/unsent-typescript/issues)
|
|
462
|
+
- [Discord Community](https://discord.gg/unsent)
|
package/dist/index.d.mts
CHANGED
|
@@ -1312,6 +1312,12 @@ type BatchEmailPayload = paths["/v1/emails/batch"]["post"]["requestBody"]["conte
|
|
|
1312
1312
|
* Successful response schema for batch email send.
|
|
1313
1313
|
*/
|
|
1314
1314
|
type BatchEmailResponseSuccess = paths["/v1/emails/batch"]["post"]["responses"]["200"]["content"]["application/json"];
|
|
1315
|
+
/**
|
|
1316
|
+
* Options for email requests.
|
|
1317
|
+
*/
|
|
1318
|
+
type EmailRequestOptions = {
|
|
1319
|
+
idempotencyKey?: string;
|
|
1320
|
+
};
|
|
1315
1321
|
/**
|
|
1316
1322
|
* Response structure for the batch method.
|
|
1317
1323
|
*/
|
|
@@ -1322,15 +1328,15 @@ type BatchEmailResponse = {
|
|
|
1322
1328
|
declare class Emails {
|
|
1323
1329
|
private readonly unsent;
|
|
1324
1330
|
constructor(unsent: unsent);
|
|
1325
|
-
send(payload: SendEmailPayload): Promise<CreateEmailResponse>;
|
|
1326
|
-
create(payload: SendEmailPayload): Promise<CreateEmailResponse>;
|
|
1331
|
+
send(payload: SendEmailPayload, options?: EmailRequestOptions): Promise<CreateEmailResponse>;
|
|
1332
|
+
create(payload: SendEmailPayload, options?: EmailRequestOptions): Promise<CreateEmailResponse>;
|
|
1327
1333
|
/**
|
|
1328
1334
|
* Send up to 100 emails in a single request.
|
|
1329
1335
|
*
|
|
1330
1336
|
* @param payload An array of email payloads. Max 100 emails.
|
|
1331
1337
|
* @returns A promise that resolves to the list of created email IDs or an error.
|
|
1332
1338
|
*/
|
|
1333
|
-
batch(payload: BatchEmailPayload): Promise<BatchEmailResponse>;
|
|
1339
|
+
batch(payload: BatchEmailPayload, options?: EmailRequestOptions): Promise<BatchEmailResponse>;
|
|
1334
1340
|
get(id: string): Promise<GetEmailResponse>;
|
|
1335
1341
|
update(id: string, payload: UpdateEmailPayload): Promise<UpdateEmailResponse>;
|
|
1336
1342
|
cancel(id: string): Promise<CancelEmailResponse>;
|
|
@@ -1419,7 +1425,9 @@ declare class unsent {
|
|
|
1419
1425
|
data: T | null;
|
|
1420
1426
|
error: ErrorResponse | null;
|
|
1421
1427
|
}>;
|
|
1422
|
-
post<T>(path: string, body: unknown
|
|
1428
|
+
post<T>(path: string, body: unknown, options?: {
|
|
1429
|
+
headers?: Record<string, string>;
|
|
1430
|
+
}): Promise<{
|
|
1423
1431
|
data: T | null;
|
|
1424
1432
|
error: ErrorResponse | null;
|
|
1425
1433
|
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1312,6 +1312,12 @@ type BatchEmailPayload = paths["/v1/emails/batch"]["post"]["requestBody"]["conte
|
|
|
1312
1312
|
* Successful response schema for batch email send.
|
|
1313
1313
|
*/
|
|
1314
1314
|
type BatchEmailResponseSuccess = paths["/v1/emails/batch"]["post"]["responses"]["200"]["content"]["application/json"];
|
|
1315
|
+
/**
|
|
1316
|
+
* Options for email requests.
|
|
1317
|
+
*/
|
|
1318
|
+
type EmailRequestOptions = {
|
|
1319
|
+
idempotencyKey?: string;
|
|
1320
|
+
};
|
|
1315
1321
|
/**
|
|
1316
1322
|
* Response structure for the batch method.
|
|
1317
1323
|
*/
|
|
@@ -1322,15 +1328,15 @@ type BatchEmailResponse = {
|
|
|
1322
1328
|
declare class Emails {
|
|
1323
1329
|
private readonly unsent;
|
|
1324
1330
|
constructor(unsent: unsent);
|
|
1325
|
-
send(payload: SendEmailPayload): Promise<CreateEmailResponse>;
|
|
1326
|
-
create(payload: SendEmailPayload): Promise<CreateEmailResponse>;
|
|
1331
|
+
send(payload: SendEmailPayload, options?: EmailRequestOptions): Promise<CreateEmailResponse>;
|
|
1332
|
+
create(payload: SendEmailPayload, options?: EmailRequestOptions): Promise<CreateEmailResponse>;
|
|
1327
1333
|
/**
|
|
1328
1334
|
* Send up to 100 emails in a single request.
|
|
1329
1335
|
*
|
|
1330
1336
|
* @param payload An array of email payloads. Max 100 emails.
|
|
1331
1337
|
* @returns A promise that resolves to the list of created email IDs or an error.
|
|
1332
1338
|
*/
|
|
1333
|
-
batch(payload: BatchEmailPayload): Promise<BatchEmailResponse>;
|
|
1339
|
+
batch(payload: BatchEmailPayload, options?: EmailRequestOptions): Promise<BatchEmailResponse>;
|
|
1334
1340
|
get(id: string): Promise<GetEmailResponse>;
|
|
1335
1341
|
update(id: string, payload: UpdateEmailPayload): Promise<UpdateEmailResponse>;
|
|
1336
1342
|
cancel(id: string): Promise<CancelEmailResponse>;
|
|
@@ -1419,7 +1425,9 @@ declare class unsent {
|
|
|
1419
1425
|
data: T | null;
|
|
1420
1426
|
error: ErrorResponse | null;
|
|
1421
1427
|
}>;
|
|
1422
|
-
post<T>(path: string, body: unknown
|
|
1428
|
+
post<T>(path: string, body: unknown, options?: {
|
|
1429
|
+
headers?: Record<string, string>;
|
|
1430
|
+
}): Promise<{
|
|
1423
1431
|
data: T | null;
|
|
1424
1432
|
error: ErrorResponse | null;
|
|
1425
1433
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -73,17 +73,18 @@ var Emails = class {
|
|
|
73
73
|
this.unsent = unsent2;
|
|
74
74
|
this.unsent = unsent2;
|
|
75
75
|
}
|
|
76
|
-
async send(payload) {
|
|
77
|
-
return this.create(payload);
|
|
76
|
+
async send(payload, options) {
|
|
77
|
+
return this.create(payload, options);
|
|
78
78
|
}
|
|
79
|
-
async create(payload) {
|
|
79
|
+
async create(payload, options) {
|
|
80
80
|
if (payload.react) {
|
|
81
81
|
payload.html = await (0, import_render.render)(payload.react);
|
|
82
82
|
delete payload.react;
|
|
83
83
|
}
|
|
84
84
|
const data = await this.unsent.post(
|
|
85
85
|
"/emails",
|
|
86
|
-
payload
|
|
86
|
+
payload,
|
|
87
|
+
options?.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : void 0
|
|
87
88
|
);
|
|
88
89
|
return data;
|
|
89
90
|
}
|
|
@@ -93,10 +94,11 @@ var Emails = class {
|
|
|
93
94
|
* @param payload An array of email payloads. Max 100 emails.
|
|
94
95
|
* @returns A promise that resolves to the list of created email IDs or an error.
|
|
95
96
|
*/
|
|
96
|
-
async batch(payload) {
|
|
97
|
+
async batch(payload, options) {
|
|
97
98
|
const response = await this.unsent.post(
|
|
98
99
|
"/emails/batch",
|
|
99
|
-
payload
|
|
100
|
+
payload,
|
|
101
|
+
options?.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : void 0
|
|
100
102
|
);
|
|
101
103
|
return {
|
|
102
104
|
data: response.data ? response.data.data : null,
|
|
@@ -206,9 +208,9 @@ var Campaigns = class {
|
|
|
206
208
|
};
|
|
207
209
|
|
|
208
210
|
// src/unsent.ts
|
|
209
|
-
var defaultBaseUrl = "https://
|
|
210
|
-
var baseUrl = `${process?.env?.UNSENT_BASE_URL ?? process?.env?.UNSENT_BASE_URL ?? defaultBaseUrl}/
|
|
211
|
-
function
|
|
211
|
+
var defaultBaseUrl = "https://api.unsent.dev";
|
|
212
|
+
var baseUrl = `${process?.env?.UNSENT_BASE_URL ?? process?.env?.UNSENT_BASE_URL ?? defaultBaseUrl}/v1`;
|
|
213
|
+
function isUnsentErrorResponse(error) {
|
|
212
214
|
return error.error.code !== void 0;
|
|
213
215
|
}
|
|
214
216
|
var unsent = class {
|
|
@@ -216,7 +218,7 @@ var unsent = class {
|
|
|
216
218
|
this.key = key;
|
|
217
219
|
if (!key) {
|
|
218
220
|
if (typeof process !== "undefined" && process.env) {
|
|
219
|
-
this.key = process.env.
|
|
221
|
+
this.key = process.env.UNSENT_API_KEY ?? process.env.UNSENT_API_KEY;
|
|
220
222
|
}
|
|
221
223
|
if (!this.key) {
|
|
222
224
|
throw new Error(
|
|
@@ -247,7 +249,7 @@ var unsent = class {
|
|
|
247
249
|
if (!response.ok) {
|
|
248
250
|
try {
|
|
249
251
|
const resp = await response.json();
|
|
250
|
-
if (
|
|
252
|
+
if (isUnsentErrorResponse(resp)) {
|
|
251
253
|
return { data: null, error: resp };
|
|
252
254
|
}
|
|
253
255
|
return { data: null, error: resp.error };
|
|
@@ -264,10 +266,16 @@ var unsent = class {
|
|
|
264
266
|
const data = await response.json();
|
|
265
267
|
return { data, error: null };
|
|
266
268
|
}
|
|
267
|
-
async post(path, body) {
|
|
269
|
+
async post(path, body, options) {
|
|
270
|
+
const headers = new Headers(this.headers);
|
|
271
|
+
if (options?.headers) {
|
|
272
|
+
Object.entries(options.headers).forEach(([key, value]) => {
|
|
273
|
+
headers.set(key, value);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
268
276
|
const requestOptions = {
|
|
269
277
|
method: "POST",
|
|
270
|
-
headers
|
|
278
|
+
headers,
|
|
271
279
|
body: JSON.stringify(body)
|
|
272
280
|
};
|
|
273
281
|
return this.fetchRequest(path, requestOptions);
|
package/dist/index.mjs
CHANGED
|
@@ -46,17 +46,18 @@ var Emails = class {
|
|
|
46
46
|
this.unsent = unsent2;
|
|
47
47
|
this.unsent = unsent2;
|
|
48
48
|
}
|
|
49
|
-
async send(payload) {
|
|
50
|
-
return this.create(payload);
|
|
49
|
+
async send(payload, options) {
|
|
50
|
+
return this.create(payload, options);
|
|
51
51
|
}
|
|
52
|
-
async create(payload) {
|
|
52
|
+
async create(payload, options) {
|
|
53
53
|
if (payload.react) {
|
|
54
54
|
payload.html = await render(payload.react);
|
|
55
55
|
delete payload.react;
|
|
56
56
|
}
|
|
57
57
|
const data = await this.unsent.post(
|
|
58
58
|
"/emails",
|
|
59
|
-
payload
|
|
59
|
+
payload,
|
|
60
|
+
options?.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : void 0
|
|
60
61
|
);
|
|
61
62
|
return data;
|
|
62
63
|
}
|
|
@@ -66,10 +67,11 @@ var Emails = class {
|
|
|
66
67
|
* @param payload An array of email payloads. Max 100 emails.
|
|
67
68
|
* @returns A promise that resolves to the list of created email IDs or an error.
|
|
68
69
|
*/
|
|
69
|
-
async batch(payload) {
|
|
70
|
+
async batch(payload, options) {
|
|
70
71
|
const response = await this.unsent.post(
|
|
71
72
|
"/emails/batch",
|
|
72
|
-
payload
|
|
73
|
+
payload,
|
|
74
|
+
options?.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : void 0
|
|
73
75
|
);
|
|
74
76
|
return {
|
|
75
77
|
data: response.data ? response.data.data : null,
|
|
@@ -179,9 +181,9 @@ var Campaigns = class {
|
|
|
179
181
|
};
|
|
180
182
|
|
|
181
183
|
// src/unsent.ts
|
|
182
|
-
var defaultBaseUrl = "https://
|
|
183
|
-
var baseUrl = `${process?.env?.UNSENT_BASE_URL ?? process?.env?.UNSENT_BASE_URL ?? defaultBaseUrl}/
|
|
184
|
-
function
|
|
184
|
+
var defaultBaseUrl = "https://api.unsent.dev";
|
|
185
|
+
var baseUrl = `${process?.env?.UNSENT_BASE_URL ?? process?.env?.UNSENT_BASE_URL ?? defaultBaseUrl}/v1`;
|
|
186
|
+
function isUnsentErrorResponse(error) {
|
|
185
187
|
return error.error.code !== void 0;
|
|
186
188
|
}
|
|
187
189
|
var unsent = class {
|
|
@@ -189,7 +191,7 @@ var unsent = class {
|
|
|
189
191
|
this.key = key;
|
|
190
192
|
if (!key) {
|
|
191
193
|
if (typeof process !== "undefined" && process.env) {
|
|
192
|
-
this.key = process.env.
|
|
194
|
+
this.key = process.env.UNSENT_API_KEY ?? process.env.UNSENT_API_KEY;
|
|
193
195
|
}
|
|
194
196
|
if (!this.key) {
|
|
195
197
|
throw new Error(
|
|
@@ -220,7 +222,7 @@ var unsent = class {
|
|
|
220
222
|
if (!response.ok) {
|
|
221
223
|
try {
|
|
222
224
|
const resp = await response.json();
|
|
223
|
-
if (
|
|
225
|
+
if (isUnsentErrorResponse(resp)) {
|
|
224
226
|
return { data: null, error: resp };
|
|
225
227
|
}
|
|
226
228
|
return { data: null, error: resp.error };
|
|
@@ -237,10 +239,16 @@ var unsent = class {
|
|
|
237
239
|
const data = await response.json();
|
|
238
240
|
return { data, error: null };
|
|
239
241
|
}
|
|
240
|
-
async post(path, body) {
|
|
242
|
+
async post(path, body, options) {
|
|
243
|
+
const headers = new Headers(this.headers);
|
|
244
|
+
if (options?.headers) {
|
|
245
|
+
Object.entries(options.headers).forEach(([key, value]) => {
|
|
246
|
+
headers.set(key, value);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
241
249
|
const requestOptions = {
|
|
242
250
|
method: "POST",
|
|
243
|
-
headers
|
|
251
|
+
headers,
|
|
244
252
|
body: JSON.stringify(body)
|
|
245
253
|
};
|
|
246
254
|
return this.fetchRequest(path, requestOptions);
|
package/package.json
CHANGED
|
@@ -1,20 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unsent/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "TypeScript SDK for the Unsent API - Send transactional emails with ease",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
-
"
|
|
9
|
-
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/souravsspace/unsent-typescript.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://unsent.dev",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/souravsspace/unsent-typescript/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"unsent",
|
|
18
|
+
"email",
|
|
19
|
+
"transactional-email",
|
|
20
|
+
"api",
|
|
21
|
+
"sdk",
|
|
22
|
+
"typescript",
|
|
23
|
+
"react-email"
|
|
24
|
+
],
|
|
25
|
+
"author": "sourav",
|
|
10
26
|
"license": "MIT",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
11
30
|
"devDependencies": {
|
|
12
31
|
"@types/node": "^24.7.0",
|
|
13
32
|
"@types/react": "^19.1.2",
|
|
14
33
|
"openapi-typescript": "^7.6.1",
|
|
15
34
|
"tsup": "^8.4.0",
|
|
16
35
|
"typescript": "^5.8.3",
|
|
17
|
-
"@
|
|
36
|
+
"@unsent/typescript-config": "0.0.0"
|
|
18
37
|
},
|
|
19
38
|
"dependencies": {
|
|
20
39
|
"@react-email/render": "^1.0.6",
|