@upyo/core 0.2.0-dev.22 → 0.2.0-dev.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,8 +6,15 @@
6
6
  [![JSR][JSR badge]][JSR]
7
7
  [![npm][npm badge]][npm]
8
8
 
9
- Shared types and interfaces for [Upyo], a simple and cross-runtime library for
10
- sending email messages.
9
+ Core types and interfaces for [Upyo], a cross-runtime email library that
10
+ provides a unified, type-safe API for sending emails across Node.js, Deno, Bun,
11
+ and edge functions.
12
+
13
+ The *@upyo/core* package provides the foundational types and interfaces that all
14
+ Upyo transport implementations use. It defines the common `Message`, `Address`,
15
+ `Transport`, and `Receipt` types that enable seamless switching between
16
+ different email providers while maintaining consistent type safety and
17
+ error handling.
11
18
 
12
19
  [JSR]: https://jsr.io/@upyo/core
13
20
  [JSR badge]: https://jsr.io/badges/@upyo/core
@@ -16,6 +23,18 @@ sending email messages.
16
23
  [Upyo]: https://upyo.org/
17
24
 
18
25
 
26
+ Features
27
+ --------
28
+
29
+ - *Universal types*: Common interfaces for all email transports
30
+ - *Type-safe messaging*: Comprehensive TypeScript definitions for email
31
+ messages
32
+ - *Attachment support*: File attachment handling
33
+ - *Cross-runtime compatibility*: Works on Node.js, Deno, Bun,
34
+ and edge functions
35
+ - *Zero dependencies*: Lightweight with no external dependencies
36
+
37
+
19
38
  Installation
20
39
  ------------
21
40
 
@@ -26,3 +45,135 @@ yarn add @upyo/core
26
45
  deno add jsr:@upyo/core
27
46
  bun add @upyo/core
28
47
  ~~~~
48
+
49
+
50
+ Usage
51
+ -----
52
+
53
+ ### Creating messages
54
+
55
+ The `createMessage()` function provides a convenient way to create email
56
+ messages:
57
+
58
+ ~~~~ typescript
59
+ import { createMessage } from "@upyo/core";
60
+
61
+ const message = createMessage({
62
+ from: "sender@example.com",
63
+ to: ["recipient@example.net", "another@example.org"],
64
+ cc: "copy@example.com",
65
+ subject: "Hello from Upyo!",
66
+ content: {
67
+ text: "This is a plain text message.",
68
+ html: "<p>This is an <strong>HTML</strong> message.</p>",
69
+ },
70
+ priority: "high",
71
+ });
72
+ ~~~~
73
+
74
+ ### Adding attachments
75
+
76
+ Attachments can be added using the standard [`File`] API:
77
+
78
+ ~~~~ typescript
79
+ import { createMessage } from "@upyo/core";
80
+
81
+ const message = createMessage({
82
+ from: "sender@example.com",
83
+ to: "recipient@example.net",
84
+ subject: "Document attached",
85
+ content: { text: "Please find the document attached." },
86
+ attachments: [
87
+ new File(
88
+ [await fetch("document.pdf").then(r => r.arrayBuffer())],
89
+ "document.pdf",
90
+ { type: "application/pdf" }
91
+ ),
92
+ ],
93
+ });
94
+ ~~~~
95
+
96
+ [`File`]: https://developer.mozilla.org/en-US/docs/Web/API/File
97
+
98
+ ### Handling receipts
99
+
100
+ All transport operations return `Receipt` objects that use discriminated unions
101
+ for type-safe error handling:
102
+
103
+ ~~~~ typescript
104
+ import type { Receipt } from "@upyo/core";
105
+
106
+ function handleReceipt(receipt: Receipt) {
107
+ if (receipt.successful) {
108
+ console.log("Message sent with ID:", receipt.messageId);
109
+ } else {
110
+ console.error("Send failed:", receipt.errorMessages.join(", "));
111
+ }
112
+ }
113
+ ~~~~
114
+
115
+ ### Implementing custom transports
116
+
117
+ The `Transport` interface defines the contract for all email providers:
118
+
119
+ ~~~~ typescript
120
+ import type { Message, Receipt, Transport, TransportOptions } from "@upyo/core";
121
+
122
+ class MyCustomTransport implements Transport {
123
+ async send(message: Message, options?: TransportOptions): Promise<Receipt> {
124
+ // Implementation details...
125
+ return { successful: true, messageId: "12345" };
126
+ }
127
+
128
+ async *sendMany(
129
+ messages: Iterable<Message> | AsyncIterable<Message>,
130
+ options?: TransportOptions,
131
+ ): AsyncIterable<Receipt> {
132
+ for await (const message of messages) {
133
+ yield await this.send(message, options);
134
+ }
135
+ }
136
+ }
137
+ ~~~~
138
+
139
+
140
+ Related packages
141
+ ----------------
142
+
143
+ The `@upyo/core` package is the foundation for all Upyo transport
144
+ implementations:
145
+
146
+ | Package | JSR | npm | Description |
147
+ | ------------------- | ------------------------------ | ------------------------------ | ------------------------------------------------- |
148
+ | @upyo/smtp | [JSR][jsr:@upyo/smtp] | [npm][npm:@upyo/smtp] | SMTP transport for any mail server |
149
+ | @upyo/mailgun | [JSR][jsr:@upyo/mailgun] | [npm][npm:@upyo/mailgun] | [Mailgun] HTTP API transport |
150
+ | @upyo/sendgrid | [JSR][jsr:@upyo/sendgrid] | [npm][npm:@upyo/sendgrid] | [SendGrid] HTTP API transport |
151
+ | @upyo/ses | [JSR][jsr:@upyo/ses] | [npm][npm:@upyo/ses] | [Amazon SES] HTTP API transport |
152
+ | @upyo/mock | [JSR][jsr:@upyo/mock] | [npm][npm:@upyo/mock] | Mock transport for testing |
153
+ | @upyo/opentelemetry | [JSR][jsr:@upyo/opentelemetry] | [npm][npm:@upyo/opentelemetry] | [OpenTelemetry] observability for Upyo transports |
154
+
155
+ [jsr:@upyo/smtp]: https://jsr.io/@upyo/smtp
156
+ [npm:@upyo/smtp]: https://www.npmjs.com/package/@upyo/smtp
157
+ [jsr:@upyo/mailgun]: https://jsr.io/@upyo/mailgun
158
+ [npm:@upyo/mailgun]: https://www.npmjs.com/package/@upyo/mailgun
159
+ [jsr:@upyo/sendgrid]: https://jsr.io/@upyo/sendgrid
160
+ [npm:@upyo/sendgrid]: https://www.npmjs.com/package/@upyo/sendgrid
161
+ [jsr:@upyo/ses]: https://jsr.io/@upyo/ses
162
+ [npm:@upyo/ses]: https://www.npmjs.com/package/@upyo/ses
163
+ [jsr:@upyo/mock]: https://jsr.io/@upyo/mock
164
+ [npm:@upyo/mock]: https://www.npmjs.com/package/@upyo/mock
165
+ [jsr:@upyo/opentelemetry]: https://jsr.io/@upyo/opentelemetry
166
+ [npm:@upyo/opentelemetry]: https://www.npmjs.com/package/@upyo/opentelemetry
167
+ [Mailgun]: https://www.mailgun.com/
168
+ [SendGrid]: https://sendgrid.com/
169
+ [Amazon SES]: https://aws.amazon.com/ses/
170
+ [OpenTelemetry]: https://opentelemetry.io/
171
+
172
+
173
+ Documentation
174
+ -------------
175
+
176
+ For comprehensive documentation, examples, and guides, visit
177
+ *<https://upyo.org/>*.
178
+
179
+ API reference documentation is available on JSR: *<https://jsr.io/@upyo/core>*.
package/dist/address.cjs CHANGED
@@ -128,7 +128,28 @@ function isValidDomainPart(domainPart) {
128
128
  return false;
129
129
  }
130
130
  }
131
+ /**
132
+ * Type guard function that checks if a given value is a valid email address.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * import { isEmailAddress } from "@upyo/core/address";
137
+ *
138
+ * const userInput = "user@example.com";
139
+ * if (isEmailAddress(userInput)) {
140
+ * // TypeScript now knows userInput is EmailAddress type
141
+ * console.log(userInput); // Type: `${string}@${string}`
142
+ * }
143
+ * ```
144
+ *
145
+ * @param email The value to check
146
+ * @returns `true` if the value is a valid email address, `false` otherwise
147
+ */
148
+ function isEmailAddress(email) {
149
+ return typeof email === "string" && isValidEmail(email);
150
+ }
131
151
 
132
152
  //#endregion
133
153
  exports.formatAddress = formatAddress;
154
+ exports.isEmailAddress = isEmailAddress;
134
155
  exports.parseAddress = parseAddress;
@@ -1,4 +1,9 @@
1
1
  //#region src/address.d.ts
2
+ /**
3
+ * A type alias for email address strings that must contain an @ symbol.
4
+ * @since 0.2.0
5
+ */
6
+ type EmailAddress = `${string}@${string}`;
2
7
  /**
3
8
  * A pair of name (which is optional) and email address.
4
9
  */
@@ -10,7 +15,7 @@ interface Address {
10
15
  /**
11
16
  * The email address itself.
12
17
  */
13
- readonly address: string;
18
+ readonly address: EmailAddress;
14
19
  }
15
20
  /**
16
21
  * Formats an address object into a string representation. This function is
@@ -64,5 +69,23 @@ declare function formatAddress(address: Address): string;
64
69
  * or `undefined` if the input is invalid.
65
70
  */
66
71
  declare function parseAddress(address: string): Address | undefined;
72
+ /**
73
+ * Type guard function that checks if a given value is a valid email address.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * import { isEmailAddress } from "@upyo/core/address";
78
+ *
79
+ * const userInput = "user@example.com";
80
+ * if (isEmailAddress(userInput)) {
81
+ * // TypeScript now knows userInput is EmailAddress type
82
+ * console.log(userInput); // Type: `${string}@${string}`
83
+ * }
84
+ * ```
85
+ *
86
+ * @param email The value to check
87
+ * @returns `true` if the value is a valid email address, `false` otherwise
88
+ */
89
+ declare function isEmailAddress(email: unknown): email is EmailAddress;
67
90
  //#endregion
68
- export { Address, formatAddress, parseAddress };
91
+ export { Address, EmailAddress, formatAddress, isEmailAddress, parseAddress };
package/dist/address.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  //#region src/address.d.ts
2
+ /**
3
+ * A type alias for email address strings that must contain an @ symbol.
4
+ * @since 0.2.0
5
+ */
6
+ type EmailAddress = `${string}@${string}`;
2
7
  /**
3
8
  * A pair of name (which is optional) and email address.
4
9
  */
@@ -10,7 +15,7 @@ interface Address {
10
15
  /**
11
16
  * The email address itself.
12
17
  */
13
- readonly address: string;
18
+ readonly address: EmailAddress;
14
19
  }
15
20
  /**
16
21
  * Formats an address object into a string representation. This function is
@@ -64,5 +69,23 @@ declare function formatAddress(address: Address): string;
64
69
  * or `undefined` if the input is invalid.
65
70
  */
66
71
  declare function parseAddress(address: string): Address | undefined;
72
+ /**
73
+ * Type guard function that checks if a given value is a valid email address.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * import { isEmailAddress } from "@upyo/core/address";
78
+ *
79
+ * const userInput = "user@example.com";
80
+ * if (isEmailAddress(userInput)) {
81
+ * // TypeScript now knows userInput is EmailAddress type
82
+ * console.log(userInput); // Type: `${string}@${string}`
83
+ * }
84
+ * ```
85
+ *
86
+ * @param email The value to check
87
+ * @returns `true` if the value is a valid email address, `false` otherwise
88
+ */
89
+ declare function isEmailAddress(email: unknown): email is EmailAddress;
67
90
  //#endregion
68
- export { Address, formatAddress, parseAddress };
91
+ export { Address, EmailAddress, formatAddress, isEmailAddress, parseAddress };
package/dist/address.js CHANGED
@@ -127,6 +127,26 @@ function isValidDomainPart(domainPart) {
127
127
  return false;
128
128
  }
129
129
  }
130
+ /**
131
+ * Type guard function that checks if a given value is a valid email address.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * import { isEmailAddress } from "@upyo/core/address";
136
+ *
137
+ * const userInput = "user@example.com";
138
+ * if (isEmailAddress(userInput)) {
139
+ * // TypeScript now knows userInput is EmailAddress type
140
+ * console.log(userInput); // Type: `${string}@${string}`
141
+ * }
142
+ * ```
143
+ *
144
+ * @param email The value to check
145
+ * @returns `true` if the value is a valid email address, `false` otherwise
146
+ */
147
+ function isEmailAddress(email) {
148
+ return typeof email === "string" && isValidEmail(email);
149
+ }
130
150
 
131
151
  //#endregion
132
- export { formatAddress, parseAddress };
152
+ export { formatAddress, isEmailAddress, parseAddress };
package/dist/index.cjs CHANGED
@@ -7,4 +7,5 @@ exports.comparePriority = require_priority.comparePriority;
7
7
  exports.createMessage = require_message.createMessage;
8
8
  exports.formatAddress = require_address.formatAddress;
9
9
  exports.isAttachment = require_attachment.isAttachment;
10
+ exports.isEmailAddress = require_address.isEmailAddress;
10
11
  exports.parseAddress = require_address.parseAddress;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { Address, formatAddress, parseAddress } from "./address.cjs";
1
+ import { Address, EmailAddress, formatAddress, isEmailAddress, parseAddress } from "./address.cjs";
2
2
  import { Attachment, isAttachment } from "./attachment.cjs";
3
3
  import { Priority, comparePriority } from "./priority.cjs";
4
4
  import { ImmutableHeaders, Message, MessageConstructor, MessageContent, createMessage } from "./message.cjs";
5
5
  import { Receipt } from "./receipt.cjs";
6
6
  import { Transport, TransportOptions } from "./transport.cjs";
7
- export { Address, Attachment, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, Transport, TransportOptions, comparePriority, createMessage, formatAddress, isAttachment, parseAddress };
7
+ export { Address, Attachment, EmailAddress, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, Transport, TransportOptions, comparePriority, createMessage, formatAddress, isAttachment, isEmailAddress, parseAddress };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { Address, formatAddress, parseAddress } from "./address.js";
1
+ import { Address, EmailAddress, formatAddress, isEmailAddress, parseAddress } from "./address.js";
2
2
  import { Attachment, isAttachment } from "./attachment.js";
3
3
  import { Priority, comparePriority } from "./priority.js";
4
4
  import { ImmutableHeaders, Message, MessageConstructor, MessageContent, createMessage } from "./message.js";
5
5
  import { Receipt } from "./receipt.js";
6
6
  import { Transport, TransportOptions } from "./transport.js";
7
- export { Address, Attachment, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, Transport, TransportOptions, comparePriority, createMessage, formatAddress, isAttachment, parseAddress };
7
+ export { Address, Attachment, EmailAddress, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, Transport, TransportOptions, comparePriority, createMessage, formatAddress, isAttachment, isEmailAddress, parseAddress };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { formatAddress, parseAddress } from "./address.js";
1
+ import { formatAddress, isEmailAddress, parseAddress } from "./address.js";
2
2
  import { isAttachment } from "./attachment.js";
3
3
  import { createMessage } from "./message.js";
4
4
  import { comparePriority } from "./priority.js";
5
5
 
6
- export { comparePriority, createMessage, formatAddress, isAttachment, parseAddress };
6
+ export { comparePriority, createMessage, formatAddress, isAttachment, isEmailAddress, parseAddress };
@@ -20,19 +20,19 @@ interface Message {
20
20
  /**
21
21
  * The email addresses of the recipient of the message.
22
22
  */
23
- readonly recipients: Address[];
23
+ readonly recipients: readonly Address[];
24
24
  /**
25
25
  * The email addresses of the carbon copy (CC) recipients of the message.
26
26
  */
27
- readonly ccRecipients: Address[];
27
+ readonly ccRecipients: readonly Address[];
28
28
  /**
29
29
  * The email addresses of the blind carbon copy (BCC) recipients of the message.
30
30
  */
31
- readonly bccRecipients: Address[];
31
+ readonly bccRecipients: readonly Address[];
32
32
  /**
33
33
  * The email addresses of the reply-to recipients of the message.
34
34
  */
35
- readonly replyRecipients: Address[];
35
+ readonly replyRecipients: readonly Address[];
36
36
  /**
37
37
  * The attachments included in the email message. These are files that
38
38
  * are sent along with the email, such as documents, images, or other
@@ -40,7 +40,7 @@ interface Message {
40
40
  * object, which contains information about the attachment such as its
41
41
  * filename, content type, and content ID.
42
42
  */
43
- readonly attachments: Attachment[];
43
+ readonly attachments: readonly Attachment[];
44
44
  /**
45
45
  * The subject of the email message. This is typically a brief summary
46
46
  * of the content of the email, and is used to help the recipient identify
@@ -67,7 +67,7 @@ interface Message {
67
67
  /**
68
68
  * The tags associated with the email message.
69
69
  */
70
- readonly tags: string[];
70
+ readonly tags: readonly string[];
71
71
  /**
72
72
  * The headers of the email message. This is represented by
73
73
  * the {@link ImmutableHeaders} type, which is a supertype of
package/dist/message.d.ts CHANGED
@@ -20,19 +20,19 @@ interface Message {
20
20
  /**
21
21
  * The email addresses of the recipient of the message.
22
22
  */
23
- readonly recipients: Address[];
23
+ readonly recipients: readonly Address[];
24
24
  /**
25
25
  * The email addresses of the carbon copy (CC) recipients of the message.
26
26
  */
27
- readonly ccRecipients: Address[];
27
+ readonly ccRecipients: readonly Address[];
28
28
  /**
29
29
  * The email addresses of the blind carbon copy (BCC) recipients of the message.
30
30
  */
31
- readonly bccRecipients: Address[];
31
+ readonly bccRecipients: readonly Address[];
32
32
  /**
33
33
  * The email addresses of the reply-to recipients of the message.
34
34
  */
35
- readonly replyRecipients: Address[];
35
+ readonly replyRecipients: readonly Address[];
36
36
  /**
37
37
  * The attachments included in the email message. These are files that
38
38
  * are sent along with the email, such as documents, images, or other
@@ -40,7 +40,7 @@ interface Message {
40
40
  * object, which contains information about the attachment such as its
41
41
  * filename, content type, and content ID.
42
42
  */
43
- readonly attachments: Attachment[];
43
+ readonly attachments: readonly Attachment[];
44
44
  /**
45
45
  * The subject of the email message. This is typically a brief summary
46
46
  * of the content of the email, and is used to help the recipient identify
@@ -67,7 +67,7 @@ interface Message {
67
67
  /**
68
68
  * The tags associated with the email message.
69
69
  */
70
- readonly tags: string[];
70
+ readonly tags: readonly string[];
71
71
  /**
72
72
  * The headers of the email message. This is represented by
73
73
  * the {@link ImmutableHeaders} type, which is a supertype of
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upyo/core",
3
- "version": "0.2.0-dev.22+3cc9fea3",
3
+ "version": "0.2.0-dev.26+8f57766a",
4
4
  "description": "Simple email sending library for Node.js, Deno, Bun, and edge functions",
5
5
  "keywords": [
6
6
  "email",