zupost 0.1.0 → 0.2.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/README.md CHANGED
@@ -29,36 +29,53 @@ const zupost = new Zupost('your-api-key');
29
29
 
30
30
  ### Send an Email
31
31
 
32
+ Zupost is **template first**: design your emails in the Zupost dashboard and send them by `templateId`, passing in dynamic `variables`. This is the recommended approach for almost all use cases — content stays out of your codebase, can be edited without a deploy, and benefits from Zupost's rendering pipeline.
33
+
34
+ For ad-hoc or dynamically generated content, you can alternatively pass raw `html`, `markdown`, or a `react` component as a fallback.
35
+
32
36
  ```typescript
33
- // Send with HTML content
34
- const { emailId } = await zupost.emails.send({
37
+ // Recommended: send with a template
38
+ const { id } = await zupost.emails.send({
35
39
  from: 'sender@example.com',
36
40
  to: 'recipient@example.com',
37
- subject: 'Hello World',
38
- html: '<h1>Hello!</h1>',
41
+ templateId: 'welcome-template',
42
+ variables: { name: 'John' },
39
43
  });
40
44
 
41
- // Send to multiple recipients
45
+ // Send to multiple recipients with a template
42
46
  await zupost.emails.send({
43
47
  from: 'sender@example.com',
44
48
  to: ['user1@example.com', 'user2@example.com'],
45
- subject: 'Team Update',
46
- markdown: '# Hello Team\n\nThis is a **markdown** email.',
49
+ templateId: 'team-update',
50
+ variables: { teamName: 'Engineering' },
51
+ });
52
+ ```
53
+
54
+ #### Fallback: inline content
55
+
56
+ When a template is not a good fit, you can pass raw content instead. Exactly one of `html`, `markdown`, or `react` is required in that case.
57
+
58
+ ```typescript
59
+ // Inline HTML
60
+ await zupost.emails.send({
61
+ from: 'sender@example.com',
62
+ to: 'recipient@example.com',
63
+ subject: 'Hello World',
64
+ html: '<h1>Hello!</h1>',
47
65
  });
48
66
 
49
- // Send with a template
67
+ // Inline markdown
50
68
  await zupost.emails.send({
51
69
  from: 'sender@example.com',
52
70
  to: 'recipient@example.com',
53
- subject: 'Welcome!',
54
- templateId: 'welcome-template',
55
- variables: { name: 'John' },
71
+ subject: 'Team Update',
72
+ markdown: '# Hello Team\n\nThis is a **markdown** email.',
56
73
  });
57
74
  ```
58
75
 
59
- ### Send with React Email
76
+ ### Send with React Email (fallback)
60
77
 
61
- Zupost supports [React Email](https://react.email) components out of the box.
78
+ As an alternative to templates, Zupost supports [React Email](https://react.email) components out of the box.
62
79
 
63
80
  ```bash
64
81
  npm install @react-email/components
package/dist/index.d.mts CHANGED
@@ -1,8 +1,26 @@
1
1
  import { Options } from '@react-email/render';
2
2
  import { ReactNode } from 'react';
3
3
 
4
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
5
+ /**
6
+ * @internal
7
+ * Internal HTTP client for the Zupost API. Not part of the public API surface.
8
+ */
9
+ declare class HttpClient {
10
+ #private;
11
+ constructor(apiKey: string, baseUrl: string, userAgent: string);
12
+ request<T = unknown>(path: string, method: HttpMethod, body?: unknown): Promise<T>;
13
+ get<T = unknown>(path: string): Promise<T>;
14
+ post<T = unknown>(path: string, body: unknown): Promise<T>;
15
+ }
16
+
4
17
  /**
5
18
  * Options for sending an email.
19
+ *
20
+ * Zupost is template first: the recommended way to send is by providing a
21
+ * `templateId` (managed in the Zupost dashboard) together with `variables`.
22
+ * `html`, `markdown`, and `react` are supported as fallbacks for ad-hoc or
23
+ * dynamically generated content. Exactly one content source is required.
6
24
  */
7
25
  interface SendEmailOptions {
8
26
  /**
@@ -33,23 +51,28 @@ interface SendEmailOptions {
33
51
  */
34
52
  bcc?: string | string[];
35
53
  /**
36
- * ID of the email template to use.
54
+ * ID of the email template to use. Preferred way of sending: content and
55
+ * subject are managed in the Zupost dashboard and can be changed without a
56
+ * deploy. Combine with `variables` for interpolation.
37
57
  */
38
58
  templateId?: string;
39
59
  /**
40
- * Variables for template interpolation.
60
+ * Variables for template interpolation. Used together with `templateId`.
41
61
  */
42
62
  variables?: Record<string, string>;
43
63
  /**
44
- * Markdown content for the email.
64
+ * Markdown content for the email. Fallback to `templateId` — use for ad-hoc
65
+ * or dynamically generated content.
45
66
  */
46
67
  markdown?: string;
47
68
  /**
48
- * HTML content for the email.
69
+ * HTML content for the email. Fallback to `templateId` — use for ad-hoc or
70
+ * dynamically generated content.
49
71
  */
50
72
  html?: string;
51
73
  /**
52
- * React component for the email.
74
+ * React component for the email. Fallback to `templateId` — use for ad-hoc
75
+ * or dynamically generated content rendered via React Email.
53
76
  */
54
77
  react?: ReactNode;
55
78
  /**
@@ -99,36 +122,40 @@ interface SendEmailResponse {
99
122
  * Emails API for sending transactional emails.
100
123
  */
101
124
  declare class Emails {
102
- private readonly zupost;
103
- constructor(zupost: Zupost);
125
+ private readonly http;
126
+ constructor(http: HttpClient);
104
127
  /**
105
- * Send an email using template, markdown or HTML content.
128
+ * Send an email.
129
+ *
130
+ * Zupost is template first: prefer sending by `templateId` with `variables`
131
+ * so your content lives in the Zupost dashboard and can be edited without a
132
+ * deploy. Inline `html`, `markdown`, or `react` content is supported as a
133
+ * fallback for ad-hoc or dynamically generated emails.
106
134
  *
107
135
  * @param options - Email options including recipient, sender, and content.
108
- * @returns A promise that resolves to the email response containing emailId.
136
+ * @returns A promise that resolves to the email response containing the email id.
109
137
  *
110
138
  * @example
111
139
  * ```typescript
112
140
  * const zupost = new Zupost('your-api-key');
113
141
  *
114
- * // Send with HTML content
115
- * const { emailId } = await zupost.emails.send({
142
+ * // Recommended: send with a template
143
+ * const { id } = await zupost.emails.send({
116
144
  * from: 'sender@example.com',
117
145
  * to: 'recipient@example.com',
118
- * subject: 'Hello World',
119
- * html: '<h1>Hello!</h1>',
146
+ * templateId: 'welcome-template',
147
+ * variables: { name: 'John' },
120
148
  * });
121
149
  *
122
- * // Send with a template
150
+ * // Fallback: inline HTML
123
151
  * await zupost.emails.send({
124
152
  * from: 'sender@example.com',
125
- * to: ['user1@example.com', 'user2@example.com'],
126
- * subject: 'Welcome!',
127
- * templateId: 'welcome-template',
128
- * variables: { name: 'John' },
153
+ * to: 'recipient@example.com',
154
+ * subject: 'Hello World',
155
+ * html: '<h1>Hello!</h1>',
129
156
  * });
130
157
  *
131
- * // Send with markdown
158
+ * // Fallback: inline markdown
132
159
  * await zupost.emails.send({
133
160
  * from: 'sender@example.com',
134
161
  * to: 'recipient@example.com',
@@ -168,8 +195,8 @@ interface SendCampaignResponse {
168
195
  * Campaigns API for sending email campaigns to audiences.
169
196
  */
170
197
  declare class Campaigns {
171
- private readonly zupost;
172
- constructor(zupost: Zupost);
198
+ private readonly http;
199
+ constructor(http: HttpClient);
173
200
  /**
174
201
  * Send a campaign to selected audiences.
175
202
  *
@@ -199,8 +226,7 @@ interface ZupostOptions {
199
226
  baseUrl?: string;
200
227
  }
201
228
  declare class Zupost {
202
- private readonly headers;
203
- private readonly baseUrl;
229
+ #private;
204
230
  /**
205
231
  * Emails API for sending transactional emails.
206
232
  */
@@ -210,21 +236,27 @@ declare class Zupost {
210
236
  */
211
237
  readonly campaigns: Campaigns;
212
238
  constructor(apiKey: string, options?: ZupostOptions);
213
- /**
214
- * @internal
215
- * Makes a request to the Zupost API.
216
- */
217
- request<T = unknown>(path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE', body?: unknown): Promise<T>;
218
- /**
219
- * @internal
220
- * Makes a GET request to the Zupost API.
221
- */
222
- get<T = unknown>(path: string): Promise<T>;
223
- /**
224
- * @internal
225
- * Makes a POST request to the Zupost API.
226
- */
227
- post<T = unknown>(path: string, body: unknown): Promise<T>;
228
239
  }
229
240
 
230
- export { type SendCampaignOptions, type SendCampaignResponse, type SendEmailOptions, type SendEmailResponse, Zupost, type ZupostOptions };
241
+ /**
242
+ * Error thrown when the Zupost API returns a non-2xx response.
243
+ */
244
+ declare class ZupostError extends Error {
245
+ readonly status: number;
246
+ readonly statusText: string;
247
+ readonly body: string;
248
+ readonly requestId?: string;
249
+ readonly code?: string;
250
+ constructor(args: {
251
+ message: string;
252
+ status: number;
253
+ statusText: string;
254
+ body: string;
255
+ requestId?: string;
256
+ code?: string;
257
+ });
258
+ /** @internal */
259
+ static fromResponse(response: Response): Promise<ZupostError>;
260
+ }
261
+
262
+ export { type SendCampaignOptions, type SendCampaignResponse, type SendEmailOptions, type SendEmailResponse, Zupost, ZupostError, type ZupostOptions };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,26 @@
1
1
  import { Options } from '@react-email/render';
2
2
  import { ReactNode } from 'react';
3
3
 
4
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
5
+ /**
6
+ * @internal
7
+ * Internal HTTP client for the Zupost API. Not part of the public API surface.
8
+ */
9
+ declare class HttpClient {
10
+ #private;
11
+ constructor(apiKey: string, baseUrl: string, userAgent: string);
12
+ request<T = unknown>(path: string, method: HttpMethod, body?: unknown): Promise<T>;
13
+ get<T = unknown>(path: string): Promise<T>;
14
+ post<T = unknown>(path: string, body: unknown): Promise<T>;
15
+ }
16
+
4
17
  /**
5
18
  * Options for sending an email.
19
+ *
20
+ * Zupost is template first: the recommended way to send is by providing a
21
+ * `templateId` (managed in the Zupost dashboard) together with `variables`.
22
+ * `html`, `markdown`, and `react` are supported as fallbacks for ad-hoc or
23
+ * dynamically generated content. Exactly one content source is required.
6
24
  */
7
25
  interface SendEmailOptions {
8
26
  /**
@@ -33,23 +51,28 @@ interface SendEmailOptions {
33
51
  */
34
52
  bcc?: string | string[];
35
53
  /**
36
- * ID of the email template to use.
54
+ * ID of the email template to use. Preferred way of sending: content and
55
+ * subject are managed in the Zupost dashboard and can be changed without a
56
+ * deploy. Combine with `variables` for interpolation.
37
57
  */
38
58
  templateId?: string;
39
59
  /**
40
- * Variables for template interpolation.
60
+ * Variables for template interpolation. Used together with `templateId`.
41
61
  */
42
62
  variables?: Record<string, string>;
43
63
  /**
44
- * Markdown content for the email.
64
+ * Markdown content for the email. Fallback to `templateId` — use for ad-hoc
65
+ * or dynamically generated content.
45
66
  */
46
67
  markdown?: string;
47
68
  /**
48
- * HTML content for the email.
69
+ * HTML content for the email. Fallback to `templateId` — use for ad-hoc or
70
+ * dynamically generated content.
49
71
  */
50
72
  html?: string;
51
73
  /**
52
- * React component for the email.
74
+ * React component for the email. Fallback to `templateId` — use for ad-hoc
75
+ * or dynamically generated content rendered via React Email.
53
76
  */
54
77
  react?: ReactNode;
55
78
  /**
@@ -99,36 +122,40 @@ interface SendEmailResponse {
99
122
  * Emails API for sending transactional emails.
100
123
  */
101
124
  declare class Emails {
102
- private readonly zupost;
103
- constructor(zupost: Zupost);
125
+ private readonly http;
126
+ constructor(http: HttpClient);
104
127
  /**
105
- * Send an email using template, markdown or HTML content.
128
+ * Send an email.
129
+ *
130
+ * Zupost is template first: prefer sending by `templateId` with `variables`
131
+ * so your content lives in the Zupost dashboard and can be edited without a
132
+ * deploy. Inline `html`, `markdown`, or `react` content is supported as a
133
+ * fallback for ad-hoc or dynamically generated emails.
106
134
  *
107
135
  * @param options - Email options including recipient, sender, and content.
108
- * @returns A promise that resolves to the email response containing emailId.
136
+ * @returns A promise that resolves to the email response containing the email id.
109
137
  *
110
138
  * @example
111
139
  * ```typescript
112
140
  * const zupost = new Zupost('your-api-key');
113
141
  *
114
- * // Send with HTML content
115
- * const { emailId } = await zupost.emails.send({
142
+ * // Recommended: send with a template
143
+ * const { id } = await zupost.emails.send({
116
144
  * from: 'sender@example.com',
117
145
  * to: 'recipient@example.com',
118
- * subject: 'Hello World',
119
- * html: '<h1>Hello!</h1>',
146
+ * templateId: 'welcome-template',
147
+ * variables: { name: 'John' },
120
148
  * });
121
149
  *
122
- * // Send with a template
150
+ * // Fallback: inline HTML
123
151
  * await zupost.emails.send({
124
152
  * from: 'sender@example.com',
125
- * to: ['user1@example.com', 'user2@example.com'],
126
- * subject: 'Welcome!',
127
- * templateId: 'welcome-template',
128
- * variables: { name: 'John' },
153
+ * to: 'recipient@example.com',
154
+ * subject: 'Hello World',
155
+ * html: '<h1>Hello!</h1>',
129
156
  * });
130
157
  *
131
- * // Send with markdown
158
+ * // Fallback: inline markdown
132
159
  * await zupost.emails.send({
133
160
  * from: 'sender@example.com',
134
161
  * to: 'recipient@example.com',
@@ -168,8 +195,8 @@ interface SendCampaignResponse {
168
195
  * Campaigns API for sending email campaigns to audiences.
169
196
  */
170
197
  declare class Campaigns {
171
- private readonly zupost;
172
- constructor(zupost: Zupost);
198
+ private readonly http;
199
+ constructor(http: HttpClient);
173
200
  /**
174
201
  * Send a campaign to selected audiences.
175
202
  *
@@ -199,8 +226,7 @@ interface ZupostOptions {
199
226
  baseUrl?: string;
200
227
  }
201
228
  declare class Zupost {
202
- private readonly headers;
203
- private readonly baseUrl;
229
+ #private;
204
230
  /**
205
231
  * Emails API for sending transactional emails.
206
232
  */
@@ -210,21 +236,27 @@ declare class Zupost {
210
236
  */
211
237
  readonly campaigns: Campaigns;
212
238
  constructor(apiKey: string, options?: ZupostOptions);
213
- /**
214
- * @internal
215
- * Makes a request to the Zupost API.
216
- */
217
- request<T = unknown>(path: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE', body?: unknown): Promise<T>;
218
- /**
219
- * @internal
220
- * Makes a GET request to the Zupost API.
221
- */
222
- get<T = unknown>(path: string): Promise<T>;
223
- /**
224
- * @internal
225
- * Makes a POST request to the Zupost API.
226
- */
227
- post<T = unknown>(path: string, body: unknown): Promise<T>;
228
239
  }
229
240
 
230
- export { type SendCampaignOptions, type SendCampaignResponse, type SendEmailOptions, type SendEmailResponse, Zupost, type ZupostOptions };
241
+ /**
242
+ * Error thrown when the Zupost API returns a non-2xx response.
243
+ */
244
+ declare class ZupostError extends Error {
245
+ readonly status: number;
246
+ readonly statusText: string;
247
+ readonly body: string;
248
+ readonly requestId?: string;
249
+ readonly code?: string;
250
+ constructor(args: {
251
+ message: string;
252
+ status: number;
253
+ statusText: string;
254
+ body: string;
255
+ requestId?: string;
256
+ code?: string;
257
+ });
258
+ /** @internal */
259
+ static fromResponse(response: Response): Promise<ZupostError>;
260
+ }
261
+
262
+ export { type SendCampaignOptions, type SendCampaignResponse, type SendEmailOptions, type SendEmailResponse, Zupost, ZupostError, type ZupostOptions };