@masters-union/outbound-sdk 0.1.2 → 0.1.3
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 +43 -28
- package/dist/index.d.mts +28 -31
- package/dist/index.d.ts +28 -31
- package/dist/index.js +58 -70
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +58 -70
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,18 +11,21 @@ npm install outbound-sdk
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import {
|
|
14
|
+
import { Outbound } from 'outbound-sdk';
|
|
15
15
|
|
|
16
|
-
const outbound = new
|
|
17
|
-
|
|
18
|
-
baseUrl: 'https://api.your-domain.com', // or set OUTBOUND_API_URL env var
|
|
16
|
+
const outbound = new Outbound({
|
|
17
|
+
baseUrl: 'https://api.your-domain.com', // optional, defaults to production
|
|
19
18
|
});
|
|
19
|
+
|
|
20
|
+
const apiKey = 'mu_outbound_...'; // your tenant API key
|
|
20
21
|
```
|
|
21
22
|
|
|
23
|
+
Every method requires an `apiKey` as the first argument, allowing you to use multiple tenants with a single client instance.
|
|
24
|
+
|
|
22
25
|
### Send an Email
|
|
23
26
|
|
|
24
27
|
```ts
|
|
25
|
-
const { jobId, messageId } = await outbound.email.send({
|
|
28
|
+
const { jobId, messageId } = await outbound.email.send(apiKey, {
|
|
26
29
|
toEmail: 'user@example.com',
|
|
27
30
|
fromEmail: 'noreply@company.com',
|
|
28
31
|
emailSubject: 'Welcome!',
|
|
@@ -33,7 +36,7 @@ const { jobId, messageId } = await outbound.email.send({
|
|
|
33
36
|
### Send Bulk Emails
|
|
34
37
|
|
|
35
38
|
```ts
|
|
36
|
-
const result = await outbound.email.bulk({
|
|
39
|
+
const result = await outbound.email.bulk(apiKey, {
|
|
37
40
|
fromEmail: 'noreply@company.com',
|
|
38
41
|
emailSubject: 'Newsletter',
|
|
39
42
|
emails: [
|
|
@@ -47,7 +50,7 @@ const result = await outbound.email.bulk({
|
|
|
47
50
|
### Check Job Status
|
|
48
51
|
|
|
49
52
|
```ts
|
|
50
|
-
const status = await outbound.email.status('job-uuid');
|
|
53
|
+
const status = await outbound.email.status(apiKey, 'job-uuid');
|
|
51
54
|
// status.job, status.recipients
|
|
52
55
|
```
|
|
53
56
|
|
|
@@ -55,7 +58,7 @@ const status = await outbound.email.status('job-uuid');
|
|
|
55
58
|
|
|
56
59
|
```ts
|
|
57
60
|
// Create
|
|
58
|
-
const { template } = await outbound.templates.create({
|
|
61
|
+
const { template } = await outbound.templates.create(apiKey, {
|
|
59
62
|
name: 'welcome',
|
|
60
63
|
subject: 'Welcome {{firstName}}!',
|
|
61
64
|
htmlBody: '<h1>Hello {{firstName}}</h1>',
|
|
@@ -63,10 +66,10 @@ const { template } = await outbound.templates.create({
|
|
|
63
66
|
});
|
|
64
67
|
|
|
65
68
|
// List
|
|
66
|
-
const { templates, total } = await outbound.templates.list({ status: 'active' });
|
|
69
|
+
const { templates, total } = await outbound.templates.list(apiKey, { status: 'active' });
|
|
67
70
|
|
|
68
71
|
// Send using template
|
|
69
|
-
const { jobId } = await outbound.templates.send({
|
|
72
|
+
const { jobId } = await outbound.templates.send(apiKey, {
|
|
70
73
|
templateId: template.id,
|
|
71
74
|
toEmail: 'user@example.com',
|
|
72
75
|
fromEmail: 'noreply@company.com',
|
|
@@ -74,7 +77,7 @@ const { jobId } = await outbound.templates.send({
|
|
|
74
77
|
});
|
|
75
78
|
|
|
76
79
|
// Bulk send using template
|
|
77
|
-
const bulk = await outbound.templates.bulkSend({
|
|
80
|
+
const bulk = await outbound.templates.bulkSend(apiKey, {
|
|
78
81
|
templateId: template.id,
|
|
79
82
|
fromEmail: 'noreply@company.com',
|
|
80
83
|
recipients: [
|
|
@@ -84,7 +87,7 @@ const bulk = await outbound.templates.bulkSend({
|
|
|
84
87
|
});
|
|
85
88
|
|
|
86
89
|
// Preview
|
|
87
|
-
const preview = await outbound.templates.preview(template.id, {
|
|
90
|
+
const preview = await outbound.templates.preview(apiKey, template.id, {
|
|
88
91
|
variables: { firstName: 'John' },
|
|
89
92
|
});
|
|
90
93
|
```
|
|
@@ -93,58 +96,70 @@ const preview = await outbound.templates.preview(template.id, {
|
|
|
93
96
|
|
|
94
97
|
```ts
|
|
95
98
|
// Add
|
|
96
|
-
await outbound.suppressions.add({ email: 'bad@example.com', reason: 'manual' });
|
|
99
|
+
await outbound.suppressions.add(apiKey, { email: 'bad@example.com', reason: 'manual' });
|
|
97
100
|
|
|
98
101
|
// List
|
|
99
|
-
const { suppressions } = await outbound.suppressions.list({ reason: 'bounce' });
|
|
102
|
+
const { suppressions } = await outbound.suppressions.list(apiKey, { reason: 'bounce' });
|
|
100
103
|
|
|
101
104
|
// Remove
|
|
102
|
-
await outbound.suppressions.remove('bad@example.com');
|
|
105
|
+
await outbound.suppressions.remove(apiKey, 'bad@example.com');
|
|
103
106
|
```
|
|
104
107
|
|
|
105
108
|
### Webhooks
|
|
106
109
|
|
|
107
110
|
```ts
|
|
108
111
|
// Create
|
|
109
|
-
const { webhook, secret } = await outbound.webhooks.create({
|
|
112
|
+
const { webhook, secret } = await outbound.webhooks.create(apiKey, {
|
|
110
113
|
url: 'https://myapp.com/webhooks/outbound',
|
|
111
114
|
events: ['delivery', 'bounce', 'complaint'],
|
|
112
115
|
});
|
|
113
116
|
// Store `secret` securely for signature verification
|
|
114
117
|
|
|
115
118
|
// Verify incoming webhook
|
|
116
|
-
const isValid =
|
|
119
|
+
const isValid = Outbound.verifyWebhookSignature(rawBody, signatureHeader, secret);
|
|
117
120
|
```
|
|
118
121
|
|
|
119
122
|
### Dashboard
|
|
120
123
|
|
|
121
124
|
```ts
|
|
122
|
-
const dashboard = await outbound.dashboard.get();
|
|
125
|
+
const dashboard = await outbound.dashboard.get(apiKey);
|
|
123
126
|
// dashboard.last30Days.sent, dashboard.quota, etc.
|
|
124
127
|
|
|
125
|
-
const quota = await outbound.dashboard.quota();
|
|
128
|
+
const quota = await outbound.dashboard.quota(apiKey);
|
|
126
129
|
// quota.dailyUsed, quota.monthlyUsed, quota.remaining
|
|
127
130
|
```
|
|
128
131
|
|
|
132
|
+
### Multi-Tenant Usage
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const outbound = new Outbound();
|
|
136
|
+
|
|
137
|
+
const tenantAKey = 'mu_outbound_tenant_a_...';
|
|
138
|
+
const tenantBKey = 'mu_outbound_tenant_b_...';
|
|
139
|
+
|
|
140
|
+
// Use different API keys for different tenants
|
|
141
|
+
await outbound.email.send(tenantAKey, { ... });
|
|
142
|
+
await outbound.email.send(tenantBKey, { ... });
|
|
143
|
+
```
|
|
144
|
+
|
|
129
145
|
## Configuration
|
|
130
146
|
|
|
131
|
-
| Option |
|
|
132
|
-
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `retryDelay` | - | `1000` | Initial retry delay in ms (exponential backoff) |
|
|
147
|
+
| Option | Default | Description |
|
|
148
|
+
|--------|---------|-------------|
|
|
149
|
+
| `baseUrl` | `https://outbound-api.mastersunion.org` | API base URL |
|
|
150
|
+
| `timeout` | `30000` | Request timeout in ms |
|
|
151
|
+
| `maxRetries` | `3` | Max retries on 429/5xx |
|
|
152
|
+
| `retryDelay` | `1000` | Initial retry delay in ms (exponential backoff) |
|
|
138
153
|
|
|
139
154
|
## Error Handling
|
|
140
155
|
|
|
141
156
|
All errors extend `OutboundError` with `statusCode`, `message`, and `details`:
|
|
142
157
|
|
|
143
158
|
```ts
|
|
144
|
-
import {
|
|
159
|
+
import { Outbound, RateLimitError, NotFoundError } from 'outbound-sdk';
|
|
145
160
|
|
|
146
161
|
try {
|
|
147
|
-
await outbound.email.send({ ... });
|
|
162
|
+
await outbound.email.send(apiKey, { ... });
|
|
148
163
|
} catch (err) {
|
|
149
164
|
if (err instanceof RateLimitError) {
|
|
150
165
|
console.log(`Rate limited. Retry after ${err.retryAfter}s`);
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
interface OutboundConfig {
|
|
2
|
-
apiKey?: string;
|
|
3
2
|
baseUrl?: string;
|
|
4
3
|
timeout?: number;
|
|
5
4
|
maxRetries?: number;
|
|
6
5
|
retryDelay?: number;
|
|
7
6
|
}
|
|
8
7
|
interface ResolvedConfig {
|
|
9
|
-
apiKey: string;
|
|
10
8
|
baseUrl: string;
|
|
11
9
|
timeout: number;
|
|
12
10
|
maxRetries: number;
|
|
@@ -298,10 +296,10 @@ interface QuotaResponse {
|
|
|
298
296
|
declare class HttpClient {
|
|
299
297
|
private config;
|
|
300
298
|
constructor(config: ResolvedConfig);
|
|
301
|
-
get<T>(path: string, params?: Record<string, unknown>): Promise<T>;
|
|
302
|
-
post<T>(path: string, body?: unknown): Promise<T>;
|
|
303
|
-
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
304
|
-
delete<T>(path: string): Promise<T>;
|
|
299
|
+
get<T>(apiKey: string, path: string, params?: Record<string, unknown>): Promise<T>;
|
|
300
|
+
post<T>(apiKey: string, path: string, body?: unknown): Promise<T>;
|
|
301
|
+
patch<T>(apiKey: string, path: string, body?: unknown): Promise<T>;
|
|
302
|
+
delete<T>(apiKey: string, path: string): Promise<T>;
|
|
305
303
|
private request;
|
|
306
304
|
private buildUrl;
|
|
307
305
|
private parseError;
|
|
@@ -311,39 +309,39 @@ declare class HttpClient {
|
|
|
311
309
|
declare class EmailResource {
|
|
312
310
|
private http;
|
|
313
311
|
constructor(http: HttpClient);
|
|
314
|
-
send(params: SendEmailParams): Promise<SendEmailResponse>;
|
|
315
|
-
bulk(params: BulkEmailParams): Promise<BulkEmailResponse>;
|
|
316
|
-
status(jobId: string): Promise<JobStatusResponse>;
|
|
312
|
+
send(apiKey: string, params: SendEmailParams): Promise<SendEmailResponse>;
|
|
313
|
+
bulk(apiKey: string, params: BulkEmailParams): Promise<BulkEmailResponse>;
|
|
314
|
+
status(apiKey: string, jobId: string): Promise<JobStatusResponse>;
|
|
317
315
|
}
|
|
318
316
|
|
|
319
317
|
declare class TemplatesResource {
|
|
320
318
|
private http;
|
|
321
319
|
constructor(http: HttpClient);
|
|
322
|
-
create(params: CreateTemplateParams): Promise<TemplateResponse>;
|
|
323
|
-
list(params?: ListTemplatesParams): Promise<ListTemplatesResponse>;
|
|
324
|
-
listAll(params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template>;
|
|
325
|
-
get(id: string): Promise<TemplateResponse>;
|
|
326
|
-
update(id: string, params: UpdateTemplateParams): Promise<TemplateResponse>;
|
|
327
|
-
delete(id: string): Promise<{
|
|
320
|
+
create(apiKey: string, params: CreateTemplateParams): Promise<TemplateResponse>;
|
|
321
|
+
list(apiKey: string, params?: ListTemplatesParams): Promise<ListTemplatesResponse>;
|
|
322
|
+
listAll(apiKey: string, params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template>;
|
|
323
|
+
get(apiKey: string, id: string): Promise<TemplateResponse>;
|
|
324
|
+
update(apiKey: string, id: string, params: UpdateTemplateParams): Promise<TemplateResponse>;
|
|
325
|
+
delete(apiKey: string, id: string): Promise<{
|
|
328
326
|
message: string;
|
|
329
327
|
id: string;
|
|
330
328
|
}>;
|
|
331
|
-
duplicate(id: string, params?: {
|
|
329
|
+
duplicate(apiKey: string, id: string, params?: {
|
|
332
330
|
name?: string;
|
|
333
331
|
}): Promise<TemplateResponse>;
|
|
334
|
-
preview(id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse>;
|
|
335
|
-
send(params: TemplateSendParams): Promise<SendEmailResponse>;
|
|
336
|
-
bulkSend(params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse>;
|
|
337
|
-
stats(): Promise<TemplateStatsResponse>;
|
|
332
|
+
preview(apiKey: string, id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse>;
|
|
333
|
+
send(apiKey: string, params: TemplateSendParams): Promise<SendEmailResponse>;
|
|
334
|
+
bulkSend(apiKey: string, params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse>;
|
|
335
|
+
stats(apiKey: string): Promise<TemplateStatsResponse>;
|
|
338
336
|
}
|
|
339
337
|
|
|
340
338
|
declare class SuppressionsResource {
|
|
341
339
|
private http;
|
|
342
340
|
constructor(http: HttpClient);
|
|
343
|
-
list(params?: ListSuppressionsParams): Promise<ListSuppressionsResponse>;
|
|
344
|
-
listAll(params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression>;
|
|
345
|
-
add(params: AddSuppressionParams): Promise<SuppressionResponse>;
|
|
346
|
-
remove(email: string): Promise<{
|
|
341
|
+
list(apiKey: string, params?: ListSuppressionsParams): Promise<ListSuppressionsResponse>;
|
|
342
|
+
listAll(apiKey: string, params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression>;
|
|
343
|
+
add(apiKey: string, params: AddSuppressionParams): Promise<SuppressionResponse>;
|
|
344
|
+
remove(apiKey: string, email: string): Promise<{
|
|
347
345
|
message: string;
|
|
348
346
|
}>;
|
|
349
347
|
}
|
|
@@ -351,10 +349,10 @@ declare class SuppressionsResource {
|
|
|
351
349
|
declare class WebhooksResource {
|
|
352
350
|
private http;
|
|
353
351
|
constructor(http: HttpClient);
|
|
354
|
-
create(params: CreateWebhookParams): Promise<CreateWebhookResponse>;
|
|
355
|
-
list(): Promise<ListWebhooksResponse>;
|
|
356
|
-
update(id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse>;
|
|
357
|
-
delete(id: string): Promise<{
|
|
352
|
+
create(apiKey: string, params: CreateWebhookParams): Promise<CreateWebhookResponse>;
|
|
353
|
+
list(apiKey: string): Promise<ListWebhooksResponse>;
|
|
354
|
+
update(apiKey: string, id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse>;
|
|
355
|
+
delete(apiKey: string, id: string): Promise<{
|
|
358
356
|
message: string;
|
|
359
357
|
id: string;
|
|
360
358
|
}>;
|
|
@@ -363,8 +361,8 @@ declare class WebhooksResource {
|
|
|
363
361
|
declare class DashboardResource {
|
|
364
362
|
private http;
|
|
365
363
|
constructor(http: HttpClient);
|
|
366
|
-
get(): Promise<DashboardResponse>;
|
|
367
|
-
quota(): Promise<QuotaResponse>;
|
|
364
|
+
get(apiKey: string): Promise<DashboardResponse>;
|
|
365
|
+
quota(apiKey: string): Promise<QuotaResponse>;
|
|
368
366
|
}
|
|
369
367
|
|
|
370
368
|
declare class Outbound {
|
|
@@ -379,7 +377,6 @@ declare class Outbound {
|
|
|
379
377
|
* Use this in your webhook handler to validate incoming requests.
|
|
380
378
|
*/
|
|
381
379
|
static verifyWebhookSignature(payload: string | Buffer, signature: string, secret: string): boolean;
|
|
382
|
-
private getEnv;
|
|
383
380
|
}
|
|
384
381
|
|
|
385
382
|
declare class OutboundError extends Error {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
interface OutboundConfig {
|
|
2
|
-
apiKey?: string;
|
|
3
2
|
baseUrl?: string;
|
|
4
3
|
timeout?: number;
|
|
5
4
|
maxRetries?: number;
|
|
6
5
|
retryDelay?: number;
|
|
7
6
|
}
|
|
8
7
|
interface ResolvedConfig {
|
|
9
|
-
apiKey: string;
|
|
10
8
|
baseUrl: string;
|
|
11
9
|
timeout: number;
|
|
12
10
|
maxRetries: number;
|
|
@@ -298,10 +296,10 @@ interface QuotaResponse {
|
|
|
298
296
|
declare class HttpClient {
|
|
299
297
|
private config;
|
|
300
298
|
constructor(config: ResolvedConfig);
|
|
301
|
-
get<T>(path: string, params?: Record<string, unknown>): Promise<T>;
|
|
302
|
-
post<T>(path: string, body?: unknown): Promise<T>;
|
|
303
|
-
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
304
|
-
delete<T>(path: string): Promise<T>;
|
|
299
|
+
get<T>(apiKey: string, path: string, params?: Record<string, unknown>): Promise<T>;
|
|
300
|
+
post<T>(apiKey: string, path: string, body?: unknown): Promise<T>;
|
|
301
|
+
patch<T>(apiKey: string, path: string, body?: unknown): Promise<T>;
|
|
302
|
+
delete<T>(apiKey: string, path: string): Promise<T>;
|
|
305
303
|
private request;
|
|
306
304
|
private buildUrl;
|
|
307
305
|
private parseError;
|
|
@@ -311,39 +309,39 @@ declare class HttpClient {
|
|
|
311
309
|
declare class EmailResource {
|
|
312
310
|
private http;
|
|
313
311
|
constructor(http: HttpClient);
|
|
314
|
-
send(params: SendEmailParams): Promise<SendEmailResponse>;
|
|
315
|
-
bulk(params: BulkEmailParams): Promise<BulkEmailResponse>;
|
|
316
|
-
status(jobId: string): Promise<JobStatusResponse>;
|
|
312
|
+
send(apiKey: string, params: SendEmailParams): Promise<SendEmailResponse>;
|
|
313
|
+
bulk(apiKey: string, params: BulkEmailParams): Promise<BulkEmailResponse>;
|
|
314
|
+
status(apiKey: string, jobId: string): Promise<JobStatusResponse>;
|
|
317
315
|
}
|
|
318
316
|
|
|
319
317
|
declare class TemplatesResource {
|
|
320
318
|
private http;
|
|
321
319
|
constructor(http: HttpClient);
|
|
322
|
-
create(params: CreateTemplateParams): Promise<TemplateResponse>;
|
|
323
|
-
list(params?: ListTemplatesParams): Promise<ListTemplatesResponse>;
|
|
324
|
-
listAll(params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template>;
|
|
325
|
-
get(id: string): Promise<TemplateResponse>;
|
|
326
|
-
update(id: string, params: UpdateTemplateParams): Promise<TemplateResponse>;
|
|
327
|
-
delete(id: string): Promise<{
|
|
320
|
+
create(apiKey: string, params: CreateTemplateParams): Promise<TemplateResponse>;
|
|
321
|
+
list(apiKey: string, params?: ListTemplatesParams): Promise<ListTemplatesResponse>;
|
|
322
|
+
listAll(apiKey: string, params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template>;
|
|
323
|
+
get(apiKey: string, id: string): Promise<TemplateResponse>;
|
|
324
|
+
update(apiKey: string, id: string, params: UpdateTemplateParams): Promise<TemplateResponse>;
|
|
325
|
+
delete(apiKey: string, id: string): Promise<{
|
|
328
326
|
message: string;
|
|
329
327
|
id: string;
|
|
330
328
|
}>;
|
|
331
|
-
duplicate(id: string, params?: {
|
|
329
|
+
duplicate(apiKey: string, id: string, params?: {
|
|
332
330
|
name?: string;
|
|
333
331
|
}): Promise<TemplateResponse>;
|
|
334
|
-
preview(id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse>;
|
|
335
|
-
send(params: TemplateSendParams): Promise<SendEmailResponse>;
|
|
336
|
-
bulkSend(params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse>;
|
|
337
|
-
stats(): Promise<TemplateStatsResponse>;
|
|
332
|
+
preview(apiKey: string, id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse>;
|
|
333
|
+
send(apiKey: string, params: TemplateSendParams): Promise<SendEmailResponse>;
|
|
334
|
+
bulkSend(apiKey: string, params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse>;
|
|
335
|
+
stats(apiKey: string): Promise<TemplateStatsResponse>;
|
|
338
336
|
}
|
|
339
337
|
|
|
340
338
|
declare class SuppressionsResource {
|
|
341
339
|
private http;
|
|
342
340
|
constructor(http: HttpClient);
|
|
343
|
-
list(params?: ListSuppressionsParams): Promise<ListSuppressionsResponse>;
|
|
344
|
-
listAll(params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression>;
|
|
345
|
-
add(params: AddSuppressionParams): Promise<SuppressionResponse>;
|
|
346
|
-
remove(email: string): Promise<{
|
|
341
|
+
list(apiKey: string, params?: ListSuppressionsParams): Promise<ListSuppressionsResponse>;
|
|
342
|
+
listAll(apiKey: string, params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression>;
|
|
343
|
+
add(apiKey: string, params: AddSuppressionParams): Promise<SuppressionResponse>;
|
|
344
|
+
remove(apiKey: string, email: string): Promise<{
|
|
347
345
|
message: string;
|
|
348
346
|
}>;
|
|
349
347
|
}
|
|
@@ -351,10 +349,10 @@ declare class SuppressionsResource {
|
|
|
351
349
|
declare class WebhooksResource {
|
|
352
350
|
private http;
|
|
353
351
|
constructor(http: HttpClient);
|
|
354
|
-
create(params: CreateWebhookParams): Promise<CreateWebhookResponse>;
|
|
355
|
-
list(): Promise<ListWebhooksResponse>;
|
|
356
|
-
update(id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse>;
|
|
357
|
-
delete(id: string): Promise<{
|
|
352
|
+
create(apiKey: string, params: CreateWebhookParams): Promise<CreateWebhookResponse>;
|
|
353
|
+
list(apiKey: string): Promise<ListWebhooksResponse>;
|
|
354
|
+
update(apiKey: string, id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse>;
|
|
355
|
+
delete(apiKey: string, id: string): Promise<{
|
|
358
356
|
message: string;
|
|
359
357
|
id: string;
|
|
360
358
|
}>;
|
|
@@ -363,8 +361,8 @@ declare class WebhooksResource {
|
|
|
363
361
|
declare class DashboardResource {
|
|
364
362
|
private http;
|
|
365
363
|
constructor(http: HttpClient);
|
|
366
|
-
get(): Promise<DashboardResponse>;
|
|
367
|
-
quota(): Promise<QuotaResponse>;
|
|
364
|
+
get(apiKey: string): Promise<DashboardResponse>;
|
|
365
|
+
quota(apiKey: string): Promise<QuotaResponse>;
|
|
368
366
|
}
|
|
369
367
|
|
|
370
368
|
declare class Outbound {
|
|
@@ -379,7 +377,6 @@ declare class Outbound {
|
|
|
379
377
|
* Use this in your webhook handler to validate incoming requests.
|
|
380
378
|
*/
|
|
381
379
|
static verifyWebhookSignature(payload: string | Buffer, signature: string, secret: string): boolean;
|
|
382
|
-
private getEnv;
|
|
383
380
|
}
|
|
384
381
|
|
|
385
382
|
declare class OutboundError extends Error {
|
package/dist/index.js
CHANGED
|
@@ -106,19 +106,19 @@ var HttpClient = class {
|
|
|
106
106
|
constructor(config) {
|
|
107
107
|
this.config = config;
|
|
108
108
|
}
|
|
109
|
-
async get(path, params) {
|
|
110
|
-
return this.request("GET", path, { params });
|
|
109
|
+
async get(apiKey, path, params) {
|
|
110
|
+
return this.request(apiKey, "GET", path, { params });
|
|
111
111
|
}
|
|
112
|
-
async post(path, body) {
|
|
113
|
-
return this.request("POST", path, { body });
|
|
112
|
+
async post(apiKey, path, body) {
|
|
113
|
+
return this.request(apiKey, "POST", path, { body });
|
|
114
114
|
}
|
|
115
|
-
async patch(path, body) {
|
|
116
|
-
return this.request("PATCH", path, { body });
|
|
115
|
+
async patch(apiKey, path, body) {
|
|
116
|
+
return this.request(apiKey, "PATCH", path, { body });
|
|
117
117
|
}
|
|
118
|
-
async delete(path) {
|
|
119
|
-
return this.request("DELETE", path);
|
|
118
|
+
async delete(apiKey, path) {
|
|
119
|
+
return this.request(apiKey, "DELETE", path);
|
|
120
120
|
}
|
|
121
|
-
async request(method, path, options) {
|
|
121
|
+
async request(apiKey, method, path, options) {
|
|
122
122
|
let lastError;
|
|
123
123
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
124
124
|
try {
|
|
@@ -128,7 +128,7 @@ var HttpClient = class {
|
|
|
128
128
|
const response = await fetch(url, {
|
|
129
129
|
method,
|
|
130
130
|
headers: {
|
|
131
|
-
"X-Api-Key":
|
|
131
|
+
"X-Api-Key": apiKey,
|
|
132
132
|
"Content-Type": "application/json"
|
|
133
133
|
},
|
|
134
134
|
body: options?.body ? JSON.stringify(options.body) : void 0,
|
|
@@ -234,14 +234,14 @@ var EmailResource = class {
|
|
|
234
234
|
constructor(http) {
|
|
235
235
|
this.http = http;
|
|
236
236
|
}
|
|
237
|
-
async send(params) {
|
|
238
|
-
return this.http.post("/v1/email/send", params);
|
|
237
|
+
async send(apiKey, params) {
|
|
238
|
+
return this.http.post(apiKey, "/v1/email/send", params);
|
|
239
239
|
}
|
|
240
|
-
async bulk(params) {
|
|
241
|
-
return this.http.post("/v1/email/bulk", params);
|
|
240
|
+
async bulk(apiKey, params) {
|
|
241
|
+
return this.http.post(apiKey, "/v1/email/bulk", params);
|
|
242
242
|
}
|
|
243
|
-
async status(jobId) {
|
|
244
|
-
return this.http.get(`/v1/email/status/${encodeURIComponent(jobId)}`);
|
|
243
|
+
async status(apiKey, jobId) {
|
|
244
|
+
return this.http.get(apiKey, `/v1/email/status/${encodeURIComponent(jobId)}`);
|
|
245
245
|
}
|
|
246
246
|
};
|
|
247
247
|
|
|
@@ -250,17 +250,17 @@ var TemplatesResource = class {
|
|
|
250
250
|
constructor(http) {
|
|
251
251
|
this.http = http;
|
|
252
252
|
}
|
|
253
|
-
async create(params) {
|
|
254
|
-
return this.http.post("/v1/email-templates", params);
|
|
253
|
+
async create(apiKey, params) {
|
|
254
|
+
return this.http.post(apiKey, "/v1/email-templates", params);
|
|
255
255
|
}
|
|
256
|
-
async list(params) {
|
|
257
|
-
return this.http.get("/v1/email-templates", params);
|
|
256
|
+
async list(apiKey, params) {
|
|
257
|
+
return this.http.get(apiKey, "/v1/email-templates", params);
|
|
258
258
|
}
|
|
259
|
-
async *listAll(params) {
|
|
259
|
+
async *listAll(apiKey, params) {
|
|
260
260
|
let page = 1;
|
|
261
261
|
const limit = params?.limit || 20;
|
|
262
262
|
while (true) {
|
|
263
|
-
const result = await this.list({ ...params, page, limit });
|
|
263
|
+
const result = await this.list(apiKey, { ...params, page, limit });
|
|
264
264
|
for (const template of result.templates) {
|
|
265
265
|
yield template;
|
|
266
266
|
}
|
|
@@ -268,29 +268,29 @@ var TemplatesResource = class {
|
|
|
268
268
|
page++;
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
|
-
async get(id) {
|
|
272
|
-
return this.http.get(`/v1/email-templates/${encodeURIComponent(id)}`);
|
|
271
|
+
async get(apiKey, id) {
|
|
272
|
+
return this.http.get(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);
|
|
273
273
|
}
|
|
274
|
-
async update(id, params) {
|
|
275
|
-
return this.http.patch(`/v1/email-templates/${encodeURIComponent(id)}`, params);
|
|
274
|
+
async update(apiKey, id, params) {
|
|
275
|
+
return this.http.patch(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`, params);
|
|
276
276
|
}
|
|
277
|
-
async delete(id) {
|
|
278
|
-
return this.http.delete(`/v1/email-templates/${encodeURIComponent(id)}`);
|
|
277
|
+
async delete(apiKey, id) {
|
|
278
|
+
return this.http.delete(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);
|
|
279
279
|
}
|
|
280
|
-
async duplicate(id, params) {
|
|
281
|
-
return this.http.post(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);
|
|
280
|
+
async duplicate(apiKey, id, params) {
|
|
281
|
+
return this.http.post(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);
|
|
282
282
|
}
|
|
283
|
-
async preview(id, params) {
|
|
284
|
-
return this.http.post(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params);
|
|
283
|
+
async preview(apiKey, id, params) {
|
|
284
|
+
return this.http.post(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/preview`, params);
|
|
285
285
|
}
|
|
286
|
-
async send(params) {
|
|
287
|
-
return this.http.post("/v1/email-templates/send", params);
|
|
286
|
+
async send(apiKey, params) {
|
|
287
|
+
return this.http.post(apiKey, "/v1/email-templates/send", params);
|
|
288
288
|
}
|
|
289
|
-
async bulkSend(params) {
|
|
290
|
-
return this.http.post("/v1/email-templates/bulk", params);
|
|
289
|
+
async bulkSend(apiKey, params) {
|
|
290
|
+
return this.http.post(apiKey, "/v1/email-templates/bulk", params);
|
|
291
291
|
}
|
|
292
|
-
async stats() {
|
|
293
|
-
return this.http.get("/v1/email-templates/stats");
|
|
292
|
+
async stats(apiKey) {
|
|
293
|
+
return this.http.get(apiKey, "/v1/email-templates/stats");
|
|
294
294
|
}
|
|
295
295
|
};
|
|
296
296
|
|
|
@@ -299,14 +299,14 @@ var SuppressionsResource = class {
|
|
|
299
299
|
constructor(http) {
|
|
300
300
|
this.http = http;
|
|
301
301
|
}
|
|
302
|
-
async list(params) {
|
|
303
|
-
return this.http.get("/v1/tenants/suppressions", params);
|
|
302
|
+
async list(apiKey, params) {
|
|
303
|
+
return this.http.get(apiKey, "/v1/tenants/suppressions", params);
|
|
304
304
|
}
|
|
305
|
-
async *listAll(params) {
|
|
305
|
+
async *listAll(apiKey, params) {
|
|
306
306
|
let page = 1;
|
|
307
307
|
const limit = params?.limit || 50;
|
|
308
308
|
while (true) {
|
|
309
|
-
const result = await this.list({ ...params, page, limit });
|
|
309
|
+
const result = await this.list(apiKey, { ...params, page, limit });
|
|
310
310
|
for (const suppression of result.suppressions) {
|
|
311
311
|
yield suppression;
|
|
312
312
|
}
|
|
@@ -314,11 +314,11 @@ var SuppressionsResource = class {
|
|
|
314
314
|
page++;
|
|
315
315
|
}
|
|
316
316
|
}
|
|
317
|
-
async add(params) {
|
|
318
|
-
return this.http.post("/v1/tenants/suppressions", params);
|
|
317
|
+
async add(apiKey, params) {
|
|
318
|
+
return this.http.post(apiKey, "/v1/tenants/suppressions", params);
|
|
319
319
|
}
|
|
320
|
-
async remove(email) {
|
|
321
|
-
return this.http.delete(`/v1/tenants/suppressions/${encodeURIComponent(email)}`);
|
|
320
|
+
async remove(apiKey, email) {
|
|
321
|
+
return this.http.delete(apiKey, `/v1/tenants/suppressions/${encodeURIComponent(email)}`);
|
|
322
322
|
}
|
|
323
323
|
};
|
|
324
324
|
|
|
@@ -327,17 +327,17 @@ var WebhooksResource = class {
|
|
|
327
327
|
constructor(http) {
|
|
328
328
|
this.http = http;
|
|
329
329
|
}
|
|
330
|
-
async create(params) {
|
|
331
|
-
return this.http.post("/v1/tenants/webhooks", params);
|
|
330
|
+
async create(apiKey, params) {
|
|
331
|
+
return this.http.post(apiKey, "/v1/tenants/webhooks", params);
|
|
332
332
|
}
|
|
333
|
-
async list() {
|
|
334
|
-
return this.http.get("/v1/tenants/webhooks");
|
|
333
|
+
async list(apiKey) {
|
|
334
|
+
return this.http.get(apiKey, "/v1/tenants/webhooks");
|
|
335
335
|
}
|
|
336
|
-
async update(id, params) {
|
|
337
|
-
return this.http.patch(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);
|
|
336
|
+
async update(apiKey, id, params) {
|
|
337
|
+
return this.http.patch(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);
|
|
338
338
|
}
|
|
339
|
-
async delete(id) {
|
|
340
|
-
return this.http.delete(`/v1/tenants/webhooks/${encodeURIComponent(id)}`);
|
|
339
|
+
async delete(apiKey, id) {
|
|
340
|
+
return this.http.delete(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`);
|
|
341
341
|
}
|
|
342
342
|
};
|
|
343
343
|
|
|
@@ -346,11 +346,11 @@ var DashboardResource = class {
|
|
|
346
346
|
constructor(http) {
|
|
347
347
|
this.http = http;
|
|
348
348
|
}
|
|
349
|
-
async get() {
|
|
350
|
-
return this.http.get("/v1/tenants/dashboard");
|
|
349
|
+
async get(apiKey) {
|
|
350
|
+
return this.http.get(apiKey, "/v1/tenants/dashboard");
|
|
351
351
|
}
|
|
352
|
-
async quota() {
|
|
353
|
-
return this.http.get("/v1/tenants/quota");
|
|
352
|
+
async quota(apiKey) {
|
|
353
|
+
return this.http.get(apiKey, "/v1/tenants/quota");
|
|
354
354
|
}
|
|
355
355
|
};
|
|
356
356
|
|
|
@@ -364,17 +364,11 @@ var Outbound = class {
|
|
|
364
364
|
dashboard;
|
|
365
365
|
constructor(config) {
|
|
366
366
|
const resolved = {
|
|
367
|
-
apiKey: config?.apiKey || this.getEnv("OUTBOUND_API_KEY") || "",
|
|
368
367
|
baseUrl: config?.baseUrl || BASE_URL,
|
|
369
368
|
timeout: config?.timeout ?? 3e4,
|
|
370
369
|
maxRetries: config?.maxRetries ?? 3,
|
|
371
370
|
retryDelay: config?.retryDelay ?? 1e3
|
|
372
371
|
};
|
|
373
|
-
if (!resolved.apiKey) {
|
|
374
|
-
throw new AuthenticationError(
|
|
375
|
-
"API key is required. Pass it to the constructor or set the OUTBOUND_API_KEY environment variable."
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
372
|
const http = new HttpClient(resolved);
|
|
379
373
|
this.email = new EmailResource(http);
|
|
380
374
|
this.templates = new TemplatesResource(http);
|
|
@@ -395,12 +389,6 @@ var Outbound = class {
|
|
|
395
389
|
return false;
|
|
396
390
|
}
|
|
397
391
|
}
|
|
398
|
-
getEnv(key) {
|
|
399
|
-
if (typeof process !== "undefined" && process.env) {
|
|
400
|
-
return process.env[key];
|
|
401
|
-
}
|
|
402
|
-
return void 0;
|
|
403
|
-
}
|
|
404
392
|
};
|
|
405
393
|
// Annotate the CommonJS export names for ESM import in node:
|
|
406
394
|
0 && (module.exports = {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/client.ts"],"sourcesContent":["export { Outbound } from './client';\n\n// Error classes\nexport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\n// All types\nexport type {\n OutboundConfig,\n ResolvedConfig,\n SendEmailParams,\n Attachment,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailRecipient,\n BulkEmailResponse,\n JobStatusResponse,\n EmailRecipientStatus,\n EmailStatus,\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n TemplateBulkSendParams,\n TemplateBulkRecipient,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n ListSuppressionsParams,\n ListSuppressionsResponse,\n Suppression,\n AddSuppressionParams,\n SuppressionResponse,\n WebhookEvent,\n CreateWebhookParams,\n UpdateWebhookParams,\n Webhook,\n CreateWebhookResponse,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n DashboardResponse,\n QuotaResponse,\n} from './types';\n","export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(path: string, params?: Record<string, unknown>): Promise<T> {\n return this.request<T>('GET', path, { params });\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('POST', path, { body });\n }\n\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PATCH', path, { body });\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>('DELETE', path);\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': this.config.apiKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n JobStatusResponse,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(params: SendEmailParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email/send', params);\n }\n\n async bulk(params: BulkEmailParams): Promise<BulkEmailResponse> {\n return this.http.post<BulkEmailResponse>('/v1/email/bulk', params);\n }\n\n async status(jobId: string): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(`/v1/email/status/${encodeURIComponent(jobId)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateTemplateParams): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>('/v1/email-templates', params);\n }\n\n async list(params?: ListTemplatesParams): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>('/v1/email-templates', params as Record<string, unknown>);\n }\n\n async *listAll(params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list({ ...params, page, limit });\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(id: string): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async update(id: string, params: UpdateTemplateParams): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, params);\n }\n\n async delete(id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async duplicate(id: string, params?: { name?: string }): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);\n }\n\n async preview(id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params);\n }\n\n async send(params: TemplateSendParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email-templates/send', params);\n }\n\n async bulkSend(params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse> {\n return this.http.post<TemplateBulkSendResponse>('/v1/email-templates/bulk', params);\n }\n\n async stats(): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>('/v1/email-templates/stats');\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n} from '../types';\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(params?: ListSuppressionsParams): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>('/v1/tenants/suppressions', params as Record<string, unknown>);\n }\n\n async *listAll(params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list({ ...params, page, limit });\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n async add(params: AddSuppressionParams): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>('/v1/tenants/suppressions', params);\n }\n\n async remove(email: string): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(`/v1/tenants/suppressions/${encodeURIComponent(email)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateWebhookParams): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>('/v1/tenants/webhooks', params);\n }\n\n async list(): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>('/v1/tenants/webhooks');\n }\n\n async update(id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);\n }\n\n async delete(id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>('/v1/tenants/dashboard');\n }\n\n async quota(): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>('/v1/tenants/quota');\n }\n}\n","import { HttpClient } from './http';\nimport { AuthenticationError } from './errors';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.mastersunion.org';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n apiKey: config?.apiKey || this.getEnv('OUTBOUND_API_KEY') || '',\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n if (!resolved.apiKey) {\n throw new AuthenticationError(\n 'API key is required. Pass it to the constructor or set the OUTBOUND_API_KEY environment variable.',\n );\n }\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n\n private getEnv(key: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[key];\n }\n return undefined;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/client.ts"],"sourcesContent":["export { Outbound } from './client';\n\n// Error classes\nexport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\n// All types\nexport type {\n OutboundConfig,\n ResolvedConfig,\n SendEmailParams,\n Attachment,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailRecipient,\n BulkEmailResponse,\n JobStatusResponse,\n EmailRecipientStatus,\n EmailStatus,\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n TemplateBulkSendParams,\n TemplateBulkRecipient,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n ListSuppressionsParams,\n ListSuppressionsResponse,\n Suppression,\n AddSuppressionParams,\n SuppressionResponse,\n WebhookEvent,\n CreateWebhookParams,\n UpdateWebhookParams,\n Webhook,\n CreateWebhookResponse,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n DashboardResponse,\n QuotaResponse,\n} from './types';\n","export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(apiKey: string, path: string, params?: Record<string, unknown>): Promise<T> {\n return this.request<T>(apiKey, 'GET', path, { params });\n }\n\n async post<T>(apiKey: string, path: string, body?: unknown): Promise<T> {\n return this.request<T>(apiKey, 'POST', path, { body });\n }\n\n async patch<T>(apiKey: string, path: string, body?: unknown): Promise<T> {\n return this.request<T>(apiKey, 'PATCH', path, { body });\n }\n\n async delete<T>(apiKey: string, path: string): Promise<T> {\n return this.request<T>(apiKey, 'DELETE', path);\n }\n\n private async request<T>(apiKey: string, method: string, path: string, options?: RequestOptions): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': apiKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n JobStatusResponse,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(apiKey: string, params: SendEmailParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>(apiKey, '/v1/email/send', params);\n }\n\n async bulk(apiKey: string, params: BulkEmailParams): Promise<BulkEmailResponse> {\n return this.http.post<BulkEmailResponse>(apiKey, '/v1/email/bulk', params);\n }\n\n async status(apiKey: string, jobId: string): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(apiKey, `/v1/email/status/${encodeURIComponent(jobId)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(apiKey: string, params: CreateTemplateParams): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(apiKey, '/v1/email-templates', params);\n }\n\n async list(apiKey: string, params?: ListTemplatesParams): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>(apiKey, '/v1/email-templates', params as Record<string, unknown>);\n }\n\n async *listAll(apiKey: string, params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list(apiKey, { ...params, page, limit });\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(apiKey: string, id: string): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async update(apiKey: string, id: string, params: UpdateTemplateParams): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`, params);\n }\n\n async delete(apiKey: string, id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async duplicate(apiKey: string, id: string, params?: { name?: string }): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);\n }\n\n async preview(apiKey: string, id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/preview`, params);\n }\n\n async send(apiKey: string, params: TemplateSendParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>(apiKey, '/v1/email-templates/send', params);\n }\n\n async bulkSend(apiKey: string, params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse> {\n return this.http.post<TemplateBulkSendResponse>(apiKey, '/v1/email-templates/bulk', params);\n }\n\n async stats(apiKey: string): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>(apiKey, '/v1/email-templates/stats');\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n} from '../types';\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(apiKey: string, params?: ListSuppressionsParams): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>(apiKey, '/v1/tenants/suppressions', params as Record<string, unknown>);\n }\n\n async *listAll(apiKey: string, params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list(apiKey, { ...params, page, limit });\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n async add(apiKey: string, params: AddSuppressionParams): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>(apiKey, '/v1/tenants/suppressions', params);\n }\n\n async remove(apiKey: string, email: string): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(apiKey, `/v1/tenants/suppressions/${encodeURIComponent(email)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(apiKey: string, params: CreateWebhookParams): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>(apiKey, '/v1/tenants/webhooks', params);\n }\n\n async list(apiKey: string): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>(apiKey, '/v1/tenants/webhooks');\n }\n\n async update(apiKey: string, id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);\n }\n\n async delete(apiKey: string, id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(apiKey: string): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>(apiKey, '/v1/tenants/dashboard');\n }\n\n async quota(apiKey: string): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>(apiKey, '/v1/tenants/quota');\n }\n}\n","import { HttpClient } from './http';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.mastersunion.org';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -77,19 +77,19 @@ var HttpClient = class {
|
|
|
77
77
|
constructor(config) {
|
|
78
78
|
this.config = config;
|
|
79
79
|
}
|
|
80
|
-
async get(path, params) {
|
|
81
|
-
return this.request("GET", path, { params });
|
|
80
|
+
async get(apiKey, path, params) {
|
|
81
|
+
return this.request(apiKey, "GET", path, { params });
|
|
82
82
|
}
|
|
83
|
-
async post(path, body) {
|
|
84
|
-
return this.request("POST", path, { body });
|
|
83
|
+
async post(apiKey, path, body) {
|
|
84
|
+
return this.request(apiKey, "POST", path, { body });
|
|
85
85
|
}
|
|
86
|
-
async patch(path, body) {
|
|
87
|
-
return this.request("PATCH", path, { body });
|
|
86
|
+
async patch(apiKey, path, body) {
|
|
87
|
+
return this.request(apiKey, "PATCH", path, { body });
|
|
88
88
|
}
|
|
89
|
-
async delete(path) {
|
|
90
|
-
return this.request("DELETE", path);
|
|
89
|
+
async delete(apiKey, path) {
|
|
90
|
+
return this.request(apiKey, "DELETE", path);
|
|
91
91
|
}
|
|
92
|
-
async request(method, path, options) {
|
|
92
|
+
async request(apiKey, method, path, options) {
|
|
93
93
|
let lastError;
|
|
94
94
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
95
95
|
try {
|
|
@@ -99,7 +99,7 @@ var HttpClient = class {
|
|
|
99
99
|
const response = await fetch(url, {
|
|
100
100
|
method,
|
|
101
101
|
headers: {
|
|
102
|
-
"X-Api-Key":
|
|
102
|
+
"X-Api-Key": apiKey,
|
|
103
103
|
"Content-Type": "application/json"
|
|
104
104
|
},
|
|
105
105
|
body: options?.body ? JSON.stringify(options.body) : void 0,
|
|
@@ -205,14 +205,14 @@ var EmailResource = class {
|
|
|
205
205
|
constructor(http) {
|
|
206
206
|
this.http = http;
|
|
207
207
|
}
|
|
208
|
-
async send(params) {
|
|
209
|
-
return this.http.post("/v1/email/send", params);
|
|
208
|
+
async send(apiKey, params) {
|
|
209
|
+
return this.http.post(apiKey, "/v1/email/send", params);
|
|
210
210
|
}
|
|
211
|
-
async bulk(params) {
|
|
212
|
-
return this.http.post("/v1/email/bulk", params);
|
|
211
|
+
async bulk(apiKey, params) {
|
|
212
|
+
return this.http.post(apiKey, "/v1/email/bulk", params);
|
|
213
213
|
}
|
|
214
|
-
async status(jobId) {
|
|
215
|
-
return this.http.get(`/v1/email/status/${encodeURIComponent(jobId)}`);
|
|
214
|
+
async status(apiKey, jobId) {
|
|
215
|
+
return this.http.get(apiKey, `/v1/email/status/${encodeURIComponent(jobId)}`);
|
|
216
216
|
}
|
|
217
217
|
};
|
|
218
218
|
|
|
@@ -221,17 +221,17 @@ var TemplatesResource = class {
|
|
|
221
221
|
constructor(http) {
|
|
222
222
|
this.http = http;
|
|
223
223
|
}
|
|
224
|
-
async create(params) {
|
|
225
|
-
return this.http.post("/v1/email-templates", params);
|
|
224
|
+
async create(apiKey, params) {
|
|
225
|
+
return this.http.post(apiKey, "/v1/email-templates", params);
|
|
226
226
|
}
|
|
227
|
-
async list(params) {
|
|
228
|
-
return this.http.get("/v1/email-templates", params);
|
|
227
|
+
async list(apiKey, params) {
|
|
228
|
+
return this.http.get(apiKey, "/v1/email-templates", params);
|
|
229
229
|
}
|
|
230
|
-
async *listAll(params) {
|
|
230
|
+
async *listAll(apiKey, params) {
|
|
231
231
|
let page = 1;
|
|
232
232
|
const limit = params?.limit || 20;
|
|
233
233
|
while (true) {
|
|
234
|
-
const result = await this.list({ ...params, page, limit });
|
|
234
|
+
const result = await this.list(apiKey, { ...params, page, limit });
|
|
235
235
|
for (const template of result.templates) {
|
|
236
236
|
yield template;
|
|
237
237
|
}
|
|
@@ -239,29 +239,29 @@ var TemplatesResource = class {
|
|
|
239
239
|
page++;
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
|
-
async get(id) {
|
|
243
|
-
return this.http.get(`/v1/email-templates/${encodeURIComponent(id)}`);
|
|
242
|
+
async get(apiKey, id) {
|
|
243
|
+
return this.http.get(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);
|
|
244
244
|
}
|
|
245
|
-
async update(id, params) {
|
|
246
|
-
return this.http.patch(`/v1/email-templates/${encodeURIComponent(id)}`, params);
|
|
245
|
+
async update(apiKey, id, params) {
|
|
246
|
+
return this.http.patch(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`, params);
|
|
247
247
|
}
|
|
248
|
-
async delete(id) {
|
|
249
|
-
return this.http.delete(`/v1/email-templates/${encodeURIComponent(id)}`);
|
|
248
|
+
async delete(apiKey, id) {
|
|
249
|
+
return this.http.delete(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);
|
|
250
250
|
}
|
|
251
|
-
async duplicate(id, params) {
|
|
252
|
-
return this.http.post(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);
|
|
251
|
+
async duplicate(apiKey, id, params) {
|
|
252
|
+
return this.http.post(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);
|
|
253
253
|
}
|
|
254
|
-
async preview(id, params) {
|
|
255
|
-
return this.http.post(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params);
|
|
254
|
+
async preview(apiKey, id, params) {
|
|
255
|
+
return this.http.post(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/preview`, params);
|
|
256
256
|
}
|
|
257
|
-
async send(params) {
|
|
258
|
-
return this.http.post("/v1/email-templates/send", params);
|
|
257
|
+
async send(apiKey, params) {
|
|
258
|
+
return this.http.post(apiKey, "/v1/email-templates/send", params);
|
|
259
259
|
}
|
|
260
|
-
async bulkSend(params) {
|
|
261
|
-
return this.http.post("/v1/email-templates/bulk", params);
|
|
260
|
+
async bulkSend(apiKey, params) {
|
|
261
|
+
return this.http.post(apiKey, "/v1/email-templates/bulk", params);
|
|
262
262
|
}
|
|
263
|
-
async stats() {
|
|
264
|
-
return this.http.get("/v1/email-templates/stats");
|
|
263
|
+
async stats(apiKey) {
|
|
264
|
+
return this.http.get(apiKey, "/v1/email-templates/stats");
|
|
265
265
|
}
|
|
266
266
|
};
|
|
267
267
|
|
|
@@ -270,14 +270,14 @@ var SuppressionsResource = class {
|
|
|
270
270
|
constructor(http) {
|
|
271
271
|
this.http = http;
|
|
272
272
|
}
|
|
273
|
-
async list(params) {
|
|
274
|
-
return this.http.get("/v1/tenants/suppressions", params);
|
|
273
|
+
async list(apiKey, params) {
|
|
274
|
+
return this.http.get(apiKey, "/v1/tenants/suppressions", params);
|
|
275
275
|
}
|
|
276
|
-
async *listAll(params) {
|
|
276
|
+
async *listAll(apiKey, params) {
|
|
277
277
|
let page = 1;
|
|
278
278
|
const limit = params?.limit || 50;
|
|
279
279
|
while (true) {
|
|
280
|
-
const result = await this.list({ ...params, page, limit });
|
|
280
|
+
const result = await this.list(apiKey, { ...params, page, limit });
|
|
281
281
|
for (const suppression of result.suppressions) {
|
|
282
282
|
yield suppression;
|
|
283
283
|
}
|
|
@@ -285,11 +285,11 @@ var SuppressionsResource = class {
|
|
|
285
285
|
page++;
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
async add(params) {
|
|
289
|
-
return this.http.post("/v1/tenants/suppressions", params);
|
|
288
|
+
async add(apiKey, params) {
|
|
289
|
+
return this.http.post(apiKey, "/v1/tenants/suppressions", params);
|
|
290
290
|
}
|
|
291
|
-
async remove(email) {
|
|
292
|
-
return this.http.delete(`/v1/tenants/suppressions/${encodeURIComponent(email)}`);
|
|
291
|
+
async remove(apiKey, email) {
|
|
292
|
+
return this.http.delete(apiKey, `/v1/tenants/suppressions/${encodeURIComponent(email)}`);
|
|
293
293
|
}
|
|
294
294
|
};
|
|
295
295
|
|
|
@@ -298,17 +298,17 @@ var WebhooksResource = class {
|
|
|
298
298
|
constructor(http) {
|
|
299
299
|
this.http = http;
|
|
300
300
|
}
|
|
301
|
-
async create(params) {
|
|
302
|
-
return this.http.post("/v1/tenants/webhooks", params);
|
|
301
|
+
async create(apiKey, params) {
|
|
302
|
+
return this.http.post(apiKey, "/v1/tenants/webhooks", params);
|
|
303
303
|
}
|
|
304
|
-
async list() {
|
|
305
|
-
return this.http.get("/v1/tenants/webhooks");
|
|
304
|
+
async list(apiKey) {
|
|
305
|
+
return this.http.get(apiKey, "/v1/tenants/webhooks");
|
|
306
306
|
}
|
|
307
|
-
async update(id, params) {
|
|
308
|
-
return this.http.patch(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);
|
|
307
|
+
async update(apiKey, id, params) {
|
|
308
|
+
return this.http.patch(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);
|
|
309
309
|
}
|
|
310
|
-
async delete(id) {
|
|
311
|
-
return this.http.delete(`/v1/tenants/webhooks/${encodeURIComponent(id)}`);
|
|
310
|
+
async delete(apiKey, id) {
|
|
311
|
+
return this.http.delete(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`);
|
|
312
312
|
}
|
|
313
313
|
};
|
|
314
314
|
|
|
@@ -317,11 +317,11 @@ var DashboardResource = class {
|
|
|
317
317
|
constructor(http) {
|
|
318
318
|
this.http = http;
|
|
319
319
|
}
|
|
320
|
-
async get() {
|
|
321
|
-
return this.http.get("/v1/tenants/dashboard");
|
|
320
|
+
async get(apiKey) {
|
|
321
|
+
return this.http.get(apiKey, "/v1/tenants/dashboard");
|
|
322
322
|
}
|
|
323
|
-
async quota() {
|
|
324
|
-
return this.http.get("/v1/tenants/quota");
|
|
323
|
+
async quota(apiKey) {
|
|
324
|
+
return this.http.get(apiKey, "/v1/tenants/quota");
|
|
325
325
|
}
|
|
326
326
|
};
|
|
327
327
|
|
|
@@ -335,17 +335,11 @@ var Outbound = class {
|
|
|
335
335
|
dashboard;
|
|
336
336
|
constructor(config) {
|
|
337
337
|
const resolved = {
|
|
338
|
-
apiKey: config?.apiKey || this.getEnv("OUTBOUND_API_KEY") || "",
|
|
339
338
|
baseUrl: config?.baseUrl || BASE_URL,
|
|
340
339
|
timeout: config?.timeout ?? 3e4,
|
|
341
340
|
maxRetries: config?.maxRetries ?? 3,
|
|
342
341
|
retryDelay: config?.retryDelay ?? 1e3
|
|
343
342
|
};
|
|
344
|
-
if (!resolved.apiKey) {
|
|
345
|
-
throw new AuthenticationError(
|
|
346
|
-
"API key is required. Pass it to the constructor or set the OUTBOUND_API_KEY environment variable."
|
|
347
|
-
);
|
|
348
|
-
}
|
|
349
343
|
const http = new HttpClient(resolved);
|
|
350
344
|
this.email = new EmailResource(http);
|
|
351
345
|
this.templates = new TemplatesResource(http);
|
|
@@ -366,12 +360,6 @@ var Outbound = class {
|
|
|
366
360
|
return false;
|
|
367
361
|
}
|
|
368
362
|
}
|
|
369
|
-
getEnv(key) {
|
|
370
|
-
if (typeof process !== "undefined" && process.env) {
|
|
371
|
-
return process.env[key];
|
|
372
|
-
}
|
|
373
|
-
return void 0;
|
|
374
|
-
}
|
|
375
363
|
};
|
|
376
364
|
export {
|
|
377
365
|
AuthenticationError,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/client.ts"],"sourcesContent":["export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(path: string, params?: Record<string, unknown>): Promise<T> {\n return this.request<T>('GET', path, { params });\n }\n\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('POST', path, { body });\n }\n\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PATCH', path, { body });\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>('DELETE', path);\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': this.config.apiKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n JobStatusResponse,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(params: SendEmailParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email/send', params);\n }\n\n async bulk(params: BulkEmailParams): Promise<BulkEmailResponse> {\n return this.http.post<BulkEmailResponse>('/v1/email/bulk', params);\n }\n\n async status(jobId: string): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(`/v1/email/status/${encodeURIComponent(jobId)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateTemplateParams): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>('/v1/email-templates', params);\n }\n\n async list(params?: ListTemplatesParams): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>('/v1/email-templates', params as Record<string, unknown>);\n }\n\n async *listAll(params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list({ ...params, page, limit });\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(id: string): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async update(id: string, params: UpdateTemplateParams): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}`, params);\n }\n\n async delete(id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async duplicate(id: string, params?: { name?: string }): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(`/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);\n }\n\n async preview(id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(`/v1/email-templates/${encodeURIComponent(id)}/preview`, params);\n }\n\n async send(params: TemplateSendParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>('/v1/email-templates/send', params);\n }\n\n async bulkSend(params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse> {\n return this.http.post<TemplateBulkSendResponse>('/v1/email-templates/bulk', params);\n }\n\n async stats(): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>('/v1/email-templates/stats');\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n} from '../types';\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(params?: ListSuppressionsParams): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>('/v1/tenants/suppressions', params as Record<string, unknown>);\n }\n\n async *listAll(params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list({ ...params, page, limit });\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n async add(params: AddSuppressionParams): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>('/v1/tenants/suppressions', params);\n }\n\n async remove(email: string): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(`/v1/tenants/suppressions/${encodeURIComponent(email)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(params: CreateWebhookParams): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>('/v1/tenants/webhooks', params);\n }\n\n async list(): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>('/v1/tenants/webhooks');\n }\n\n async update(id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);\n }\n\n async delete(id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(`/v1/tenants/webhooks/${encodeURIComponent(id)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>('/v1/tenants/dashboard');\n }\n\n async quota(): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>('/v1/tenants/quota');\n }\n}\n","import { HttpClient } from './http';\nimport { AuthenticationError } from './errors';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.mastersunion.org';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n apiKey: config?.apiKey || this.getEnv('OUTBOUND_API_KEY') || '',\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n if (!resolved.apiKey) {\n throw new AuthenticationError(\n 'API key is required. Pass it to the constructor or set the OUTBOUND_API_KEY environment variable.',\n );\n }\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n\n private getEnv(key: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[key];\n }\n return undefined;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/email.ts","../src/resources/templates.ts","../src/resources/suppressions.ts","../src/resources/webhooks.ts","../src/resources/dashboard.ts","../src/client.ts"],"sourcesContent":["export class OutboundError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly details?: unknown,\n public readonly requestId?: string,\n ) {\n super(message);\n this.name = 'OutboundError';\n }\n}\n\nexport class BadRequestError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 400, details, requestId);\n this.name = 'BadRequestError';\n }\n}\n\nexport class AuthenticationError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 401, details, requestId);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 403, details, requestId);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 404, details, requestId);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ConflictError extends OutboundError {\n constructor(message: string, details?: unknown, requestId?: string) {\n super(message, 409, details, requestId);\n this.name = 'ConflictError';\n }\n}\n\nexport class RateLimitError extends OutboundError {\n public readonly retryAfter?: number;\n\n constructor(message: string, retryAfter?: number, details?: unknown, requestId?: string) {\n super(message, 429, details, requestId);\n this.name = 'RateLimitError';\n this.retryAfter = retryAfter;\n }\n}\n\nexport class ServerError extends OutboundError {\n constructor(message: string, statusCode: number = 500, details?: unknown, requestId?: string) {\n super(message, statusCode, details, requestId);\n this.name = 'ServerError';\n }\n}\n\nexport class TimeoutError extends OutboundError {\n constructor(message: string = 'Request timed out') {\n super(message, 0);\n this.name = 'TimeoutError';\n }\n}\n\nexport class NetworkError extends OutboundError {\n constructor(message: string = 'Network request failed') {\n super(message, 0);\n this.name = 'NetworkError';\n }\n}\n","import type { ResolvedConfig } from './types';\nimport {\n OutboundError,\n BadRequestError,\n AuthenticationError,\n ForbiddenError,\n NotFoundError,\n ConflictError,\n RateLimitError,\n ServerError,\n TimeoutError,\n NetworkError,\n} from './errors';\n\nexport interface RequestOptions {\n body?: unknown;\n params?: Record<string, unknown>;\n}\n\nexport class HttpClient {\n constructor(private config: ResolvedConfig) {}\n\n async get<T>(apiKey: string, path: string, params?: Record<string, unknown>): Promise<T> {\n return this.request<T>(apiKey, 'GET', path, { params });\n }\n\n async post<T>(apiKey: string, path: string, body?: unknown): Promise<T> {\n return this.request<T>(apiKey, 'POST', path, { body });\n }\n\n async patch<T>(apiKey: string, path: string, body?: unknown): Promise<T> {\n return this.request<T>(apiKey, 'PATCH', path, { body });\n }\n\n async delete<T>(apiKey: string, path: string): Promise<T> {\n return this.request<T>(apiKey, 'DELETE', path);\n }\n\n private async request<T>(apiKey: string, method: string, path: string, options?: RequestOptions): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const url = this.buildUrl(path, options?.params);\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n const response = await fetch(url, {\n method,\n headers: {\n 'X-Api-Key': apiKey,\n 'Content-Type': 'application/json',\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n const error = await this.parseError(response);\n\n // Only retry on 429 and 5xx\n if (response.status === 429 || response.status >= 500) {\n lastError = error;\n\n if (attempt < this.config.maxRetries) {\n const retryAfter = error instanceof RateLimitError && error.retryAfter\n ? error.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n\n await this.sleep(retryAfter);\n continue;\n }\n }\n\n throw error;\n } catch (err) {\n if (err instanceof OutboundError) {\n // Already a typed error from parseError — check if retryable\n if ((err.statusCode === 429 || err.statusCode >= 500) && attempt < this.config.maxRetries) {\n lastError = err;\n const retryAfter = err instanceof RateLimitError && err.retryAfter\n ? err.retryAfter * 1000\n : this.config.retryDelay * Math.pow(2, attempt);\n await this.sleep(retryAfter);\n continue;\n }\n throw err;\n }\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n lastError = new TimeoutError(`Request timed out after ${this.config.timeout}ms`);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n\n lastError = new NetworkError((err as Error).message);\n if (attempt < this.config.maxRetries) {\n await this.sleep(this.config.retryDelay * Math.pow(2, attempt));\n continue;\n }\n throw lastError;\n }\n }\n\n throw lastError || new NetworkError('Request failed after retries');\n }\n\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const base = this.config.baseUrl.replace(/\\/+$/, '');\n const url = new URL(`${base}${path}`);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private async parseError(response: Response): Promise<OutboundError> {\n let body: { error?: string; message?: string; details?: unknown } = {};\n const requestId = response.headers.get('x-request-id') || undefined;\n\n try {\n body = (await response.json()) as typeof body;\n } catch {\n // Response may not be JSON\n }\n\n const message = body.error || body.message || `HTTP ${response.status}`;\n const details = body.details;\n\n switch (response.status) {\n case 400:\n return new BadRequestError(message, details, requestId);\n case 401:\n return new AuthenticationError(message, details, requestId);\n case 403:\n return new ForbiddenError(message, details, requestId);\n case 404:\n return new NotFoundError(message, details, requestId);\n case 409:\n return new ConflictError(message, details, requestId);\n case 429: {\n const retryAfter = response.headers.get('retry-after');\n return new RateLimitError(\n message,\n retryAfter ? parseInt(retryAfter, 10) : undefined,\n details,\n requestId,\n );\n }\n default:\n if (response.status >= 500) {\n return new ServerError(message, response.status, details, requestId);\n }\n return new OutboundError(message, response.status, details, requestId);\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n SendEmailParams,\n SendEmailResponse,\n BulkEmailParams,\n BulkEmailResponse,\n JobStatusResponse,\n} from '../types';\n\nexport class EmailResource {\n constructor(private http: HttpClient) {}\n\n async send(apiKey: string, params: SendEmailParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>(apiKey, '/v1/email/send', params);\n }\n\n async bulk(apiKey: string, params: BulkEmailParams): Promise<BulkEmailResponse> {\n return this.http.post<BulkEmailResponse>(apiKey, '/v1/email/bulk', params);\n }\n\n async status(apiKey: string, jobId: string): Promise<JobStatusResponse> {\n return this.http.get<JobStatusResponse>(apiKey, `/v1/email/status/${encodeURIComponent(jobId)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateTemplateParams,\n UpdateTemplateParams,\n ListTemplatesParams,\n ListTemplatesResponse,\n Template,\n TemplateResponse,\n TemplateSendParams,\n SendEmailResponse,\n TemplateBulkSendParams,\n TemplateBulkSendResponse,\n TemplatePreviewParams,\n TemplatePreviewResponse,\n TemplateStatsResponse,\n} from '../types';\n\nexport class TemplatesResource {\n constructor(private http: HttpClient) {}\n\n async create(apiKey: string, params: CreateTemplateParams): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(apiKey, '/v1/email-templates', params);\n }\n\n async list(apiKey: string, params?: ListTemplatesParams): Promise<ListTemplatesResponse> {\n return this.http.get<ListTemplatesResponse>(apiKey, '/v1/email-templates', params as Record<string, unknown>);\n }\n\n async *listAll(apiKey: string, params?: Omit<ListTemplatesParams, 'page'>): AsyncGenerator<Template> {\n let page = 1;\n const limit = params?.limit || 20;\n\n while (true) {\n const result = await this.list(apiKey, { ...params, page, limit });\n for (const template of result.templates) {\n yield template;\n }\n if (result.templates.length < limit) break;\n page++;\n }\n }\n\n async get(apiKey: string, id: string): Promise<TemplateResponse> {\n return this.http.get<TemplateResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async update(apiKey: string, id: string, params: UpdateTemplateParams): Promise<TemplateResponse> {\n return this.http.patch<TemplateResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`, params);\n }\n\n async delete(apiKey: string, id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}`);\n }\n\n async duplicate(apiKey: string, id: string, params?: { name?: string }): Promise<TemplateResponse> {\n return this.http.post<TemplateResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/duplicate`, params);\n }\n\n async preview(apiKey: string, id: string, params?: TemplatePreviewParams): Promise<TemplatePreviewResponse> {\n return this.http.post<TemplatePreviewResponse>(apiKey, `/v1/email-templates/${encodeURIComponent(id)}/preview`, params);\n }\n\n async send(apiKey: string, params: TemplateSendParams): Promise<SendEmailResponse> {\n return this.http.post<SendEmailResponse>(apiKey, '/v1/email-templates/send', params);\n }\n\n async bulkSend(apiKey: string, params: TemplateBulkSendParams): Promise<TemplateBulkSendResponse> {\n return this.http.post<TemplateBulkSendResponse>(apiKey, '/v1/email-templates/bulk', params);\n }\n\n async stats(apiKey: string): Promise<TemplateStatsResponse> {\n return this.http.get<TemplateStatsResponse>(apiKey, '/v1/email-templates/stats');\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n ListSuppressionsParams,\n ListSuppressionsResponse,\n AddSuppressionParams,\n SuppressionResponse,\n Suppression,\n} from '../types';\n\nexport class SuppressionsResource {\n constructor(private http: HttpClient) {}\n\n async list(apiKey: string, params?: ListSuppressionsParams): Promise<ListSuppressionsResponse> {\n return this.http.get<ListSuppressionsResponse>(apiKey, '/v1/tenants/suppressions', params as Record<string, unknown>);\n }\n\n async *listAll(apiKey: string, params?: Omit<ListSuppressionsParams, 'page'>): AsyncGenerator<Suppression> {\n let page = 1;\n const limit = params?.limit || 50;\n\n while (true) {\n const result = await this.list(apiKey, { ...params, page, limit });\n for (const suppression of result.suppressions) {\n yield suppression;\n }\n if (result.suppressions.length < limit) break;\n page++;\n }\n }\n\n async add(apiKey: string, params: AddSuppressionParams): Promise<SuppressionResponse> {\n return this.http.post<SuppressionResponse>(apiKey, '/v1/tenants/suppressions', params);\n }\n\n async remove(apiKey: string, email: string): Promise<{ message: string }> {\n return this.http.delete<{ message: string }>(apiKey, `/v1/tenants/suppressions/${encodeURIComponent(email)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type {\n CreateWebhookParams,\n CreateWebhookResponse,\n UpdateWebhookParams,\n UpdateWebhookResponse,\n ListWebhooksResponse,\n} from '../types';\n\nexport class WebhooksResource {\n constructor(private http: HttpClient) {}\n\n async create(apiKey: string, params: CreateWebhookParams): Promise<CreateWebhookResponse> {\n return this.http.post<CreateWebhookResponse>(apiKey, '/v1/tenants/webhooks', params);\n }\n\n async list(apiKey: string): Promise<ListWebhooksResponse> {\n return this.http.get<ListWebhooksResponse>(apiKey, '/v1/tenants/webhooks');\n }\n\n async update(apiKey: string, id: string, params: UpdateWebhookParams): Promise<UpdateWebhookResponse> {\n return this.http.patch<UpdateWebhookResponse>(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`, params);\n }\n\n async delete(apiKey: string, id: string): Promise<{ message: string; id: string }> {\n return this.http.delete<{ message: string; id: string }>(apiKey, `/v1/tenants/webhooks/${encodeURIComponent(id)}`);\n }\n}\n","import type { HttpClient } from '../http';\nimport type { DashboardResponse, QuotaResponse } from '../types';\n\nexport class DashboardResource {\n constructor(private http: HttpClient) {}\n\n async get(apiKey: string): Promise<DashboardResponse> {\n return this.http.get<DashboardResponse>(apiKey, '/v1/tenants/dashboard');\n }\n\n async quota(apiKey: string): Promise<QuotaResponse> {\n return this.http.get<QuotaResponse>(apiKey, '/v1/tenants/quota');\n }\n}\n","import { HttpClient } from './http';\nimport { EmailResource } from './resources/email';\nimport { TemplatesResource } from './resources/templates';\nimport { SuppressionsResource } from './resources/suppressions';\nimport { WebhooksResource } from './resources/webhooks';\nimport { DashboardResource } from './resources/dashboard';\nimport type { OutboundConfig, ResolvedConfig } from './types';\n\nconst BASE_URL = 'https://outbound-api.mastersunion.org';\n\nexport class Outbound {\n readonly email: EmailResource;\n readonly templates: TemplatesResource;\n readonly suppressions: SuppressionsResource;\n readonly webhooks: WebhooksResource;\n readonly dashboard: DashboardResource;\n\n constructor(config?: OutboundConfig) {\n const resolved: ResolvedConfig = {\n baseUrl: config?.baseUrl || BASE_URL,\n timeout: config?.timeout ?? 30_000,\n maxRetries: config?.maxRetries ?? 3,\n retryDelay: config?.retryDelay ?? 1000,\n };\n\n const http = new HttpClient(resolved);\n\n this.email = new EmailResource(http);\n this.templates = new TemplatesResource(http);\n this.suppressions = new SuppressionsResource(http);\n this.webhooks = new WebhooksResource(http);\n this.dashboard = new DashboardResource(http);\n }\n\n /**\n * Verify a webhook signature using HMAC-SHA256.\n * Use this in your webhook handler to validate incoming requests.\n */\n static verifyWebhookSignature(\n payload: string | Buffer,\n signature: string,\n secret: string,\n ): boolean {\n // Dynamic import to keep browser-compatible at the type level\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const crypto = require('crypto') as typeof import('crypto');\n const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');\n try {\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|