@upyo/sendgrid 0.1.0-dev.13
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 +77 -0
- package/dist/index.cjs +470 -0
- package/dist/index.d.cts +320 -0
- package/dist/index.d.ts +320 -0
- package/dist/index.js +467 -0
- package/package.json +70 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
//#region src/config.ts
|
|
2
|
+
/**
|
|
3
|
+
* Creates a resolved SendGrid configuration by applying default values to optional fields.
|
|
4
|
+
*
|
|
5
|
+
* This function takes a partial SendGrid configuration and returns a complete
|
|
6
|
+
* configuration with all optional fields filled with sensible defaults.
|
|
7
|
+
*
|
|
8
|
+
* @param config - The SendGrid configuration with optional fields
|
|
9
|
+
* @returns A resolved configuration with all defaults applied
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const resolved = createSendGridConfig({
|
|
14
|
+
* apiKey: 'your-api-key'
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // resolved.baseUrl will be 'https://api.sendgrid.com/v3' (default)
|
|
18
|
+
* // resolved.timeout will be 30000 (default)
|
|
19
|
+
* // resolved.retries will be 3 (default)
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function createSendGridConfig(config) {
|
|
23
|
+
return {
|
|
24
|
+
apiKey: config.apiKey,
|
|
25
|
+
baseUrl: config.baseUrl ?? "https://api.sendgrid.com/v3",
|
|
26
|
+
timeout: config.timeout ?? 3e4,
|
|
27
|
+
retries: config.retries ?? 3,
|
|
28
|
+
validateSsl: config.validateSsl ?? true,
|
|
29
|
+
headers: config.headers ?? {},
|
|
30
|
+
clickTracking: config.clickTracking ?? true,
|
|
31
|
+
openTracking: config.openTracking ?? true,
|
|
32
|
+
subscriptionTracking: config.subscriptionTracking ?? false,
|
|
33
|
+
googleAnalytics: config.googleAnalytics ?? false
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/http-client.ts
|
|
39
|
+
/**
|
|
40
|
+
* HTTP client wrapper for SendGrid API requests.
|
|
41
|
+
*
|
|
42
|
+
* This class handles authentication, request formatting, error handling,
|
|
43
|
+
* and retry logic for SendGrid API calls.
|
|
44
|
+
*/
|
|
45
|
+
var SendGridHttpClient = class {
|
|
46
|
+
config;
|
|
47
|
+
constructor(config) {
|
|
48
|
+
this.config = config;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Sends a message via SendGrid API.
|
|
52
|
+
*
|
|
53
|
+
* @param messageData The JSON data to send to SendGrid.
|
|
54
|
+
* @param signal Optional AbortSignal for cancellation.
|
|
55
|
+
* @returns Promise that resolves to the SendGrid response.
|
|
56
|
+
*/
|
|
57
|
+
sendMessage(messageData, signal) {
|
|
58
|
+
const url = `${this.config.baseUrl}/mail/send`;
|
|
59
|
+
return this.makeRequest(url, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: { "Content-Type": "application/json" },
|
|
62
|
+
body: JSON.stringify(messageData),
|
|
63
|
+
signal
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Makes an HTTP request to SendGrid API with retry logic.
|
|
68
|
+
*
|
|
69
|
+
* @param url The URL to make the request to.
|
|
70
|
+
* @param options Fetch options.
|
|
71
|
+
* @returns Promise that resolves to the parsed response.
|
|
72
|
+
*/
|
|
73
|
+
async makeRequest(url, options) {
|
|
74
|
+
let lastError = null;
|
|
75
|
+
for (let attempt = 0; attempt <= this.config.retries; attempt++) try {
|
|
76
|
+
const response = await this.fetchWithAuth(url, options);
|
|
77
|
+
const text = await response.text();
|
|
78
|
+
if (response.status === 202) return {
|
|
79
|
+
statusCode: response.status,
|
|
80
|
+
body: text,
|
|
81
|
+
headers: this.headersToRecord(response.headers)
|
|
82
|
+
};
|
|
83
|
+
let errorData;
|
|
84
|
+
try {
|
|
85
|
+
errorData = JSON.parse(text);
|
|
86
|
+
} catch {
|
|
87
|
+
errorData = { message: text || `HTTP ${response.status}` };
|
|
88
|
+
}
|
|
89
|
+
throw new SendGridApiError(errorData.message || `HTTP ${response.status}`, response.status, errorData.errors);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
92
|
+
if (error instanceof SendGridApiError && error.statusCode && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
93
|
+
if (attempt === this.config.retries) throw error;
|
|
94
|
+
const delay = Math.pow(2, attempt) * 1e3;
|
|
95
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
96
|
+
}
|
|
97
|
+
throw lastError || /* @__PURE__ */ new Error("Request failed after all retries");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Makes a fetch request with SendGrid authentication.
|
|
101
|
+
*
|
|
102
|
+
* @param url The URL to make the request to.
|
|
103
|
+
* @param options Fetch options.
|
|
104
|
+
* @returns Promise that resolves to the fetch response.
|
|
105
|
+
*/
|
|
106
|
+
async fetchWithAuth(url, options) {
|
|
107
|
+
const headers = new Headers(options.headers);
|
|
108
|
+
headers.set("Authorization", `Bearer ${this.config.apiKey}`);
|
|
109
|
+
for (const [key, value] of Object.entries(this.config.headers)) headers.set(key, value);
|
|
110
|
+
const controller = new AbortController();
|
|
111
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
112
|
+
let signal = controller.signal;
|
|
113
|
+
if (options.signal) {
|
|
114
|
+
signal = options.signal;
|
|
115
|
+
if (options.signal.aborted) controller.abort();
|
|
116
|
+
else options.signal.addEventListener("abort", () => controller.abort());
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
return await globalThis.fetch(url, {
|
|
120
|
+
...options,
|
|
121
|
+
headers,
|
|
122
|
+
signal
|
|
123
|
+
});
|
|
124
|
+
} finally {
|
|
125
|
+
clearTimeout(timeoutId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Converts Headers object to a plain Record.
|
|
130
|
+
*
|
|
131
|
+
* @param headers The Headers object to convert.
|
|
132
|
+
* @returns A plain object with header key-value pairs.
|
|
133
|
+
*/
|
|
134
|
+
headersToRecord(headers) {
|
|
135
|
+
const record = {};
|
|
136
|
+
for (const [key, value] of headers.entries()) record[key] = value;
|
|
137
|
+
return record;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Custom error class for SendGrid API errors.
|
|
142
|
+
*/
|
|
143
|
+
var SendGridApiError = class extends Error {
|
|
144
|
+
statusCode;
|
|
145
|
+
errors;
|
|
146
|
+
constructor(message, statusCode, errors) {
|
|
147
|
+
super(message);
|
|
148
|
+
this.name = "SendGridApiError";
|
|
149
|
+
this.statusCode = statusCode;
|
|
150
|
+
this.errors = errors;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/message-converter.ts
|
|
156
|
+
/**
|
|
157
|
+
* Converts a Upyo Message to SendGrid API JSON format.
|
|
158
|
+
*
|
|
159
|
+
* This function transforms the standardized Upyo message format into
|
|
160
|
+
* the specific format expected by the SendGrid API.
|
|
161
|
+
*
|
|
162
|
+
* @param message - The Upyo message to convert
|
|
163
|
+
* @param config - The resolved SendGrid configuration
|
|
164
|
+
* @returns Promise that resolves to a SendGrid mail object
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* const mailData = await convertMessage(message, config);
|
|
169
|
+
* const response = await httpClient.sendMessage(mailData);
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
async function convertMessage(message, config) {
|
|
173
|
+
const sendGridMail = {
|
|
174
|
+
personalizations: [],
|
|
175
|
+
from: formatAddress(message.sender)
|
|
176
|
+
};
|
|
177
|
+
const personalization = {
|
|
178
|
+
to: message.recipients.map(formatAddress),
|
|
179
|
+
subject: message.subject
|
|
180
|
+
};
|
|
181
|
+
if (message.ccRecipients.length > 0) personalization.cc = message.ccRecipients.map(formatAddress);
|
|
182
|
+
if (message.bccRecipients.length > 0) personalization.bcc = message.bccRecipients.map(formatAddress);
|
|
183
|
+
sendGridMail.personalizations.push(personalization);
|
|
184
|
+
if (message.replyRecipients.length > 0) if (message.replyRecipients.length === 1) sendGridMail.reply_to = formatAddress(message.replyRecipients[0]);
|
|
185
|
+
else sendGridMail.reply_to_list = message.replyRecipients.map(formatAddress);
|
|
186
|
+
const content = [];
|
|
187
|
+
if ("html" in message.content) {
|
|
188
|
+
if (message.content.text) content.push({
|
|
189
|
+
type: "text/plain",
|
|
190
|
+
value: message.content.text
|
|
191
|
+
});
|
|
192
|
+
content.push({
|
|
193
|
+
type: "text/html",
|
|
194
|
+
value: message.content.html
|
|
195
|
+
});
|
|
196
|
+
} else content.push({
|
|
197
|
+
type: "text/plain",
|
|
198
|
+
value: message.content.text
|
|
199
|
+
});
|
|
200
|
+
sendGridMail.content = content;
|
|
201
|
+
if (message.priority !== "normal") {
|
|
202
|
+
const headers = {};
|
|
203
|
+
switch (message.priority) {
|
|
204
|
+
case "high":
|
|
205
|
+
headers["X-Priority"] = "1";
|
|
206
|
+
headers["X-MSMail-Priority"] = "High";
|
|
207
|
+
headers["Importance"] = "High";
|
|
208
|
+
break;
|
|
209
|
+
case "low":
|
|
210
|
+
headers["X-Priority"] = "5";
|
|
211
|
+
headers["X-MSMail-Priority"] = "Low";
|
|
212
|
+
headers["Importance"] = "Low";
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
sendGridMail.headers = {
|
|
216
|
+
...sendGridMail.headers,
|
|
217
|
+
...headers
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (message.tags.length > 0) sendGridMail.categories = message.tags;
|
|
221
|
+
const customHeaders = {};
|
|
222
|
+
for (const [key, value] of message.headers.entries()) if (!isStandardHeader(key)) customHeaders[key] = value;
|
|
223
|
+
if (Object.keys(customHeaders).length > 0) sendGridMail.headers = {
|
|
224
|
+
...sendGridMail.headers,
|
|
225
|
+
...customHeaders
|
|
226
|
+
};
|
|
227
|
+
if (message.attachments.length > 0) sendGridMail.attachments = await Promise.all(message.attachments.map(convertAttachment));
|
|
228
|
+
const trackingSettings = {};
|
|
229
|
+
if (config.clickTracking !== void 0) trackingSettings.click_tracking = {
|
|
230
|
+
enable: config.clickTracking,
|
|
231
|
+
enable_text: config.clickTracking
|
|
232
|
+
};
|
|
233
|
+
if (config.openTracking !== void 0) trackingSettings.open_tracking = { enable: config.openTracking };
|
|
234
|
+
if (config.subscriptionTracking !== void 0) trackingSettings.subscription_tracking = { enable: config.subscriptionTracking };
|
|
235
|
+
if (config.googleAnalytics !== void 0) trackingSettings.ganalytics = { enable: config.googleAnalytics };
|
|
236
|
+
if (Object.keys(trackingSettings).length > 0) sendGridMail.tracking_settings = trackingSettings;
|
|
237
|
+
return sendGridMail;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Formats an address for SendGrid API.
|
|
241
|
+
*
|
|
242
|
+
* @param address - The address to format
|
|
243
|
+
* @returns Formatted address object
|
|
244
|
+
*/
|
|
245
|
+
function formatAddress(address) {
|
|
246
|
+
const result = { email: address.address };
|
|
247
|
+
if (address.name) result.name = address.name;
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Converts a Upyo attachment to SendGrid format.
|
|
252
|
+
*
|
|
253
|
+
* @param attachment - The attachment to convert
|
|
254
|
+
* @returns Promise that resolves to a SendGrid attachment object
|
|
255
|
+
*/
|
|
256
|
+
async function convertAttachment(attachment) {
|
|
257
|
+
const contentBytes = await attachment.content;
|
|
258
|
+
const base64Content = btoa(String.fromCharCode(...contentBytes));
|
|
259
|
+
const sendGridAttachment = {
|
|
260
|
+
content: base64Content,
|
|
261
|
+
filename: attachment.filename
|
|
262
|
+
};
|
|
263
|
+
if (attachment.contentType) sendGridAttachment.type = attachment.contentType;
|
|
264
|
+
if (attachment.inline && attachment.contentId) {
|
|
265
|
+
sendGridAttachment.disposition = "inline";
|
|
266
|
+
sendGridAttachment.content_id = attachment.contentId;
|
|
267
|
+
} else sendGridAttachment.disposition = "attachment";
|
|
268
|
+
return sendGridAttachment;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Checks if a header is a standard email header that should not be added as custom header.
|
|
272
|
+
*
|
|
273
|
+
* @param headerName - The header name to check
|
|
274
|
+
* @returns True if it's a standard header
|
|
275
|
+
*/
|
|
276
|
+
function isStandardHeader(headerName) {
|
|
277
|
+
const standardHeaders = [
|
|
278
|
+
"from",
|
|
279
|
+
"to",
|
|
280
|
+
"cc",
|
|
281
|
+
"bcc",
|
|
282
|
+
"reply-to",
|
|
283
|
+
"subject",
|
|
284
|
+
"date",
|
|
285
|
+
"message-id",
|
|
286
|
+
"content-type",
|
|
287
|
+
"content-transfer-encoding",
|
|
288
|
+
"mime-version",
|
|
289
|
+
"x-priority",
|
|
290
|
+
"x-msmail-priority",
|
|
291
|
+
"importance"
|
|
292
|
+
];
|
|
293
|
+
return standardHeaders.includes(headerName.toLowerCase());
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/sendgrid-transport.ts
|
|
298
|
+
/**
|
|
299
|
+
* SendGrid transport implementation for sending emails via SendGrid API.
|
|
300
|
+
*
|
|
301
|
+
* This transport provides efficient email delivery using SendGrid's v3 HTTP API,
|
|
302
|
+
* with support for authentication, retry logic, and batch sending capabilities.
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```typescript
|
|
306
|
+
* import { SendGridTransport } from '@upyo/sendgrid';
|
|
307
|
+
*
|
|
308
|
+
* const transport = new SendGridTransport({
|
|
309
|
+
* apiKey: 'your-sendgrid-api-key',
|
|
310
|
+
* clickTracking: true,
|
|
311
|
+
* openTracking: true
|
|
312
|
+
* });
|
|
313
|
+
*
|
|
314
|
+
* const receipt = await transport.send(message);
|
|
315
|
+
* console.log('Message sent:', receipt.messageId);
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
var SendGridTransport = class {
|
|
319
|
+
config;
|
|
320
|
+
httpClient;
|
|
321
|
+
/**
|
|
322
|
+
* Creates a new SendGrid transport instance.
|
|
323
|
+
*
|
|
324
|
+
* @param config SendGrid configuration including API key and options.
|
|
325
|
+
*/
|
|
326
|
+
constructor(config) {
|
|
327
|
+
this.config = createSendGridConfig(config);
|
|
328
|
+
this.httpClient = new SendGridHttpClient(this.config);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Sends a single email message via SendGrid API.
|
|
332
|
+
*
|
|
333
|
+
* This method converts the message to SendGrid format, makes an HTTP request
|
|
334
|
+
* to the SendGrid API, and returns a receipt with the result.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```typescript
|
|
338
|
+
* const receipt = await transport.send({
|
|
339
|
+
* sender: { address: 'from@example.com' },
|
|
340
|
+
* recipients: [{ address: 'to@example.com' }],
|
|
341
|
+
* ccRecipients: [],
|
|
342
|
+
* bccRecipients: [],
|
|
343
|
+
* replyRecipients: [],
|
|
344
|
+
* subject: 'Hello',
|
|
345
|
+
* content: { text: 'Hello World!' },
|
|
346
|
+
* attachments: [],
|
|
347
|
+
* priority: 'normal',
|
|
348
|
+
* tags: [],
|
|
349
|
+
* headers: new Headers()
|
|
350
|
+
* });
|
|
351
|
+
*
|
|
352
|
+
* if (receipt.successful) {
|
|
353
|
+
* console.log('Message sent successfully');
|
|
354
|
+
* }
|
|
355
|
+
* ```
|
|
356
|
+
*
|
|
357
|
+
* @param message The email message to send.
|
|
358
|
+
* @param options Optional transport options including `AbortSignal` for
|
|
359
|
+
* cancellation.
|
|
360
|
+
* @returns A promise that resolves to a receipt indicating success or
|
|
361
|
+
* failure.
|
|
362
|
+
*/
|
|
363
|
+
async send(message, options) {
|
|
364
|
+
options?.signal?.throwIfAborted();
|
|
365
|
+
try {
|
|
366
|
+
const mailData = await convertMessage(message, this.config);
|
|
367
|
+
options?.signal?.throwIfAborted();
|
|
368
|
+
const response = await this.httpClient.sendMessage(mailData, options?.signal);
|
|
369
|
+
const messageId = this.extractMessageId(response);
|
|
370
|
+
return {
|
|
371
|
+
messageId,
|
|
372
|
+
errorMessages: [],
|
|
373
|
+
successful: true
|
|
374
|
+
};
|
|
375
|
+
} catch (error) {
|
|
376
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
377
|
+
return {
|
|
378
|
+
messageId: "",
|
|
379
|
+
errorMessages: [errorMessage],
|
|
380
|
+
successful: false
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Sends multiple email messages efficiently via SendGrid API.
|
|
386
|
+
*
|
|
387
|
+
* This method sends each message individually but provides a streamlined
|
|
388
|
+
* interface for processing multiple messages. Each message is sent as a
|
|
389
|
+
* separate API request to SendGrid.
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* const messages = [
|
|
394
|
+
* {
|
|
395
|
+
* sender: { address: 'from@example.com' },
|
|
396
|
+
* recipients: [{ address: 'user1@example.com' }],
|
|
397
|
+
* ccRecipients: [],
|
|
398
|
+
* bccRecipients: [],
|
|
399
|
+
* replyRecipients: [],
|
|
400
|
+
* subject: 'Message 1',
|
|
401
|
+
* content: { text: 'Hello User 1!' },
|
|
402
|
+
* attachments: [],
|
|
403
|
+
* priority: 'normal',
|
|
404
|
+
* tags: [],
|
|
405
|
+
* headers: new Headers()
|
|
406
|
+
* },
|
|
407
|
+
* {
|
|
408
|
+
* sender: { address: 'from@example.com' },
|
|
409
|
+
* recipients: [{ address: 'user2@example.com' }],
|
|
410
|
+
* ccRecipients: [],
|
|
411
|
+
* bccRecipients: [],
|
|
412
|
+
* replyRecipients: [],
|
|
413
|
+
* subject: 'Message 2',
|
|
414
|
+
* content: { text: 'Hello User 2!' },
|
|
415
|
+
* attachments: [],
|
|
416
|
+
* priority: 'normal',
|
|
417
|
+
* tags: [],
|
|
418
|
+
* headers: new Headers()
|
|
419
|
+
* }
|
|
420
|
+
* ];
|
|
421
|
+
*
|
|
422
|
+
* for await (const receipt of transport.sendMany(messages)) {
|
|
423
|
+
* if (receipt.successful) {
|
|
424
|
+
* console.log('Sent:', receipt.messageId);
|
|
425
|
+
* } else {
|
|
426
|
+
* console.error('Failed:', receipt.errorMessages);
|
|
427
|
+
* }
|
|
428
|
+
* }
|
|
429
|
+
* ```
|
|
430
|
+
*
|
|
431
|
+
* @param messages An iterable or async iterable of messages to send.
|
|
432
|
+
* @param options Optional transport options including `AbortSignal` for
|
|
433
|
+
* cancellation.
|
|
434
|
+
* @returns An async iterable of receipts, one for each message.
|
|
435
|
+
*/
|
|
436
|
+
async *sendMany(messages, options) {
|
|
437
|
+
options?.signal?.throwIfAborted();
|
|
438
|
+
const isAsyncIterable = Symbol.asyncIterator in messages;
|
|
439
|
+
if (isAsyncIterable) for await (const message of messages) {
|
|
440
|
+
options?.signal?.throwIfAborted();
|
|
441
|
+
yield await this.send(message, options);
|
|
442
|
+
}
|
|
443
|
+
else for (const message of messages) {
|
|
444
|
+
options?.signal?.throwIfAborted();
|
|
445
|
+
yield await this.send(message, options);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Extracts or generates a message ID from the SendGrid response.
|
|
450
|
+
*
|
|
451
|
+
* SendGrid doesn't return a message ID in the response body for successful sends,
|
|
452
|
+
* so we generate a synthetic ID based on timestamp and some response data.
|
|
453
|
+
*
|
|
454
|
+
* @param response The SendGrid API response.
|
|
455
|
+
* @returns A message ID string.
|
|
456
|
+
*/
|
|
457
|
+
extractMessageId(response) {
|
|
458
|
+
const messageIdHeader = response.headers?.["x-message-id"] || response.headers?.["X-Message-Id"];
|
|
459
|
+
if (messageIdHeader) return messageIdHeader;
|
|
460
|
+
const timestamp = Date.now();
|
|
461
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
462
|
+
return `sendgrid-${timestamp}-${random}`;
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
//#endregion
|
|
467
|
+
export { SendGridApiError, SendGridTransport, createSendGridConfig };
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@upyo/sendgrid",
|
|
3
|
+
"version": "0.1.0-dev.13+aad44636",
|
|
4
|
+
"description": "SendGrid transport for Upyo email library",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"email",
|
|
7
|
+
"mail",
|
|
8
|
+
"sendmail",
|
|
9
|
+
"sendgrid"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": {
|
|
13
|
+
"name": "Hong Minhee",
|
|
14
|
+
"email": "hong@minhee.org",
|
|
15
|
+
"url": "https://hongminhee.org/"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://upyo.org/",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/dahlia/upyo.git",
|
|
21
|
+
"directory": "packages/sendgrid/"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/dahlia/upyo/issues"
|
|
25
|
+
},
|
|
26
|
+
"funding": [
|
|
27
|
+
"https://github.com/sponsors/dahlia"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20.0.0",
|
|
31
|
+
"bun": ">=1.2.0",
|
|
32
|
+
"deno": ">=2.3.0"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist/",
|
|
36
|
+
"package.json",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"type": "module",
|
|
40
|
+
"module": "./dist/index.js",
|
|
41
|
+
"main": "./dist/index.cjs",
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"exports": {
|
|
44
|
+
".": {
|
|
45
|
+
"types": {
|
|
46
|
+
"import": "./dist/index.d.ts",
|
|
47
|
+
"require": "./dist/index.d.cts"
|
|
48
|
+
},
|
|
49
|
+
"import": "./dist/index.js",
|
|
50
|
+
"require": "./dist/index.cjs"
|
|
51
|
+
},
|
|
52
|
+
"./package.json": "./package.json"
|
|
53
|
+
},
|
|
54
|
+
"sideEffects": false,
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@upyo/core": "0.1.0-dev.13+aad44636"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@dotenvx/dotenvx": "^1.47.3",
|
|
60
|
+
"tsdown": "^0.12.7",
|
|
61
|
+
"typescript": "5.8.3"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsdown",
|
|
65
|
+
"prepublish": "tsdown",
|
|
66
|
+
"test": "tsdown && dotenvx run --ignore=MISSING_ENV_FILE -- node --experimental-transform-types --test",
|
|
67
|
+
"test:bun": "tsdown && bun test --timeout=30000 --env-file=.env",
|
|
68
|
+
"test:deno": "deno test --allow-env --allow-net --env-file=.env"
|
|
69
|
+
}
|
|
70
|
+
}
|