@unsent/sdk 1.0.0 → 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 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 open source product to send emails</p>",
64
- text: "unsent is the best open source product to send emails",
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
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): Promise<{
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): Promise<{
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,
@@ -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: this.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,
@@ -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: this.headers,
251
+ headers,
244
252
  body: JSON.stringify(body)
245
253
  };
246
254
  return this.fetchRequest(path, requestOptions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unsent/sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
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",