@upyo/core 0.6.0-dev.311 → 0.6.0-dev.312

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.
@@ -1,3 +1,4 @@
1
+ const require_abort_signal = require('./abort-signal.cjs');
1
2
 
2
3
  //#region src/attachment.ts
3
4
  /**
@@ -6,8 +7,160 @@
6
7
  * @return `true` if the value is an {@link Attachment}, otherwise `false`.
7
8
  */
8
9
  function isAttachment(attachment) {
9
- return typeof attachment === "object" && attachment !== null && "inline" in attachment && "filename" in attachment && "content" in attachment && "contentType" in attachment && "contentId" in attachment && typeof attachment.inline === "boolean" && typeof attachment.filename === "string" && (attachment.content instanceof Uint8Array || attachment.content instanceof Promise && typeof attachment.content.then === "function") && typeof attachment.contentType === "string" && typeof attachment.contentId === "string";
10
+ return typeof attachment === "object" && attachment !== null && "inline" in attachment && "filename" in attachment && "content" in attachment && "contentType" in attachment && "contentId" in attachment && typeof attachment.inline === "boolean" && typeof attachment.filename === "string" && (attachment.content instanceof Uint8Array || typeof attachment.content === "function" || typeof Blob !== "undefined" && attachment.content instanceof Blob || attachment.content instanceof Promise && typeof attachment.content.then === "function") && typeof attachment.contentType === "string" && typeof attachment.contentId === "string";
11
+ }
12
+ function waitForContent(promise, signal) {
13
+ return new Promise((resolve, reject) => {
14
+ const abort = () => reject(signal.reason);
15
+ signal.addEventListener("abort", abort, { once: true });
16
+ promise.then(resolve, reject).finally(() => {
17
+ signal.removeEventListener("abort", abort);
18
+ });
19
+ if (signal.aborted) abort();
20
+ });
21
+ }
22
+ function blobIterator(blob) {
23
+ const reader = blob.stream().getReader();
24
+ let pending;
25
+ let released = false;
26
+ const release = () => {
27
+ if (!released) {
28
+ released = true;
29
+ reader.releaseLock();
30
+ }
31
+ };
32
+ return {
33
+ async next() {
34
+ pending = reader.read();
35
+ const result = await pending;
36
+ if (result.done) release();
37
+ return result.done ? {
38
+ done: true,
39
+ value: void 0
40
+ } : {
41
+ done: false,
42
+ value: result.value
43
+ };
44
+ },
45
+ async return() {
46
+ try {
47
+ await reader.cancel();
48
+ await pending;
49
+ } finally {
50
+ release();
51
+ }
52
+ return {
53
+ done: true,
54
+ value: void 0
55
+ };
56
+ }
57
+ };
58
+ }
59
+ /**
60
+ * Reads attachment chunks without prefetching. Early exit or cancellation
61
+ * aborts the source and requests cleanup without waiting for an uncooperative
62
+ * producer. Producers remain responsible for honoring cancellation.
63
+ * @param content Replayable content to read.
64
+ * @param signal Optional cancellation signal.
65
+ * @returns An iterable of byte chunks, valid until the next read.
66
+ * @throws {TypeError} If a source or yielded chunk is invalid.
67
+ * @throws {Error} If reading fails or cancellation is requested.
68
+ * @since 0.6.0
69
+ */
70
+ async function* iterateAttachmentContent(content, signal) {
71
+ const controller = new AbortController();
72
+ const combined = require_abort_signal.combineSignals(controller.signal, signal);
73
+ const ownedSignal = combined.signal;
74
+ let iterator;
75
+ let returned = false;
76
+ let done = false;
77
+ const close = () => {
78
+ if (iterator == null || returned || done) return;
79
+ returned = true;
80
+ try {
81
+ Promise.resolve(iterator.return?.()).catch(() => {});
82
+ } catch {}
83
+ };
84
+ const abort = () => close();
85
+ ownedSignal.addEventListener("abort", abort, { once: true });
86
+ try {
87
+ if (content instanceof Promise) content.catch(() => {});
88
+ ownedSignal.throwIfAborted();
89
+ if (content instanceof Uint8Array || content instanceof Promise) {
90
+ const bytes = await waitForContent(Promise.resolve(content), ownedSignal);
91
+ ownedSignal.throwIfAborted();
92
+ if (!(bytes instanceof Uint8Array)) throw new TypeError("Expected attachment bytes to be a Uint8Array.");
93
+ yield bytes;
94
+ done = true;
95
+ return;
96
+ }
97
+ if (typeof Blob !== "undefined" && content instanceof Blob) iterator = blobIterator(content);
98
+ else if (typeof content === "function") {
99
+ const opening = Promise.resolve(content(ownedSignal)).then((source) => {
100
+ iterator = source[Symbol.asyncIterator]();
101
+ if (ownedSignal.aborted) close();
102
+ return iterator;
103
+ });
104
+ iterator = await waitForContent(opening, ownedSignal);
105
+ } else throw new TypeError("Expected replayable attachment content.");
106
+ let iterations = 0;
107
+ let bytesRead = 0;
108
+ while (true) {
109
+ ownedSignal.throwIfAborted();
110
+ const result = await waitForContent(Promise.resolve(iterator.next()), ownedSignal);
111
+ ownedSignal.throwIfAborted();
112
+ if (result.done) {
113
+ done = true;
114
+ break;
115
+ }
116
+ if (!(result.value instanceof Uint8Array)) throw new TypeError("Expected an attachment chunk to be a Uint8Array.");
117
+ yield result.value;
118
+ bytesRead += result.value.length;
119
+ if (++iterations >= 256 || bytesRead >= 1024 * 1024) {
120
+ await waitForContent(new Promise((resolve) => setTimeout(resolve, 0)), ownedSignal);
121
+ iterations = bytesRead = 0;
122
+ }
123
+ }
124
+ } finally {
125
+ if (!done) {
126
+ controller.abort();
127
+ close();
128
+ }
129
+ ownedSignal.removeEventListener("abort", abort);
130
+ combined.cleanup();
131
+ }
132
+ }
133
+ /**
134
+ * Collects an attachment in memory. Existing arrays retain their identity;
135
+ * streamed chunks are copied before the producer can reuse their storage.
136
+ * @param content Replayable content to collect.
137
+ * @param signal Optional cancellation signal.
138
+ * @returns The complete attachment bytes.
139
+ * @throws {TypeError} If a source or yielded chunk is invalid.
140
+ * @throws {RangeError} If the attachment cannot fit in a byte array.
141
+ * @throws {Error} If reading fails or cancellation is requested.
142
+ * @since 0.6.0
143
+ */
144
+ async function readAttachmentContent(content, signal) {
145
+ const chunks = [];
146
+ let length = 0;
147
+ for await (const chunk of iterateAttachmentContent(content, signal)) {
148
+ if (content instanceof Uint8Array || content instanceof Promise) return chunk;
149
+ if (chunk.length === 0) continue;
150
+ chunks.push(new Uint8Array(chunk));
151
+ length += chunk.length;
152
+ if (!Number.isSafeInteger(length)) throw new RangeError("Attachment size exceeds the safe integer range.");
153
+ }
154
+ const bytes = new Uint8Array(length);
155
+ let offset = 0;
156
+ for (const chunk of chunks) {
157
+ bytes.set(chunk, offset);
158
+ offset += chunk.length;
159
+ }
160
+ return bytes;
10
161
  }
11
162
 
12
163
  //#endregion
13
- exports.isAttachment = isAttachment;
164
+ exports.isAttachment = isAttachment;
165
+ exports.iterateAttachmentContent = iterateAttachmentContent;
166
+ exports.readAttachmentContent = readAttachmentContent;
@@ -1,4 +1,20 @@
1
1
  //#region src/attachment.d.ts
2
+ /**
3
+ * Opens a fresh, independent attachment reader on every invocation. Readers
4
+ * must produce identical bytes for retries, concurrent sends, and DKIM passes.
5
+ * A yielded chunk must remain valid until the next read. Factories should honor
6
+ * the signal during acquisition and release resources when iteration ends.
7
+ * @param signal Cancellation signal owned by the reader.
8
+ * @returns A new iterable, optionally acquired asynchronously.
9
+ * @since 0.6.0
10
+ */
11
+ type AttachmentContentFactory = (signal?: AbortSignal) => AsyncIterable<Uint8Array> | Promise<AsyncIterable<Uint8Array>>;
12
+ /**
13
+ * Replayable attachment bytes. One-shot iterables are intentionally excluded;
14
+ * wrap them in a factory that opens a new reader for each invocation.
15
+ * @since 0.6.0
16
+ */
17
+ type AttachmentContent = Uint8Array | Promise<Uint8Array> | Blob | AttachmentContentFactory;
2
18
  /**
3
19
  * Represents an attachment in an email message.
4
20
  */
@@ -13,11 +29,10 @@ interface Attachment {
13
29
  */
14
30
  readonly filename: string;
15
31
  /**
16
- * The content of the attachment as a byte array. It can be a `Promise`
17
- * that resolves to a `Uint8Array`, allowing for asynchronous loading
18
- * of the attachment content.
32
+ * Replayable attachment content. Use {@link readAttachmentContent} to collect
33
+ * bytes or {@link iterateAttachmentContent} to read them incrementally.
19
34
  */
20
- readonly content: Uint8Array | Promise<Uint8Array>;
35
+ readonly content: AttachmentContent;
21
36
  /**
22
37
  * The media type of the attachment, which indicates the type of content
23
38
  * and how it should be handled by email clients.
@@ -35,5 +50,29 @@ interface Attachment {
35
50
  * @return `true` if the value is an {@link Attachment}, otherwise `false`.
36
51
  */
37
52
  declare function isAttachment(attachment: unknown): attachment is Attachment;
53
+ /**
54
+ * Reads attachment chunks without prefetching. Early exit or cancellation
55
+ * aborts the source and requests cleanup without waiting for an uncooperative
56
+ * producer. Producers remain responsible for honoring cancellation.
57
+ * @param content Replayable content to read.
58
+ * @param signal Optional cancellation signal.
59
+ * @returns An iterable of byte chunks, valid until the next read.
60
+ * @throws {TypeError} If a source or yielded chunk is invalid.
61
+ * @throws {Error} If reading fails or cancellation is requested.
62
+ * @since 0.6.0
63
+ */
64
+ declare function iterateAttachmentContent(content: AttachmentContent, signal?: AbortSignal): AsyncIterable<Uint8Array>;
65
+ /**
66
+ * Collects an attachment in memory. Existing arrays retain their identity;
67
+ * streamed chunks are copied before the producer can reuse their storage.
68
+ * @param content Replayable content to collect.
69
+ * @param signal Optional cancellation signal.
70
+ * @returns The complete attachment bytes.
71
+ * @throws {TypeError} If a source or yielded chunk is invalid.
72
+ * @throws {RangeError} If the attachment cannot fit in a byte array.
73
+ * @throws {Error} If reading fails or cancellation is requested.
74
+ * @since 0.6.0
75
+ */
76
+ declare function readAttachmentContent(content: AttachmentContent, signal?: AbortSignal): Promise<Uint8Array>;
38
77
  //#endregion
39
- export { Attachment, isAttachment };
78
+ export { Attachment, AttachmentContent, AttachmentContentFactory, isAttachment, iterateAttachmentContent, readAttachmentContent };
@@ -1,4 +1,20 @@
1
1
  //#region src/attachment.d.ts
2
+ /**
3
+ * Opens a fresh, independent attachment reader on every invocation. Readers
4
+ * must produce identical bytes for retries, concurrent sends, and DKIM passes.
5
+ * A yielded chunk must remain valid until the next read. Factories should honor
6
+ * the signal during acquisition and release resources when iteration ends.
7
+ * @param signal Cancellation signal owned by the reader.
8
+ * @returns A new iterable, optionally acquired asynchronously.
9
+ * @since 0.6.0
10
+ */
11
+ type AttachmentContentFactory = (signal?: AbortSignal) => AsyncIterable<Uint8Array> | Promise<AsyncIterable<Uint8Array>>;
12
+ /**
13
+ * Replayable attachment bytes. One-shot iterables are intentionally excluded;
14
+ * wrap them in a factory that opens a new reader for each invocation.
15
+ * @since 0.6.0
16
+ */
17
+ type AttachmentContent = Uint8Array | Promise<Uint8Array> | Blob | AttachmentContentFactory;
2
18
  /**
3
19
  * Represents an attachment in an email message.
4
20
  */
@@ -13,11 +29,10 @@ interface Attachment {
13
29
  */
14
30
  readonly filename: string;
15
31
  /**
16
- * The content of the attachment as a byte array. It can be a `Promise`
17
- * that resolves to a `Uint8Array`, allowing for asynchronous loading
18
- * of the attachment content.
32
+ * Replayable attachment content. Use {@link readAttachmentContent} to collect
33
+ * bytes or {@link iterateAttachmentContent} to read them incrementally.
19
34
  */
20
- readonly content: Uint8Array | Promise<Uint8Array>;
35
+ readonly content: AttachmentContent;
21
36
  /**
22
37
  * The media type of the attachment, which indicates the type of content
23
38
  * and how it should be handled by email clients.
@@ -35,5 +50,29 @@ interface Attachment {
35
50
  * @return `true` if the value is an {@link Attachment}, otherwise `false`.
36
51
  */
37
52
  declare function isAttachment(attachment: unknown): attachment is Attachment;
53
+ /**
54
+ * Reads attachment chunks without prefetching. Early exit or cancellation
55
+ * aborts the source and requests cleanup without waiting for an uncooperative
56
+ * producer. Producers remain responsible for honoring cancellation.
57
+ * @param content Replayable content to read.
58
+ * @param signal Optional cancellation signal.
59
+ * @returns An iterable of byte chunks, valid until the next read.
60
+ * @throws {TypeError} If a source or yielded chunk is invalid.
61
+ * @throws {Error} If reading fails or cancellation is requested.
62
+ * @since 0.6.0
63
+ */
64
+ declare function iterateAttachmentContent(content: AttachmentContent, signal?: AbortSignal): AsyncIterable<Uint8Array>;
65
+ /**
66
+ * Collects an attachment in memory. Existing arrays retain their identity;
67
+ * streamed chunks are copied before the producer can reuse their storage.
68
+ * @param content Replayable content to collect.
69
+ * @param signal Optional cancellation signal.
70
+ * @returns The complete attachment bytes.
71
+ * @throws {TypeError} If a source or yielded chunk is invalid.
72
+ * @throws {RangeError} If the attachment cannot fit in a byte array.
73
+ * @throws {Error} If reading fails or cancellation is requested.
74
+ * @since 0.6.0
75
+ */
76
+ declare function readAttachmentContent(content: AttachmentContent, signal?: AbortSignal): Promise<Uint8Array>;
38
77
  //#endregion
39
- export { Attachment, isAttachment };
78
+ export { Attachment, AttachmentContent, AttachmentContentFactory, isAttachment, iterateAttachmentContent, readAttachmentContent };
@@ -1,3 +1,5 @@
1
+ import { combineSignals } from "./abort-signal.js";
2
+
1
3
  //#region src/attachment.ts
2
4
  /**
3
5
  * Checks if the provided value is an {@link Attachment} object.
@@ -5,8 +7,158 @@
5
7
  * @return `true` if the value is an {@link Attachment}, otherwise `false`.
6
8
  */
7
9
  function isAttachment(attachment) {
8
- return typeof attachment === "object" && attachment !== null && "inline" in attachment && "filename" in attachment && "content" in attachment && "contentType" in attachment && "contentId" in attachment && typeof attachment.inline === "boolean" && typeof attachment.filename === "string" && (attachment.content instanceof Uint8Array || attachment.content instanceof Promise && typeof attachment.content.then === "function") && typeof attachment.contentType === "string" && typeof attachment.contentId === "string";
10
+ return typeof attachment === "object" && attachment !== null && "inline" in attachment && "filename" in attachment && "content" in attachment && "contentType" in attachment && "contentId" in attachment && typeof attachment.inline === "boolean" && typeof attachment.filename === "string" && (attachment.content instanceof Uint8Array || typeof attachment.content === "function" || typeof Blob !== "undefined" && attachment.content instanceof Blob || attachment.content instanceof Promise && typeof attachment.content.then === "function") && typeof attachment.contentType === "string" && typeof attachment.contentId === "string";
11
+ }
12
+ function waitForContent(promise, signal) {
13
+ return new Promise((resolve, reject) => {
14
+ const abort = () => reject(signal.reason);
15
+ signal.addEventListener("abort", abort, { once: true });
16
+ promise.then(resolve, reject).finally(() => {
17
+ signal.removeEventListener("abort", abort);
18
+ });
19
+ if (signal.aborted) abort();
20
+ });
21
+ }
22
+ function blobIterator(blob) {
23
+ const reader = blob.stream().getReader();
24
+ let pending;
25
+ let released = false;
26
+ const release = () => {
27
+ if (!released) {
28
+ released = true;
29
+ reader.releaseLock();
30
+ }
31
+ };
32
+ return {
33
+ async next() {
34
+ pending = reader.read();
35
+ const result = await pending;
36
+ if (result.done) release();
37
+ return result.done ? {
38
+ done: true,
39
+ value: void 0
40
+ } : {
41
+ done: false,
42
+ value: result.value
43
+ };
44
+ },
45
+ async return() {
46
+ try {
47
+ await reader.cancel();
48
+ await pending;
49
+ } finally {
50
+ release();
51
+ }
52
+ return {
53
+ done: true,
54
+ value: void 0
55
+ };
56
+ }
57
+ };
58
+ }
59
+ /**
60
+ * Reads attachment chunks without prefetching. Early exit or cancellation
61
+ * aborts the source and requests cleanup without waiting for an uncooperative
62
+ * producer. Producers remain responsible for honoring cancellation.
63
+ * @param content Replayable content to read.
64
+ * @param signal Optional cancellation signal.
65
+ * @returns An iterable of byte chunks, valid until the next read.
66
+ * @throws {TypeError} If a source or yielded chunk is invalid.
67
+ * @throws {Error} If reading fails or cancellation is requested.
68
+ * @since 0.6.0
69
+ */
70
+ async function* iterateAttachmentContent(content, signal) {
71
+ const controller = new AbortController();
72
+ const combined = combineSignals(controller.signal, signal);
73
+ const ownedSignal = combined.signal;
74
+ let iterator;
75
+ let returned = false;
76
+ let done = false;
77
+ const close = () => {
78
+ if (iterator == null || returned || done) return;
79
+ returned = true;
80
+ try {
81
+ Promise.resolve(iterator.return?.()).catch(() => {});
82
+ } catch {}
83
+ };
84
+ const abort = () => close();
85
+ ownedSignal.addEventListener("abort", abort, { once: true });
86
+ try {
87
+ if (content instanceof Promise) content.catch(() => {});
88
+ ownedSignal.throwIfAborted();
89
+ if (content instanceof Uint8Array || content instanceof Promise) {
90
+ const bytes = await waitForContent(Promise.resolve(content), ownedSignal);
91
+ ownedSignal.throwIfAborted();
92
+ if (!(bytes instanceof Uint8Array)) throw new TypeError("Expected attachment bytes to be a Uint8Array.");
93
+ yield bytes;
94
+ done = true;
95
+ return;
96
+ }
97
+ if (typeof Blob !== "undefined" && content instanceof Blob) iterator = blobIterator(content);
98
+ else if (typeof content === "function") {
99
+ const opening = Promise.resolve(content(ownedSignal)).then((source) => {
100
+ iterator = source[Symbol.asyncIterator]();
101
+ if (ownedSignal.aborted) close();
102
+ return iterator;
103
+ });
104
+ iterator = await waitForContent(opening, ownedSignal);
105
+ } else throw new TypeError("Expected replayable attachment content.");
106
+ let iterations = 0;
107
+ let bytesRead = 0;
108
+ while (true) {
109
+ ownedSignal.throwIfAborted();
110
+ const result = await waitForContent(Promise.resolve(iterator.next()), ownedSignal);
111
+ ownedSignal.throwIfAborted();
112
+ if (result.done) {
113
+ done = true;
114
+ break;
115
+ }
116
+ if (!(result.value instanceof Uint8Array)) throw new TypeError("Expected an attachment chunk to be a Uint8Array.");
117
+ yield result.value;
118
+ bytesRead += result.value.length;
119
+ if (++iterations >= 256 || bytesRead >= 1024 * 1024) {
120
+ await waitForContent(new Promise((resolve) => setTimeout(resolve, 0)), ownedSignal);
121
+ iterations = bytesRead = 0;
122
+ }
123
+ }
124
+ } finally {
125
+ if (!done) {
126
+ controller.abort();
127
+ close();
128
+ }
129
+ ownedSignal.removeEventListener("abort", abort);
130
+ combined.cleanup();
131
+ }
132
+ }
133
+ /**
134
+ * Collects an attachment in memory. Existing arrays retain their identity;
135
+ * streamed chunks are copied before the producer can reuse their storage.
136
+ * @param content Replayable content to collect.
137
+ * @param signal Optional cancellation signal.
138
+ * @returns The complete attachment bytes.
139
+ * @throws {TypeError} If a source or yielded chunk is invalid.
140
+ * @throws {RangeError} If the attachment cannot fit in a byte array.
141
+ * @throws {Error} If reading fails or cancellation is requested.
142
+ * @since 0.6.0
143
+ */
144
+ async function readAttachmentContent(content, signal) {
145
+ const chunks = [];
146
+ let length = 0;
147
+ for await (const chunk of iterateAttachmentContent(content, signal)) {
148
+ if (content instanceof Uint8Array || content instanceof Promise) return chunk;
149
+ if (chunk.length === 0) continue;
150
+ chunks.push(new Uint8Array(chunk));
151
+ length += chunk.length;
152
+ if (!Number.isSafeInteger(length)) throw new RangeError("Attachment size exceeds the safe integer range.");
153
+ }
154
+ const bytes = new Uint8Array(length);
155
+ let offset = 0;
156
+ for (const chunk of chunks) {
157
+ bytes.set(chunk, offset);
158
+ offset += chunk.length;
159
+ }
160
+ return bytes;
9
161
  }
10
162
 
11
163
  //#endregion
12
- export { isAttachment };
164
+ export { isAttachment, iterateAttachmentContent, readAttachmentContent };
package/dist/index.cjs CHANGED
@@ -15,5 +15,7 @@ exports.createReceiptError = require_receipt.createReceiptError;
15
15
  exports.formatAddress = require_address.formatAddress;
16
16
  exports.isAttachment = require_attachment.isAttachment;
17
17
  exports.isEmailAddress = require_address.isEmailAddress;
18
+ exports.iterateAttachmentContent = require_attachment.iterateAttachmentContent;
18
19
  exports.parseAddress = require_address.parseAddress;
19
- exports.parseRetryAfter = require_receipt.parseRetryAfter;
20
+ exports.parseRetryAfter = require_receipt.parseRetryAfter;
21
+ exports.readAttachmentContent = require_attachment.readAttachmentContent;
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { CombinedSignal, combineSignals } from "./abort-signal.cjs";
2
2
  import { Address, EmailAddress, formatAddress, isEmailAddress, parseAddress } from "./address.cjs";
3
- import { Attachment, isAttachment } from "./attachment.cjs";
3
+ import { Attachment, AttachmentContent, AttachmentContentFactory, isAttachment, iterateAttachmentContent, readAttachmentContent } from "./attachment.cjs";
4
4
  import { Priority, comparePriority } from "./priority.cjs";
5
5
  import { ImmutableHeaders, Message, MessageConstructor, MessageContent, createMessage } from "./message.cjs";
6
6
  import { CreateFailedReceiptOptions, CreateReceiptErrorOptions, Receipt, ReceiptError, ReceiptErrorCategory, ReceiptErrorClassification, classifyHttpStatus, classifyReceiptError, createFailedReceipt, createReceiptError, parseRetryAfter } from "./receipt.cjs";
7
7
  import { Transport, TransportOptions } from "./transport.cjs";
8
- export { Address, Attachment, CombinedSignal, CreateFailedReceiptOptions, CreateReceiptErrorOptions, EmailAddress, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, ReceiptError, ReceiptErrorCategory, ReceiptErrorClassification, Transport, TransportOptions, classifyHttpStatus, classifyReceiptError, combineSignals, comparePriority, createFailedReceipt, createMessage, createReceiptError, formatAddress, isAttachment, isEmailAddress, parseAddress, parseRetryAfter };
8
+ export { Address, Attachment, AttachmentContent, AttachmentContentFactory, CombinedSignal, CreateFailedReceiptOptions, CreateReceiptErrorOptions, EmailAddress, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, ReceiptError, ReceiptErrorCategory, ReceiptErrorClassification, Transport, TransportOptions, classifyHttpStatus, classifyReceiptError, combineSignals, comparePriority, createFailedReceipt, createMessage, createReceiptError, formatAddress, isAttachment, isEmailAddress, iterateAttachmentContent, parseAddress, parseRetryAfter, readAttachmentContent };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { CombinedSignal, combineSignals } from "./abort-signal.js";
2
2
  import { Address, EmailAddress, formatAddress, isEmailAddress, parseAddress } from "./address.js";
3
- import { Attachment, isAttachment } from "./attachment.js";
3
+ import { Attachment, AttachmentContent, AttachmentContentFactory, isAttachment, iterateAttachmentContent, readAttachmentContent } from "./attachment.js";
4
4
  import { Priority, comparePriority } from "./priority.js";
5
5
  import { ImmutableHeaders, Message, MessageConstructor, MessageContent, createMessage } from "./message.js";
6
6
  import { CreateFailedReceiptOptions, CreateReceiptErrorOptions, Receipt, ReceiptError, ReceiptErrorCategory, ReceiptErrorClassification, classifyHttpStatus, classifyReceiptError, createFailedReceipt, createReceiptError, parseRetryAfter } from "./receipt.js";
7
7
  import { Transport, TransportOptions } from "./transport.js";
8
- export { Address, Attachment, CombinedSignal, CreateFailedReceiptOptions, CreateReceiptErrorOptions, EmailAddress, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, ReceiptError, ReceiptErrorCategory, ReceiptErrorClassification, Transport, TransportOptions, classifyHttpStatus, classifyReceiptError, combineSignals, comparePriority, createFailedReceipt, createMessage, createReceiptError, formatAddress, isAttachment, isEmailAddress, parseAddress, parseRetryAfter };
8
+ export { Address, Attachment, AttachmentContent, AttachmentContentFactory, CombinedSignal, CreateFailedReceiptOptions, CreateReceiptErrorOptions, EmailAddress, ImmutableHeaders, Message, MessageConstructor, MessageContent, Priority, Receipt, ReceiptError, ReceiptErrorCategory, ReceiptErrorClassification, Transport, TransportOptions, classifyHttpStatus, classifyReceiptError, combineSignals, comparePriority, createFailedReceipt, createMessage, createReceiptError, formatAddress, isAttachment, isEmailAddress, iterateAttachmentContent, parseAddress, parseRetryAfter, readAttachmentContent };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { combineSignals } from "./abort-signal.js";
2
2
  import { formatAddress, isEmailAddress, parseAddress } from "./address.js";
3
- import { isAttachment } from "./attachment.js";
3
+ import { isAttachment, iterateAttachmentContent, readAttachmentContent } from "./attachment.js";
4
4
  import { createMessage } from "./message.js";
5
5
  import { comparePriority } from "./priority.js";
6
6
  import { classifyHttpStatus, classifyReceiptError, createFailedReceipt, createReceiptError, parseRetryAfter } from "./receipt.js";
7
7
 
8
- export { classifyHttpStatus, classifyReceiptError, combineSignals, comparePriority, createFailedReceipt, createMessage, createReceiptError, formatAddress, isAttachment, isEmailAddress, parseAddress, parseRetryAfter };
8
+ export { classifyHttpStatus, classifyReceiptError, combineSignals, comparePriority, createFailedReceipt, createMessage, createReceiptError, formatAddress, isAttachment, isEmailAddress, iterateAttachmentContent, parseAddress, parseRetryAfter, readAttachmentContent };
package/dist/message.cjs CHANGED
@@ -37,7 +37,7 @@ function createMessage(constructor) {
37
37
  if (attachment instanceof File) return {
38
38
  inline: false,
39
39
  filename: attachment.name,
40
- content: attachment.arrayBuffer().then((b) => new Uint8Array(b)),
40
+ content: attachment,
41
41
  contentType: attachment.type == null || attachment.type === "" ? "application/octet-stream" : attachment.type,
42
42
  contentId: `${crypto.randomUUID()}@${sender.address.replace(/^[^@]*@/, "")}`
43
43
  };
package/dist/message.js CHANGED
@@ -37,7 +37,7 @@ function createMessage(constructor) {
37
37
  if (attachment instanceof File) return {
38
38
  inline: false,
39
39
  filename: attachment.name,
40
- content: attachment.arrayBuffer().then((b) => new Uint8Array(b)),
40
+ content: attachment,
41
41
  contentType: attachment.type == null || attachment.type === "" ? "application/octet-stream" : attachment.type,
42
42
  contentId: `${crypto.randomUUID()}@${sender.address.replace(/^[^@]*@/, "")}`
43
43
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upyo/core",
3
- "version": "0.6.0-dev.311",
3
+ "version": "0.6.0-dev.312",
4
4
  "description": "Simple email sending library for Node.js, Deno, Bun, and edge functions",
5
5
  "keywords": [
6
6
  "email",