sendcore 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -0
- package/dist/index.d.mts +176 -0
- package/dist/index.d.ts +176 -0
- package/dist/index.js +213 -0
- package/dist/index.mjs +185 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# SendCore Node.js SDK
|
|
2
|
+
|
|
3
|
+
The official Node.js SDK for [SendCore](https://sendcore.elasto.ng) — reliable email infrastructure for developers and businesses.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install sendcore
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { SendCore } from 'sendcore';
|
|
15
|
+
|
|
16
|
+
const sendcore = new SendCore('sc_live_xxxxxxxxxx');
|
|
17
|
+
|
|
18
|
+
// Send an email
|
|
19
|
+
await sendcore.emails.send({
|
|
20
|
+
from: 'hello@yourdomain.com',
|
|
21
|
+
to: 'user@example.com',
|
|
22
|
+
subject: 'Welcome!',
|
|
23
|
+
html: '<h1>Hello World</h1>',
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- **Zero dependencies** — uses native `fetch` (Node 18+)
|
|
30
|
+
- **Full TypeScript support** — complete type definitions included
|
|
31
|
+
- **Automatic retries** — exponential backoff on 5xx errors
|
|
32
|
+
- **Configurable timeouts** — prevent hanging requests
|
|
33
|
+
- **Secure by default** — API key via `x-api-key` header
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { SendCore } from 'sendcore';
|
|
41
|
+
|
|
42
|
+
// Simple — just pass your API key
|
|
43
|
+
const sendcore = new SendCore('sc_live_xxxxxxxxxx');
|
|
44
|
+
|
|
45
|
+
// Advanced — full configuration
|
|
46
|
+
const sendcore = new SendCore({
|
|
47
|
+
apiKey: 'sc_live_xxxxxxxxxx',
|
|
48
|
+
baseUrl: 'https://api.sendcore.elasto.ng', // optional
|
|
49
|
+
timeout: 30000, // optional, ms
|
|
50
|
+
retries: 2, // optional
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Get your API key from the [SendCore Dashboard](https://sendcore.elasto.ng/dashboard/api-keys).
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Sending Emails
|
|
59
|
+
|
|
60
|
+
### Basic Email
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
await sendcore.emails.send({
|
|
64
|
+
from: 'hello@yourdomain.com',
|
|
65
|
+
to: 'user@example.com',
|
|
66
|
+
subject: 'Hello!',
|
|
67
|
+
html: '<h1>Welcome to our platform</h1>',
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### With Multiple Recipients
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
await sendcore.emails.send({
|
|
75
|
+
from: 'Team <team@yourdomain.com>',
|
|
76
|
+
to: ['alice@example.com', 'bob@example.com'],
|
|
77
|
+
cc: 'manager@example.com',
|
|
78
|
+
bcc: ['audit@yourdomain.com'],
|
|
79
|
+
subject: 'Team Update',
|
|
80
|
+
html: '<p>Here is your weekly update.</p>',
|
|
81
|
+
replyTo: 'support@yourdomain.com',
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Using a Template
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
await sendcore.emails.sendTemplate({
|
|
89
|
+
from: 'hello@yourdomain.com',
|
|
90
|
+
to: 'user@example.com',
|
|
91
|
+
templateId: 'welcome-email',
|
|
92
|
+
templateData: {
|
|
93
|
+
name: 'John',
|
|
94
|
+
plan: 'Pro',
|
|
95
|
+
loginUrl: 'https://app.example.com/login',
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### With Attachments
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { readFileSync } from 'fs';
|
|
104
|
+
|
|
105
|
+
await sendcore.emails.send({
|
|
106
|
+
from: 'billing@yourdomain.com',
|
|
107
|
+
to: 'user@example.com',
|
|
108
|
+
subject: 'Your Invoice',
|
|
109
|
+
html: '<p>Please find your invoice attached.</p>',
|
|
110
|
+
attachments: [
|
|
111
|
+
{
|
|
112
|
+
filename: 'invoice.pdf',
|
|
113
|
+
content: readFileSync('./invoice.pdf').toString('base64'),
|
|
114
|
+
contentType: 'application/pdf',
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### With Tags
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
await sendcore.emails.send({
|
|
124
|
+
from: 'hello@yourdomain.com',
|
|
125
|
+
to: 'user@example.com',
|
|
126
|
+
subject: 'Order Confirmation',
|
|
127
|
+
html: '<p>Your order is confirmed!</p>',
|
|
128
|
+
tags: {
|
|
129
|
+
category: 'transactional',
|
|
130
|
+
orderId: 'ORD-12345',
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Managing Contacts
|
|
138
|
+
|
|
139
|
+
### Subscribe a Contact
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
await sendcore.contacts.subscribe({
|
|
143
|
+
email: 'user@example.com',
|
|
144
|
+
firstName: 'John',
|
|
145
|
+
lastName: 'Doe',
|
|
146
|
+
listId: 'lst_abc123', // optional
|
|
147
|
+
customData: { plan: 'pro' }, // optional
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Unsubscribe a Contact
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
await sendcore.contacts.unsubscribe({
|
|
155
|
+
email: 'user@example.com',
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Error Handling
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
import { SendCore, SendCoreError } from 'sendcore';
|
|
165
|
+
|
|
166
|
+
const sendcore = new SendCore('sc_live_xxxxxxxxxx');
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
await sendcore.emails.send({
|
|
170
|
+
from: 'hello@yourdomain.com',
|
|
171
|
+
to: 'user@example.com',
|
|
172
|
+
subject: 'Test',
|
|
173
|
+
html: '<p>Hello</p>',
|
|
174
|
+
});
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (error instanceof SendCoreError) {
|
|
177
|
+
console.error('Status:', error.statusCode); // e.g. 400, 401, 422
|
|
178
|
+
console.error('Message:', error.message);
|
|
179
|
+
console.error('Detail:', error.detail);
|
|
180
|
+
} else {
|
|
181
|
+
console.error('Network error:', error);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Requirements
|
|
189
|
+
|
|
190
|
+
- **Node.js 18+** (uses native `fetch`)
|
|
191
|
+
- A SendCore API key
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/** Configuration for the SendCore client */
|
|
2
|
+
interface SendCoreConfig {
|
|
3
|
+
/** Your API key from the SendCore dashboard */
|
|
4
|
+
apiKey: string;
|
|
5
|
+
/** Base URL of the SendCore API (default: https://api.sendcore.elasto.ng) */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
8
|
+
timeout?: number;
|
|
9
|
+
/** Number of automatic retries on 5xx errors (default: 2) */
|
|
10
|
+
retries?: number;
|
|
11
|
+
}
|
|
12
|
+
interface EmailAttachment {
|
|
13
|
+
/** Filename of the attachment */
|
|
14
|
+
filename: string;
|
|
15
|
+
/** Base64-encoded content of the file */
|
|
16
|
+
content: string;
|
|
17
|
+
/** MIME content type (e.g. 'application/pdf') */
|
|
18
|
+
contentType?: string;
|
|
19
|
+
}
|
|
20
|
+
interface SendEmailParams {
|
|
21
|
+
/** Sender address (e.g. 'John <john@example.com>') */
|
|
22
|
+
from: string;
|
|
23
|
+
/** One or more recipient email addresses */
|
|
24
|
+
to: string | string[];
|
|
25
|
+
/** Email subject line */
|
|
26
|
+
subject?: string;
|
|
27
|
+
/** HTML body of the email */
|
|
28
|
+
html?: string;
|
|
29
|
+
/** Plain text body of the email */
|
|
30
|
+
text?: string;
|
|
31
|
+
/** CC recipients */
|
|
32
|
+
cc?: string | string[];
|
|
33
|
+
/** BCC recipients */
|
|
34
|
+
bcc?: string | string[];
|
|
35
|
+
/** Reply-to addresses */
|
|
36
|
+
replyTo?: string | string[];
|
|
37
|
+
/** Use a pre-built template by its ID */
|
|
38
|
+
templateId?: string;
|
|
39
|
+
/** Variables to inject into the template */
|
|
40
|
+
templateData?: Record<string, any>;
|
|
41
|
+
/** File attachments */
|
|
42
|
+
attachments?: EmailAttachment[];
|
|
43
|
+
/** Custom tags for tracking and analytics */
|
|
44
|
+
tags?: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
interface SendEmailResponse {
|
|
47
|
+
id: string;
|
|
48
|
+
message: string;
|
|
49
|
+
[key: string]: any;
|
|
50
|
+
}
|
|
51
|
+
interface SubscribeParams {
|
|
52
|
+
/** Email address of the contact */
|
|
53
|
+
email: string;
|
|
54
|
+
/** First name */
|
|
55
|
+
firstName?: string;
|
|
56
|
+
/** Last name */
|
|
57
|
+
lastName?: string;
|
|
58
|
+
/** ID of the audience list to add the contact to */
|
|
59
|
+
listId?: string;
|
|
60
|
+
/** Any additional custom data */
|
|
61
|
+
customData?: Record<string, any>;
|
|
62
|
+
}
|
|
63
|
+
interface UnsubscribeParams {
|
|
64
|
+
/** Email address to unsubscribe */
|
|
65
|
+
email: string;
|
|
66
|
+
}
|
|
67
|
+
interface SendCoreErrorDetail {
|
|
68
|
+
statusCode: number;
|
|
69
|
+
message: string;
|
|
70
|
+
error?: string;
|
|
71
|
+
[key: string]: any;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* SendCore — Official Node.js SDK
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { SendCore } from 'sendcore';
|
|
80
|
+
*
|
|
81
|
+
* const sendcore = new SendCore('sc_live_xxxxxxxxxx');
|
|
82
|
+
*
|
|
83
|
+
* await sendcore.emails.send({
|
|
84
|
+
* from: 'hello@yourdomain.com',
|
|
85
|
+
* to: 'user@example.com',
|
|
86
|
+
* subject: 'Welcome!',
|
|
87
|
+
* html: '<h1>Hello World</h1>',
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare class SendCore {
|
|
92
|
+
private readonly apiKey;
|
|
93
|
+
private readonly baseUrl;
|
|
94
|
+
private readonly timeout;
|
|
95
|
+
private readonly retries;
|
|
96
|
+
/** Email operations */
|
|
97
|
+
readonly emails: EmailsResource;
|
|
98
|
+
/** Audience / contact operations */
|
|
99
|
+
readonly contacts: ContactsResource;
|
|
100
|
+
constructor(apiKeyOrConfig: string | SendCoreConfig);
|
|
101
|
+
/** @internal */
|
|
102
|
+
_request<T = any>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, body?: Record<string, any>): Promise<T>;
|
|
103
|
+
}
|
|
104
|
+
declare class EmailsResource {
|
|
105
|
+
private readonly client;
|
|
106
|
+
constructor(client: SendCore);
|
|
107
|
+
/**
|
|
108
|
+
* Send an email.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* const result = await sendcore.emails.send({
|
|
113
|
+
* from: 'hello@yourdomain.com',
|
|
114
|
+
* to: 'user@example.com',
|
|
115
|
+
* subject: 'Hello!',
|
|
116
|
+
* html: '<h1>Welcome</h1>',
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
send(params: SendEmailParams): Promise<SendEmailResponse>;
|
|
121
|
+
/**
|
|
122
|
+
* Send an email using a pre-built template.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* await sendcore.emails.sendTemplate({
|
|
127
|
+
* from: 'hello@yourdomain.com',
|
|
128
|
+
* to: 'user@example.com',
|
|
129
|
+
* templateId: 'welcome-email',
|
|
130
|
+
* templateData: { name: 'John', plan: 'Pro' },
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
sendTemplate(params: Omit<SendEmailParams, 'html' | 'text'> & {
|
|
135
|
+
templateId: string;
|
|
136
|
+
templateData?: Record<string, any>;
|
|
137
|
+
}): Promise<SendEmailResponse>;
|
|
138
|
+
}
|
|
139
|
+
declare class ContactsResource {
|
|
140
|
+
private readonly client;
|
|
141
|
+
constructor(client: SendCore);
|
|
142
|
+
/**
|
|
143
|
+
* Subscribe a contact (add to your audience).
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* await sendcore.contacts.subscribe({
|
|
148
|
+
* email: 'user@example.com',
|
|
149
|
+
* firstName: 'John',
|
|
150
|
+
* listId: 'lst_abc123',
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
subscribe(params: SubscribeParams): Promise<any>;
|
|
155
|
+
/**
|
|
156
|
+
* Unsubscribe a contact from your audience.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* await sendcore.contacts.unsubscribe({ email: 'user@example.com' });
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
unsubscribe(params: UnsubscribeParams): Promise<any>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Custom error class for SendCore API errors.
|
|
168
|
+
* Contains the HTTP status code and structured error detail from the server.
|
|
169
|
+
*/
|
|
170
|
+
declare class SendCoreError extends Error {
|
|
171
|
+
readonly statusCode: number;
|
|
172
|
+
readonly detail: SendCoreErrorDetail;
|
|
173
|
+
constructor(statusCode: number, detail: SendCoreErrorDetail);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export { type EmailAttachment, SendCore, type SendCoreConfig, SendCoreError, type SendCoreErrorDetail, type SendEmailParams, type SendEmailResponse, type SubscribeParams, type UnsubscribeParams };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/** Configuration for the SendCore client */
|
|
2
|
+
interface SendCoreConfig {
|
|
3
|
+
/** Your API key from the SendCore dashboard */
|
|
4
|
+
apiKey: string;
|
|
5
|
+
/** Base URL of the SendCore API (default: https://api.sendcore.elasto.ng) */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
8
|
+
timeout?: number;
|
|
9
|
+
/** Number of automatic retries on 5xx errors (default: 2) */
|
|
10
|
+
retries?: number;
|
|
11
|
+
}
|
|
12
|
+
interface EmailAttachment {
|
|
13
|
+
/** Filename of the attachment */
|
|
14
|
+
filename: string;
|
|
15
|
+
/** Base64-encoded content of the file */
|
|
16
|
+
content: string;
|
|
17
|
+
/** MIME content type (e.g. 'application/pdf') */
|
|
18
|
+
contentType?: string;
|
|
19
|
+
}
|
|
20
|
+
interface SendEmailParams {
|
|
21
|
+
/** Sender address (e.g. 'John <john@example.com>') */
|
|
22
|
+
from: string;
|
|
23
|
+
/** One or more recipient email addresses */
|
|
24
|
+
to: string | string[];
|
|
25
|
+
/** Email subject line */
|
|
26
|
+
subject?: string;
|
|
27
|
+
/** HTML body of the email */
|
|
28
|
+
html?: string;
|
|
29
|
+
/** Plain text body of the email */
|
|
30
|
+
text?: string;
|
|
31
|
+
/** CC recipients */
|
|
32
|
+
cc?: string | string[];
|
|
33
|
+
/** BCC recipients */
|
|
34
|
+
bcc?: string | string[];
|
|
35
|
+
/** Reply-to addresses */
|
|
36
|
+
replyTo?: string | string[];
|
|
37
|
+
/** Use a pre-built template by its ID */
|
|
38
|
+
templateId?: string;
|
|
39
|
+
/** Variables to inject into the template */
|
|
40
|
+
templateData?: Record<string, any>;
|
|
41
|
+
/** File attachments */
|
|
42
|
+
attachments?: EmailAttachment[];
|
|
43
|
+
/** Custom tags for tracking and analytics */
|
|
44
|
+
tags?: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
interface SendEmailResponse {
|
|
47
|
+
id: string;
|
|
48
|
+
message: string;
|
|
49
|
+
[key: string]: any;
|
|
50
|
+
}
|
|
51
|
+
interface SubscribeParams {
|
|
52
|
+
/** Email address of the contact */
|
|
53
|
+
email: string;
|
|
54
|
+
/** First name */
|
|
55
|
+
firstName?: string;
|
|
56
|
+
/** Last name */
|
|
57
|
+
lastName?: string;
|
|
58
|
+
/** ID of the audience list to add the contact to */
|
|
59
|
+
listId?: string;
|
|
60
|
+
/** Any additional custom data */
|
|
61
|
+
customData?: Record<string, any>;
|
|
62
|
+
}
|
|
63
|
+
interface UnsubscribeParams {
|
|
64
|
+
/** Email address to unsubscribe */
|
|
65
|
+
email: string;
|
|
66
|
+
}
|
|
67
|
+
interface SendCoreErrorDetail {
|
|
68
|
+
statusCode: number;
|
|
69
|
+
message: string;
|
|
70
|
+
error?: string;
|
|
71
|
+
[key: string]: any;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* SendCore — Official Node.js SDK
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { SendCore } from 'sendcore';
|
|
80
|
+
*
|
|
81
|
+
* const sendcore = new SendCore('sc_live_xxxxxxxxxx');
|
|
82
|
+
*
|
|
83
|
+
* await sendcore.emails.send({
|
|
84
|
+
* from: 'hello@yourdomain.com',
|
|
85
|
+
* to: 'user@example.com',
|
|
86
|
+
* subject: 'Welcome!',
|
|
87
|
+
* html: '<h1>Hello World</h1>',
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare class SendCore {
|
|
92
|
+
private readonly apiKey;
|
|
93
|
+
private readonly baseUrl;
|
|
94
|
+
private readonly timeout;
|
|
95
|
+
private readonly retries;
|
|
96
|
+
/** Email operations */
|
|
97
|
+
readonly emails: EmailsResource;
|
|
98
|
+
/** Audience / contact operations */
|
|
99
|
+
readonly contacts: ContactsResource;
|
|
100
|
+
constructor(apiKeyOrConfig: string | SendCoreConfig);
|
|
101
|
+
/** @internal */
|
|
102
|
+
_request<T = any>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, body?: Record<string, any>): Promise<T>;
|
|
103
|
+
}
|
|
104
|
+
declare class EmailsResource {
|
|
105
|
+
private readonly client;
|
|
106
|
+
constructor(client: SendCore);
|
|
107
|
+
/**
|
|
108
|
+
* Send an email.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* const result = await sendcore.emails.send({
|
|
113
|
+
* from: 'hello@yourdomain.com',
|
|
114
|
+
* to: 'user@example.com',
|
|
115
|
+
* subject: 'Hello!',
|
|
116
|
+
* html: '<h1>Welcome</h1>',
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
send(params: SendEmailParams): Promise<SendEmailResponse>;
|
|
121
|
+
/**
|
|
122
|
+
* Send an email using a pre-built template.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* await sendcore.emails.sendTemplate({
|
|
127
|
+
* from: 'hello@yourdomain.com',
|
|
128
|
+
* to: 'user@example.com',
|
|
129
|
+
* templateId: 'welcome-email',
|
|
130
|
+
* templateData: { name: 'John', plan: 'Pro' },
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
sendTemplate(params: Omit<SendEmailParams, 'html' | 'text'> & {
|
|
135
|
+
templateId: string;
|
|
136
|
+
templateData?: Record<string, any>;
|
|
137
|
+
}): Promise<SendEmailResponse>;
|
|
138
|
+
}
|
|
139
|
+
declare class ContactsResource {
|
|
140
|
+
private readonly client;
|
|
141
|
+
constructor(client: SendCore);
|
|
142
|
+
/**
|
|
143
|
+
* Subscribe a contact (add to your audience).
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* await sendcore.contacts.subscribe({
|
|
148
|
+
* email: 'user@example.com',
|
|
149
|
+
* firstName: 'John',
|
|
150
|
+
* listId: 'lst_abc123',
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
subscribe(params: SubscribeParams): Promise<any>;
|
|
155
|
+
/**
|
|
156
|
+
* Unsubscribe a contact from your audience.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* await sendcore.contacts.unsubscribe({ email: 'user@example.com' });
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
unsubscribe(params: UnsubscribeParams): Promise<any>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Custom error class for SendCore API errors.
|
|
168
|
+
* Contains the HTTP status code and structured error detail from the server.
|
|
169
|
+
*/
|
|
170
|
+
declare class SendCoreError extends Error {
|
|
171
|
+
readonly statusCode: number;
|
|
172
|
+
readonly detail: SendCoreErrorDetail;
|
|
173
|
+
constructor(statusCode: number, detail: SendCoreErrorDetail);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export { type EmailAttachment, SendCore, type SendCoreConfig, SendCoreError, type SendCoreErrorDetail, type SendEmailParams, type SendEmailResponse, type SubscribeParams, type UnsubscribeParams };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
SendCore: () => SendCore,
|
|
24
|
+
SendCoreError: () => SendCoreError
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/errors.ts
|
|
29
|
+
var SendCoreError = class _SendCoreError extends Error {
|
|
30
|
+
statusCode;
|
|
31
|
+
detail;
|
|
32
|
+
constructor(statusCode, detail) {
|
|
33
|
+
const msg = detail.message || `SendCore API error (${statusCode})`;
|
|
34
|
+
super(msg);
|
|
35
|
+
this.name = "SendCoreError";
|
|
36
|
+
this.statusCode = statusCode;
|
|
37
|
+
this.detail = detail;
|
|
38
|
+
Object.setPrototypeOf(this, _SendCoreError.prototype);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/client.ts
|
|
43
|
+
var DEFAULT_BASE_URL = "https://api.sendcore.elasto.ng";
|
|
44
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
45
|
+
var DEFAULT_RETRIES = 2;
|
|
46
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
47
|
+
var SDK_VERSION = "1.0.0";
|
|
48
|
+
var SendCore = class {
|
|
49
|
+
apiKey;
|
|
50
|
+
baseUrl;
|
|
51
|
+
timeout;
|
|
52
|
+
retries;
|
|
53
|
+
/** Email operations */
|
|
54
|
+
emails;
|
|
55
|
+
/** Audience / contact operations */
|
|
56
|
+
contacts;
|
|
57
|
+
constructor(apiKeyOrConfig) {
|
|
58
|
+
const config = typeof apiKeyOrConfig === "string" ? { apiKey: apiKeyOrConfig } : apiKeyOrConfig;
|
|
59
|
+
if (!config.apiKey) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"SendCore: An API key is required. Get one at https://sendcore.elasto.ng/dashboard/api-keys"
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
this.apiKey = config.apiKey;
|
|
65
|
+
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
66
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
67
|
+
this.retries = config.retries ?? DEFAULT_RETRIES;
|
|
68
|
+
this.emails = new EmailsResource(this);
|
|
69
|
+
this.contacts = new ContactsResource(this);
|
|
70
|
+
}
|
|
71
|
+
// ─── Internal HTTP layer ────────────────────
|
|
72
|
+
/** @internal */
|
|
73
|
+
async _request(method, path, body) {
|
|
74
|
+
const url = `${this.baseUrl}${path}`;
|
|
75
|
+
const headers = {
|
|
76
|
+
"x-api-key": this.apiKey,
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
"User-Agent": `sendcore-node/${SDK_VERSION}`
|
|
79
|
+
};
|
|
80
|
+
const fetchOptions = {
|
|
81
|
+
method,
|
|
82
|
+
headers,
|
|
83
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
84
|
+
...body ? { body: JSON.stringify(body) } : {}
|
|
85
|
+
};
|
|
86
|
+
let lastError = null;
|
|
87
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
88
|
+
try {
|
|
89
|
+
const response = await fetch(url, fetchOptions);
|
|
90
|
+
const responseBody = await response.json().catch(() => ({}));
|
|
91
|
+
if (response.ok) {
|
|
92
|
+
return responseBody;
|
|
93
|
+
}
|
|
94
|
+
if (!RETRYABLE_STATUS_CODES.has(response.status)) {
|
|
95
|
+
throw new SendCoreError(response.status, {
|
|
96
|
+
statusCode: response.status,
|
|
97
|
+
message: responseBody.message || response.statusText,
|
|
98
|
+
error: responseBody.error,
|
|
99
|
+
...responseBody
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
lastError = new SendCoreError(response.status, {
|
|
103
|
+
statusCode: response.status,
|
|
104
|
+
message: responseBody.message || response.statusText,
|
|
105
|
+
error: responseBody.error,
|
|
106
|
+
...responseBody
|
|
107
|
+
});
|
|
108
|
+
} catch (err) {
|
|
109
|
+
if (err instanceof SendCoreError) throw err;
|
|
110
|
+
lastError = err;
|
|
111
|
+
}
|
|
112
|
+
if (attempt < this.retries) {
|
|
113
|
+
const delay = Math.min(1e3 * 2 ** attempt, 1e4);
|
|
114
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
throw lastError ?? new Error("SendCore: Request failed after retries");
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var EmailsResource = class {
|
|
121
|
+
constructor(client) {
|
|
122
|
+
this.client = client;
|
|
123
|
+
}
|
|
124
|
+
client;
|
|
125
|
+
/**
|
|
126
|
+
* Send an email.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* const result = await sendcore.emails.send({
|
|
131
|
+
* from: 'hello@yourdomain.com',
|
|
132
|
+
* to: 'user@example.com',
|
|
133
|
+
* subject: 'Hello!',
|
|
134
|
+
* html: '<h1>Welcome</h1>',
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
async send(params) {
|
|
139
|
+
if (!params.from) {
|
|
140
|
+
throw new Error("SendCore: The 'from' field is required to send an email.");
|
|
141
|
+
}
|
|
142
|
+
if (!params.to) {
|
|
143
|
+
throw new Error("SendCore: The 'to' field is required to send an email.");
|
|
144
|
+
}
|
|
145
|
+
const payload = {
|
|
146
|
+
...params,
|
|
147
|
+
to: Array.isArray(params.to) ? params.to : [params.to],
|
|
148
|
+
cc: params.cc ? Array.isArray(params.cc) ? params.cc : [params.cc] : void 0,
|
|
149
|
+
bcc: params.bcc ? Array.isArray(params.bcc) ? params.bcc : [params.bcc] : void 0,
|
|
150
|
+
replyTo: params.replyTo ? Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo] : void 0
|
|
151
|
+
};
|
|
152
|
+
return this.client._request("POST", "/emails/send", payload);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Send an email using a pre-built template.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* await sendcore.emails.sendTemplate({
|
|
160
|
+
* from: 'hello@yourdomain.com',
|
|
161
|
+
* to: 'user@example.com',
|
|
162
|
+
* templateId: 'welcome-email',
|
|
163
|
+
* templateData: { name: 'John', plan: 'Pro' },
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
async sendTemplate(params) {
|
|
168
|
+
return this.send(params);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
var ContactsResource = class {
|
|
172
|
+
constructor(client) {
|
|
173
|
+
this.client = client;
|
|
174
|
+
}
|
|
175
|
+
client;
|
|
176
|
+
/**
|
|
177
|
+
* Subscribe a contact (add to your audience).
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* await sendcore.contacts.subscribe({
|
|
182
|
+
* email: 'user@example.com',
|
|
183
|
+
* firstName: 'John',
|
|
184
|
+
* listId: 'lst_abc123',
|
|
185
|
+
* });
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
async subscribe(params) {
|
|
189
|
+
if (!params.email) {
|
|
190
|
+
throw new Error("SendCore: The 'email' field is required.");
|
|
191
|
+
}
|
|
192
|
+
return this.client._request("POST", "/organizations/audience/subscribe", params);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Unsubscribe a contact from your audience.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* await sendcore.contacts.unsubscribe({ email: 'user@example.com' });
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
async unsubscribe(params) {
|
|
203
|
+
if (!params.email) {
|
|
204
|
+
throw new Error("SendCore: The 'email' field is required.");
|
|
205
|
+
}
|
|
206
|
+
return this.client._request("POST", "/organizations/audience/unsubscribe", params);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
210
|
+
0 && (module.exports = {
|
|
211
|
+
SendCore,
|
|
212
|
+
SendCoreError
|
|
213
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var SendCoreError = class _SendCoreError extends Error {
|
|
3
|
+
statusCode;
|
|
4
|
+
detail;
|
|
5
|
+
constructor(statusCode, detail) {
|
|
6
|
+
const msg = detail.message || `SendCore API error (${statusCode})`;
|
|
7
|
+
super(msg);
|
|
8
|
+
this.name = "SendCoreError";
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
this.detail = detail;
|
|
11
|
+
Object.setPrototypeOf(this, _SendCoreError.prototype);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/client.ts
|
|
16
|
+
var DEFAULT_BASE_URL = "https://api.sendcore.elasto.ng";
|
|
17
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
18
|
+
var DEFAULT_RETRIES = 2;
|
|
19
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
20
|
+
var SDK_VERSION = "1.0.0";
|
|
21
|
+
var SendCore = class {
|
|
22
|
+
apiKey;
|
|
23
|
+
baseUrl;
|
|
24
|
+
timeout;
|
|
25
|
+
retries;
|
|
26
|
+
/** Email operations */
|
|
27
|
+
emails;
|
|
28
|
+
/** Audience / contact operations */
|
|
29
|
+
contacts;
|
|
30
|
+
constructor(apiKeyOrConfig) {
|
|
31
|
+
const config = typeof apiKeyOrConfig === "string" ? { apiKey: apiKeyOrConfig } : apiKeyOrConfig;
|
|
32
|
+
if (!config.apiKey) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"SendCore: An API key is required. Get one at https://sendcore.elasto.ng/dashboard/api-keys"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
this.apiKey = config.apiKey;
|
|
38
|
+
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
39
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
40
|
+
this.retries = config.retries ?? DEFAULT_RETRIES;
|
|
41
|
+
this.emails = new EmailsResource(this);
|
|
42
|
+
this.contacts = new ContactsResource(this);
|
|
43
|
+
}
|
|
44
|
+
// ─── Internal HTTP layer ────────────────────
|
|
45
|
+
/** @internal */
|
|
46
|
+
async _request(method, path, body) {
|
|
47
|
+
const url = `${this.baseUrl}${path}`;
|
|
48
|
+
const headers = {
|
|
49
|
+
"x-api-key": this.apiKey,
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
"User-Agent": `sendcore-node/${SDK_VERSION}`
|
|
52
|
+
};
|
|
53
|
+
const fetchOptions = {
|
|
54
|
+
method,
|
|
55
|
+
headers,
|
|
56
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
57
|
+
...body ? { body: JSON.stringify(body) } : {}
|
|
58
|
+
};
|
|
59
|
+
let lastError = null;
|
|
60
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetch(url, fetchOptions);
|
|
63
|
+
const responseBody = await response.json().catch(() => ({}));
|
|
64
|
+
if (response.ok) {
|
|
65
|
+
return responseBody;
|
|
66
|
+
}
|
|
67
|
+
if (!RETRYABLE_STATUS_CODES.has(response.status)) {
|
|
68
|
+
throw new SendCoreError(response.status, {
|
|
69
|
+
statusCode: response.status,
|
|
70
|
+
message: responseBody.message || response.statusText,
|
|
71
|
+
error: responseBody.error,
|
|
72
|
+
...responseBody
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
lastError = new SendCoreError(response.status, {
|
|
76
|
+
statusCode: response.status,
|
|
77
|
+
message: responseBody.message || response.statusText,
|
|
78
|
+
error: responseBody.error,
|
|
79
|
+
...responseBody
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
if (err instanceof SendCoreError) throw err;
|
|
83
|
+
lastError = err;
|
|
84
|
+
}
|
|
85
|
+
if (attempt < this.retries) {
|
|
86
|
+
const delay = Math.min(1e3 * 2 ** attempt, 1e4);
|
|
87
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
throw lastError ?? new Error("SendCore: Request failed after retries");
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var EmailsResource = class {
|
|
94
|
+
constructor(client) {
|
|
95
|
+
this.client = client;
|
|
96
|
+
}
|
|
97
|
+
client;
|
|
98
|
+
/**
|
|
99
|
+
* Send an email.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* const result = await sendcore.emails.send({
|
|
104
|
+
* from: 'hello@yourdomain.com',
|
|
105
|
+
* to: 'user@example.com',
|
|
106
|
+
* subject: 'Hello!',
|
|
107
|
+
* html: '<h1>Welcome</h1>',
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
async send(params) {
|
|
112
|
+
if (!params.from) {
|
|
113
|
+
throw new Error("SendCore: The 'from' field is required to send an email.");
|
|
114
|
+
}
|
|
115
|
+
if (!params.to) {
|
|
116
|
+
throw new Error("SendCore: The 'to' field is required to send an email.");
|
|
117
|
+
}
|
|
118
|
+
const payload = {
|
|
119
|
+
...params,
|
|
120
|
+
to: Array.isArray(params.to) ? params.to : [params.to],
|
|
121
|
+
cc: params.cc ? Array.isArray(params.cc) ? params.cc : [params.cc] : void 0,
|
|
122
|
+
bcc: params.bcc ? Array.isArray(params.bcc) ? params.bcc : [params.bcc] : void 0,
|
|
123
|
+
replyTo: params.replyTo ? Array.isArray(params.replyTo) ? params.replyTo : [params.replyTo] : void 0
|
|
124
|
+
};
|
|
125
|
+
return this.client._request("POST", "/emails/send", payload);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Send an email using a pre-built template.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* await sendcore.emails.sendTemplate({
|
|
133
|
+
* from: 'hello@yourdomain.com',
|
|
134
|
+
* to: 'user@example.com',
|
|
135
|
+
* templateId: 'welcome-email',
|
|
136
|
+
* templateData: { name: 'John', plan: 'Pro' },
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
async sendTemplate(params) {
|
|
141
|
+
return this.send(params);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
var ContactsResource = class {
|
|
145
|
+
constructor(client) {
|
|
146
|
+
this.client = client;
|
|
147
|
+
}
|
|
148
|
+
client;
|
|
149
|
+
/**
|
|
150
|
+
* Subscribe a contact (add to your audience).
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* await sendcore.contacts.subscribe({
|
|
155
|
+
* email: 'user@example.com',
|
|
156
|
+
* firstName: 'John',
|
|
157
|
+
* listId: 'lst_abc123',
|
|
158
|
+
* });
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
async subscribe(params) {
|
|
162
|
+
if (!params.email) {
|
|
163
|
+
throw new Error("SendCore: The 'email' field is required.");
|
|
164
|
+
}
|
|
165
|
+
return this.client._request("POST", "/organizations/audience/subscribe", params);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Unsubscribe a contact from your audience.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```ts
|
|
172
|
+
* await sendcore.contacts.unsubscribe({ email: 'user@example.com' });
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
async unsubscribe(params) {
|
|
176
|
+
if (!params.email) {
|
|
177
|
+
throw new Error("SendCore: The 'email' field is required.");
|
|
178
|
+
}
|
|
179
|
+
return this.client._request("POST", "/organizations/audience/unsubscribe", params);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
export {
|
|
183
|
+
SendCore,
|
|
184
|
+
SendCoreError
|
|
185
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sendcore",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Node.js SDK for the SendCore email delivery platform",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"lint": "tsc --noEmit",
|
|
26
|
+
"prepublishOnly": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"sendcore",
|
|
30
|
+
"email",
|
|
31
|
+
"smtp",
|
|
32
|
+
"transactional-email",
|
|
33
|
+
"email-api",
|
|
34
|
+
"broadcast",
|
|
35
|
+
"newsletter",
|
|
36
|
+
"elasto"
|
|
37
|
+
],
|
|
38
|
+
"author": "Elasto Team",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/elastodev/sendcore-node"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"tsup": "^8.0.0",
|
|
49
|
+
"typescript": "^5.4.0",
|
|
50
|
+
"vitest": "^2.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|