@framers/agentos-ext-channel-email 0.1.2 → 0.2.1
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 +108 -0
- package/dist/EmailChannelAdapter.d.ts +9 -0
- package/dist/EmailChannelAdapter.d.ts.map +1 -1
- package/dist/EmailChannelAdapter.js +14 -1
- package/dist/EmailChannelAdapter.js.map +1 -1
- package/dist/EmailService.d.ts +43 -3
- package/dist/EmailService.d.ts.map +1 -1
- package/dist/EmailService.js +95 -17
- package/dist/EmailService.js.map +1 -1
- package/dist/ResendTransport.d.ts +101 -0
- package/dist/ResendTransport.d.ts.map +1 -0
- package/dist/ResendTransport.js +194 -0
- package/dist/ResendTransport.js.map +1 -0
- package/dist/agentAttachments.d.ts +39 -0
- package/dist/agentAttachments.d.ts.map +1 -0
- package/dist/agentAttachments.js +104 -0
- package/dist/agentAttachments.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -12
- package/dist/index.js.map +1 -1
- package/dist/messageText.d.ts +24 -0
- package/dist/messageText.d.ts.map +1 -0
- package/dist/messageText.js +38 -0
- package/dist/messageText.js.map +1 -0
- package/dist/tools/reply.d.ts +5 -0
- package/dist/tools/reply.d.ts.map +1 -1
- package/dist/tools/reply.js +5 -0
- package/dist/tools/reply.js.map +1 -1
- package/dist/tools/send.d.ts +13 -1
- package/dist/tools/send.d.ts.map +1 -1
- package/dist/tools/send.js +14 -3
- package/dist/tools/send.js.map +1 -1
- package/manifest.json +4 -4
- package/package.json +10 -5
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview A transport for Resend's HTTPS API: one `POST /emails` a message, the API key as the bearer, an
|
|
3
|
+
* `Idempotency-Key` when the caller gives one, the text and the HTML part in one call, and Resend's own retry terms
|
|
4
|
+
* inside one deadline. A refusal keeps the status and Resend's error name, never its message, which can quote an
|
|
5
|
+
* address.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* An attachment path Resend fetches the file from itself: an `http:` or `https:` address. The agent surfaces'
|
|
9
|
+
* attachment check passes an address by this same test, so an address it passes is never read here.
|
|
10
|
+
*/
|
|
11
|
+
export declare const REMOTE_ADDRESS: RegExp;
|
|
12
|
+
/** What the transport needs: the key, and where and as what it calls. */
|
|
13
|
+
export interface ResendOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The API key, or a function that answers it at each send (a key file read when a message goes out). Whitespace around
|
|
16
|
+
* it, such as a key file's final line break, is trimmed.
|
|
17
|
+
*/
|
|
18
|
+
apiKey: string | (() => string);
|
|
19
|
+
/** The API's origin with no trailing slash; Resend's own when unset. */
|
|
20
|
+
baseUrl?: string;
|
|
21
|
+
/** The `User-Agent` every request carries, which Resend requires; the pack's name when unset. */
|
|
22
|
+
userAgent?: string;
|
|
23
|
+
/** The longest one send may take, its retries and their waits included; fifteen seconds when unset. */
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
/** The most retries one send makes; two when unset. */
|
|
26
|
+
maxRetries?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One file sent with a message: its `content` (Base64 on the wire), or a `path`. An `http:` or `https:` path is the
|
|
30
|
+
* address Resend fetches the file from; a `data:` address or a file on this host is read here and sent as content, as
|
|
31
|
+
* nodemailer reads both over SMTP. With `content` given, a path Resend cannot fetch is left out. This process reads a
|
|
32
|
+
* file path, so it must come from the developer's code and never from a model's output: the pack's `emailSend` tool
|
|
33
|
+
* and channel adapter accept only `content`, `data:` addresses and, through Resend, `http(s)` addresses.
|
|
34
|
+
*/
|
|
35
|
+
export interface OutgoingAttachment {
|
|
36
|
+
filename: string;
|
|
37
|
+
content?: string | Buffer;
|
|
38
|
+
path?: string;
|
|
39
|
+
contentType?: string;
|
|
40
|
+
}
|
|
41
|
+
/** One message as the transport sends it. */
|
|
42
|
+
export interface OutgoingEmail {
|
|
43
|
+
/** The From header; a display name is allowed, as in "Example <hello@example.com>". */
|
|
44
|
+
from: string;
|
|
45
|
+
/** The one recipient. */
|
|
46
|
+
to: string;
|
|
47
|
+
subject: string;
|
|
48
|
+
/** The plain-text part. */
|
|
49
|
+
text: string;
|
|
50
|
+
/** The HTML part, sent in the same call. */
|
|
51
|
+
html?: string;
|
|
52
|
+
replyTo?: string;
|
|
53
|
+
cc?: string;
|
|
54
|
+
bcc?: string;
|
|
55
|
+
/** Headers added to the message, such as `In-Reply-To` and `References` for a reply. */
|
|
56
|
+
headers?: Record<string, string>;
|
|
57
|
+
/**
|
|
58
|
+
* Resend's `Idempotency-Key`: a second request under the same key within 24 hours delivers nothing more. At most 256
|
|
59
|
+
* characters, and never personal data.
|
|
60
|
+
*/
|
|
61
|
+
idempotencyKey?: string;
|
|
62
|
+
attachments?: OutgoingAttachment[];
|
|
63
|
+
}
|
|
64
|
+
/** A send Resend answered outside 2xx: its status, Resend's error name (`unknown` when it named none) and the wait it asked for. */
|
|
65
|
+
export declare class EmailApiError extends Error {
|
|
66
|
+
/** The type's own name. */
|
|
67
|
+
name: string;
|
|
68
|
+
/** The HTTP status Resend answered with. */
|
|
69
|
+
readonly status: number;
|
|
70
|
+
/** Resend's error name, such as `rate_limit_exceeded`, or `unknown`. */
|
|
71
|
+
readonly type: string;
|
|
72
|
+
/** The seconds the answer's `retry-after` header asked for, or null. */
|
|
73
|
+
readonly retryAfterSeconds: number | null;
|
|
74
|
+
constructor(status: number, type: string, retryAfterSeconds: number | null);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The wait before the next try, in seconds, or null when the refusal is not tried again: a rate limit always (it was
|
|
78
|
+
* refused before anything was sent), and under an idempotency key a 409 `concurrent_idempotent_requests` and any 5xx,
|
|
79
|
+
* which Resend's errors page answers with "Try the request again later"; never a quota, a validation error or
|
|
80
|
+
* `invalid_idempotent_request`. The wait is the answer's `retry-after`, else one second, then two.
|
|
81
|
+
*/
|
|
82
|
+
export declare function retryWaitSeconds(error: EmailApiError, keyed: boolean, retry: number): number | null;
|
|
83
|
+
/** Resend's send call. */
|
|
84
|
+
export declare class ResendTransport {
|
|
85
|
+
private readonly options;
|
|
86
|
+
constructor(options: ResendOptions);
|
|
87
|
+
/**
|
|
88
|
+
* Sends one message: the key read once and trimmed, then `POST /emails`, tried again on Resend's terms while the
|
|
89
|
+
* deadline allows. Throws an `Error` before any request when the key, the idempotency key or the User-Agent holds a
|
|
90
|
+
* character an HTTP header cannot carry, with a message that names the field and none of its value; `EmailApiError`
|
|
91
|
+
* for a refusal; and what `fetch` throws for a connection that fails (`TypeError`) or the deadline (`TimeoutError`),
|
|
92
|
+
* so a caller can tell them apart. A 2xx answer always resolves, since Resend has taken the email: its `messageId` is
|
|
93
|
+
* the empty string when the answer names no id or its body cannot be read before the deadline. An attachment from a
|
|
94
|
+
* `data:` address or a file on this host is read first, before the deadline starts; a file that cannot be read throws
|
|
95
|
+
* its own error before any request.
|
|
96
|
+
*/
|
|
97
|
+
send(message: OutgoingEmail): Promise<{
|
|
98
|
+
messageId: string;
|
|
99
|
+
}>;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=ResendTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResendTransport.d.ts","sourceRoot":"","sources":["../src/ResendTransport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2BH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAkB,CAAC;AAK9C,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAChC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uGAAuG;IACvG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC5B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACpC;AAED,oIAAoI;AACpI,qBAAa,aAAc,SAAQ,KAAK;IACtC,2BAA2B;IAClB,IAAI,SAAmB;IAEhC,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,wEAAwE;IACxE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;gBAE9B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,IAAI;CAM3E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGnG;AAsFD,0BAA0B;AAC1B,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,OAAO,EAAE,aAAa;IAIlC;;;;;;;;;OASG;IACG,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAwBnE"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview A transport for Resend's HTTPS API: one `POST /emails` a message, the API key as the bearer, an
|
|
4
|
+
* `Idempotency-Key` when the caller gives one, the text and the HTML part in one call, and Resend's own retry terms
|
|
5
|
+
* inside one deadline. A refusal keeps the status and Resend's error name, never its message, which can quote an
|
|
6
|
+
* address.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ResendTransport = exports.EmailApiError = exports.REMOTE_ADDRESS = void 0;
|
|
10
|
+
exports.retryWaitSeconds = retryWaitSeconds;
|
|
11
|
+
const promises_1 = require("node:fs/promises");
|
|
12
|
+
/** Resend's API origin. */
|
|
13
|
+
const RESEND_API = 'https://api.resend.com';
|
|
14
|
+
/** The `User-Agent` sent when the caller names none: Resend refuses a request without one. */
|
|
15
|
+
const DEFAULT_USER_AGENT = 'agentos-ext-channel-email';
|
|
16
|
+
/** The longest one send may take when the caller names no deadline, retries and their waits included. */
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 15000;
|
|
18
|
+
/** The retries one send makes at most when the caller names no number. */
|
|
19
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
20
|
+
/** The shape of an error name Resend gives, such as `validation_error`; any other value is read as `unknown`. */
|
|
21
|
+
const ERROR_NAME = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
22
|
+
/**
|
|
23
|
+
* A character an HTTP header value cannot carry through Node's `fetch` (undici), whose own header check this is: only a
|
|
24
|
+
* tab, a space, the visible ASCII characters and U+0080 to U+00FF pass. `Headers` throws a `TypeError` for a character
|
|
25
|
+
* above U+00FF and for a NUL, CR or LF inside the value (that one quoting the whole value, key and all), and the
|
|
26
|
+
* request fails for any other control character.
|
|
27
|
+
*/
|
|
28
|
+
const NOT_A_HEADER_CHARACTER = /[^\t\x20-\x7e\x80-\xff]/;
|
|
29
|
+
/**
|
|
30
|
+
* An attachment path Resend fetches the file from itself: an `http:` or `https:` address. The agent surfaces'
|
|
31
|
+
* attachment check passes an address by this same test, so an address it passes is never read here.
|
|
32
|
+
*/
|
|
33
|
+
exports.REMOTE_ADDRESS = /^https?:\/\//i;
|
|
34
|
+
/** A `data:` address, which holds its attachment's bytes in itself. */
|
|
35
|
+
const DATA_ADDRESS = /^data:/i;
|
|
36
|
+
/** A send Resend answered outside 2xx: its status, Resend's error name (`unknown` when it named none) and the wait it asked for. */
|
|
37
|
+
class EmailApiError extends Error {
|
|
38
|
+
constructor(status, type, retryAfterSeconds) {
|
|
39
|
+
super(`Resend refused the email with ${status} ${type}`);
|
|
40
|
+
/** The type's own name. */
|
|
41
|
+
this.name = 'EmailApiError';
|
|
42
|
+
this.status = status;
|
|
43
|
+
this.type = type;
|
|
44
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.EmailApiError = EmailApiError;
|
|
48
|
+
/**
|
|
49
|
+
* The wait before the next try, in seconds, or null when the refusal is not tried again: a rate limit always (it was
|
|
50
|
+
* refused before anything was sent), and under an idempotency key a 409 `concurrent_idempotent_requests` and any 5xx,
|
|
51
|
+
* which Resend's errors page answers with "Try the request again later"; never a quota, a validation error or
|
|
52
|
+
* `invalid_idempotent_request`. The wait is the answer's `retry-after`, else one second, then two.
|
|
53
|
+
*/
|
|
54
|
+
function retryWaitSeconds(error, keyed, retry) {
|
|
55
|
+
const tryAgain = error.type === 'rate_limit_exceeded' || (keyed && (error.type === 'concurrent_idempotent_requests' || error.status >= 500));
|
|
56
|
+
return tryAgain ? (error.retryAfterSeconds ?? retry) : null;
|
|
57
|
+
}
|
|
58
|
+
/** The answer's `retry-after` in seconds, or null when it is absent or not a number of seconds. */
|
|
59
|
+
function retryAfterOf(headers) {
|
|
60
|
+
const raw = headers.get('retry-after');
|
|
61
|
+
if (raw === null || raw.trim() === '')
|
|
62
|
+
return null;
|
|
63
|
+
const seconds = Number(raw);
|
|
64
|
+
return Number.isFinite(seconds) && seconds >= 0 ? seconds : null;
|
|
65
|
+
}
|
|
66
|
+
/** A refusal read from Resend's answer: the status, the error's name when it is a word, the wait; the rest dropped. */
|
|
67
|
+
async function refusalOf(answer) {
|
|
68
|
+
let type = 'unknown';
|
|
69
|
+
try {
|
|
70
|
+
const body = await answer.json();
|
|
71
|
+
const name = typeof body === 'object' && body !== null && 'name' in body ? body.name : undefined;
|
|
72
|
+
if (typeof name === 'string' && ERROR_NAME.test(name))
|
|
73
|
+
type = name;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// not JSON: the name stays unknown
|
|
77
|
+
}
|
|
78
|
+
return new EmailApiError(answer.status, type, retryAfterOf(answer.headers));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The message's id from a 2xx answer, or the empty string when the answer's body names none or cannot be read (not
|
|
82
|
+
* JSON, no `id`, or cut off by the deadline). A 2xx means Resend took the email, so the send still succeeds: a failure
|
|
83
|
+
* reported here would lead a caller to send the email a second time.
|
|
84
|
+
*/
|
|
85
|
+
async function messageIdOf(answer) {
|
|
86
|
+
try {
|
|
87
|
+
const body = await answer.json();
|
|
88
|
+
const id = typeof body === 'object' && body !== null && 'id' in body ? body.id : undefined;
|
|
89
|
+
return typeof id === 'string' ? id : '';
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** What a path Resend cannot fetch holds: a `data:` address decoded, with its media type, or a file on this host read. */
|
|
96
|
+
async function readAttachment(path) {
|
|
97
|
+
if (DATA_ADDRESS.test(path)) {
|
|
98
|
+
// fetch decodes a data: address itself, Base64 or percent-encoded, by the Fetch standard's data: URL processor.
|
|
99
|
+
const decoded = await fetch(path);
|
|
100
|
+
return { bytes: Buffer.from(await decoded.arrayBuffer()), type: decoded.headers.get('content-type') };
|
|
101
|
+
}
|
|
102
|
+
return { bytes: await (0, promises_1.readFile)(path), type: null };
|
|
103
|
+
}
|
|
104
|
+
/** One attachment in Resend's shape: an `http:` or `https:` path as Resend's own, any other path read into content. */
|
|
105
|
+
async function attachmentOf(attachment) {
|
|
106
|
+
const shaped = { filename: attachment.filename };
|
|
107
|
+
if (attachment.content !== undefined) {
|
|
108
|
+
shaped.content = (typeof attachment.content === 'string' ? Buffer.from(attachment.content) : attachment.content).toString('base64');
|
|
109
|
+
}
|
|
110
|
+
if (attachment.path !== undefined && exports.REMOTE_ADDRESS.test(attachment.path)) {
|
|
111
|
+
shaped.path = attachment.path;
|
|
112
|
+
}
|
|
113
|
+
else if (attachment.path !== undefined && attachment.content === undefined) {
|
|
114
|
+
const { bytes, type } = await readAttachment(attachment.path);
|
|
115
|
+
shaped.content = bytes.toString('base64');
|
|
116
|
+
if (type !== null)
|
|
117
|
+
shaped.content_type = type;
|
|
118
|
+
}
|
|
119
|
+
if (attachment.contentType !== undefined)
|
|
120
|
+
shaped.content_type = attachment.contentType;
|
|
121
|
+
return shaped;
|
|
122
|
+
}
|
|
123
|
+
/** The request's JSON body: the fields Resend's send call names, and only those the message carries. */
|
|
124
|
+
async function bodyOf(message) {
|
|
125
|
+
const body = { from: message.from, to: [message.to], subject: message.subject, text: message.text };
|
|
126
|
+
if (message.html !== undefined)
|
|
127
|
+
body.html = message.html;
|
|
128
|
+
if (message.replyTo !== undefined)
|
|
129
|
+
body.reply_to = message.replyTo;
|
|
130
|
+
if (message.cc !== undefined)
|
|
131
|
+
body.cc = message.cc;
|
|
132
|
+
if (message.bcc !== undefined)
|
|
133
|
+
body.bcc = message.bcc;
|
|
134
|
+
if (message.headers !== undefined)
|
|
135
|
+
body.headers = message.headers;
|
|
136
|
+
if (message.attachments !== undefined && message.attachments.length > 0)
|
|
137
|
+
body.attachments = await Promise.all(message.attachments.map(attachmentOf));
|
|
138
|
+
return body;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Throws an `Error` that names the field and none of its value when a header's value holds a character a header cannot
|
|
142
|
+
* carry, so the send stops before any request rather than inside `fetch` with a `TypeError` that reads as a failed
|
|
143
|
+
* connection.
|
|
144
|
+
*/
|
|
145
|
+
function requireHeaderValue(value, field) {
|
|
146
|
+
if (NOT_A_HEADER_CHARACTER.test(value))
|
|
147
|
+
throw new Error(`${field} holds a character an HTTP header cannot carry`);
|
|
148
|
+
}
|
|
149
|
+
/** Resend's send call. */
|
|
150
|
+
class ResendTransport {
|
|
151
|
+
constructor(options) {
|
|
152
|
+
this.options = options;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Sends one message: the key read once and trimmed, then `POST /emails`, tried again on Resend's terms while the
|
|
156
|
+
* deadline allows. Throws an `Error` before any request when the key, the idempotency key or the User-Agent holds a
|
|
157
|
+
* character an HTTP header cannot carry, with a message that names the field and none of its value; `EmailApiError`
|
|
158
|
+
* for a refusal; and what `fetch` throws for a connection that fails (`TypeError`) or the deadline (`TimeoutError`),
|
|
159
|
+
* so a caller can tell them apart. A 2xx answer always resolves, since Resend has taken the email: its `messageId` is
|
|
160
|
+
* the empty string when the answer names no id or its body cannot be read before the deadline. An attachment from a
|
|
161
|
+
* `data:` address or a file on this host is read first, before the deadline starts; a file that cannot be read throws
|
|
162
|
+
* its own error before any request.
|
|
163
|
+
*/
|
|
164
|
+
async send(message) {
|
|
165
|
+
// String() keeps the coercion a template literal gave a key answered outside TypeScript, such as a Buffer.
|
|
166
|
+
const key = String(typeof this.options.apiKey === 'function' ? this.options.apiKey() : this.options.apiKey).trim();
|
|
167
|
+
requireHeaderValue(key, 'The Resend API key');
|
|
168
|
+
const userAgent = this.options.userAgent ?? DEFAULT_USER_AGENT;
|
|
169
|
+
requireHeaderValue(userAgent, 'The User-Agent');
|
|
170
|
+
if (message.idempotencyKey !== undefined)
|
|
171
|
+
requireHeaderValue(message.idempotencyKey, 'The idempotency key');
|
|
172
|
+
const body = JSON.stringify(await bodyOf(message));
|
|
173
|
+
const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
174
|
+
const maxRetries = this.options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
175
|
+
const deadline = Date.now() + timeoutMs;
|
|
176
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
177
|
+
const headers = new Headers({ Authorization: `Bearer ${key}`, 'Content-Type': 'application/json', 'User-Agent': userAgent });
|
|
178
|
+
if (message.idempotencyKey !== undefined)
|
|
179
|
+
headers.set('Idempotency-Key', message.idempotencyKey);
|
|
180
|
+
const url = `${(this.options.baseUrl ?? RESEND_API).replace(/\/+$/, '')}/emails`;
|
|
181
|
+
for (let retry = 0;; retry += 1) {
|
|
182
|
+
const answer = await fetch(url, { method: 'POST', headers, body, redirect: 'error', signal });
|
|
183
|
+
if (answer.ok)
|
|
184
|
+
return { messageId: await messageIdOf(answer) };
|
|
185
|
+
const error = await refusalOf(answer);
|
|
186
|
+
const wait = retry < maxRetries ? retryWaitSeconds(error, message.idempotencyKey !== undefined, retry + 1) : null;
|
|
187
|
+
if (wait === null || Date.now() + wait * 1000 >= deadline)
|
|
188
|
+
throw error;
|
|
189
|
+
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
exports.ResendTransport = ResendTransport;
|
|
194
|
+
//# sourceMappingURL=ResendTransport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResendTransport.js","sourceRoot":"","sources":["../src/ResendTransport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The attachment check of the pack's two agent surfaces, the `emailSend` tool and the channel adapter,
|
|
3
|
+
* whose arguments a model writes. `EmailService.sendEmail` reads a file path on this host, and through SMTP fetches an
|
|
4
|
+
* `http:` or `https:` address from this host, so text that steers an agent could have it mail any file the process can
|
|
5
|
+
* read, or the answer of an address only this host reaches. The two surfaces pass on only what neither transport reads
|
|
6
|
+
* or fetches here, and they send the copy the check made, so what is sent is what was checked.
|
|
7
|
+
*/
|
|
8
|
+
/** One attachment as the check read it: its own values, each read once, with a Buffer's bytes copied. */
|
|
9
|
+
export interface CheckedAttachment {
|
|
10
|
+
/** The name the message gives the file. */
|
|
11
|
+
filename?: string;
|
|
12
|
+
/** The file's content: text, or a new Buffer holding the bytes the caller gave. */
|
|
13
|
+
content?: string | Buffer;
|
|
14
|
+
/** A `data:` address, or an `http(s)` address when the service sends through Resend. */
|
|
15
|
+
path?: string;
|
|
16
|
+
/** The content's type; the transport works it out from the filename or the path when it is not given. */
|
|
17
|
+
contentType?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Checks the attachments an agent named and returns the copies the surface sends, or throws an `Error` when one would
|
|
21
|
+
* make this process read a file or fetch an address, before anything is sent and without reading the file or fetching
|
|
22
|
+
* the address. Each attachment must be an object, and the check reads its own `filename`, `content`, `path` and
|
|
23
|
+
* `contentType` once each, refusing one given through a getter or a setter: a copy holds those values alone, so a value
|
|
24
|
+
* read again later, or any other property, never reaches a transport. An attachment passes when its `content`, if
|
|
25
|
+
* given, is a string or a Buffer (copied into a new Buffer), its `path`, if given, is a `data:` address, or an `http:`
|
|
26
|
+
* or `https:` address while the service sends through Resend, whose servers fetch it, and its `filename` and
|
|
27
|
+
* `contentType`, if given, are strings (`null` leaves either out). A path is checked even next to `content`, since
|
|
28
|
+
* nodemailer reads `path` first, and `content` of any other kind is refused, since nodemailer reads the `path` or
|
|
29
|
+
* fetches the `href` of a content object. The message names the attachment's `filename`, or its place in the list when
|
|
30
|
+
* it has none, and the rule, never its path.
|
|
31
|
+
*
|
|
32
|
+
* @param attachments The attachments as the surface took them. `undefined` or `null` passes as `undefined`, since there
|
|
33
|
+
* is nothing to send. Any other value that is not a list is refused, since nodemailer takes a single attachment object
|
|
34
|
+
* as a list of one and reads its `path`.
|
|
35
|
+
* @param throughResend Whether the service sends through Resend, as `EmailService.transport` tells.
|
|
36
|
+
* @returns The copies, in the order given, or `undefined` for no attachments.
|
|
37
|
+
*/
|
|
38
|
+
export declare function requireAgentAttachments(attachments: unknown, throughResend: boolean): CheckedAttachment[] | undefined;
|
|
39
|
+
//# sourceMappingURL=agentAttachments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentAttachments.d.ts","sourceRoot":"","sources":["../src/agentAttachments.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqBH,yGAAyG;AACzG,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,wFAAwF;IACxF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yGAAyG;IACzG,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA8CD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAMrH"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview The attachment check of the pack's two agent surfaces, the `emailSend` tool and the channel adapter,
|
|
4
|
+
* whose arguments a model writes. `EmailService.sendEmail` reads a file path on this host, and through SMTP fetches an
|
|
5
|
+
* `http:` or `https:` address from this host, so text that steers an agent could have it mail any file the process can
|
|
6
|
+
* read, or the answer of an address only this host reaches. The two surfaces pass on only what neither transport reads
|
|
7
|
+
* or fetches here, and they send the copy the check made, so what is sent is what was checked.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.requireAgentAttachments = requireAgentAttachments;
|
|
11
|
+
const node_util_1 = require("node:util");
|
|
12
|
+
const ResendTransport_js_1 = require("./ResendTransport.js");
|
|
13
|
+
/**
|
|
14
|
+
* A `data:` address up to the comma that ends its header. nodemailer decodes a path only in this form, with `data:` in
|
|
15
|
+
* lowercase and a comma, and reads any other path that is not an `http(s)` address as a file.
|
|
16
|
+
*/
|
|
17
|
+
const DATA_ADDRESS = /^data:[^,]*,/;
|
|
18
|
+
/** The rule a refusal names when the service sends through Resend. */
|
|
19
|
+
const THROUGH_RESEND = 'an attachment takes its content as a string, a data: address or an http(s) address; files on this machine are not read';
|
|
20
|
+
/** The rule a refusal names when the service sends through SMTP. */
|
|
21
|
+
const THROUGH_SMTP = 'through SMTP an attachment takes its content as a string or a data: address; files on this machine are not read and addresses are not fetched';
|
|
22
|
+
/** The properties the check reads from an attachment and copies, in this order; any other property is left out. */
|
|
23
|
+
const COPIED = ['filename', 'content', 'path', 'contentType'];
|
|
24
|
+
/** The error a refusal throws: it names the attachment and the reason, never a path. */
|
|
25
|
+
function refused(named, reason) {
|
|
26
|
+
return new Error(`The attachment ${named} was refused: ${reason}`);
|
|
27
|
+
}
|
|
28
|
+
/** Checks one attachment and returns its copy, or throws the refusal. */
|
|
29
|
+
function checkOne(attachment, index, throughResend) {
|
|
30
|
+
let named = `number ${index + 1}`;
|
|
31
|
+
if (typeof attachment !== 'object' || attachment === null || Array.isArray(attachment)) {
|
|
32
|
+
throw refused(named, 'give it as an object');
|
|
33
|
+
}
|
|
34
|
+
const own = {};
|
|
35
|
+
for (const field of COPIED) {
|
|
36
|
+
// An own data property is read once here; a getter could answer this check one value and the send another.
|
|
37
|
+
const descriptor = Object.getOwnPropertyDescriptor(attachment, field);
|
|
38
|
+
if (descriptor === undefined)
|
|
39
|
+
continue;
|
|
40
|
+
if (!('value' in descriptor)) {
|
|
41
|
+
throw refused(named, `give its ${field} as a value, not through a getter or a setter`);
|
|
42
|
+
}
|
|
43
|
+
own[field] = descriptor.value;
|
|
44
|
+
if (field === 'filename' && typeof own.filename === 'string' && own.filename !== '') {
|
|
45
|
+
named = JSON.stringify(own.filename);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const { filename, content, path, contentType } = own;
|
|
49
|
+
const rule = throughResend ? THROUGH_RESEND : THROUGH_SMTP;
|
|
50
|
+
const copy = {};
|
|
51
|
+
if (typeof filename === 'string')
|
|
52
|
+
copy.filename = filename;
|
|
53
|
+
else if (filename !== undefined && filename !== null)
|
|
54
|
+
throw refused(named, 'give its filename as a string');
|
|
55
|
+
// nodemailer reads the path of any content object, a Buffer's own included, so a Buffer is copied into a new one.
|
|
56
|
+
if (typeof content === 'string')
|
|
57
|
+
copy.content = content;
|
|
58
|
+
else if (Buffer.isBuffer(content) && node_util_1.types.isUint8Array(content))
|
|
59
|
+
copy.content = Buffer.from(content);
|
|
60
|
+
else if (content !== undefined)
|
|
61
|
+
throw refused(named, rule);
|
|
62
|
+
if (typeof path === 'string' && (DATA_ADDRESS.test(path) || (throughResend && ResendTransport_js_1.REMOTE_ADDRESS.test(path)))) {
|
|
63
|
+
copy.path = path;
|
|
64
|
+
}
|
|
65
|
+
else if (path !== undefined) {
|
|
66
|
+
throw refused(named, rule);
|
|
67
|
+
}
|
|
68
|
+
// nodemailer writes an object header value marked `prepared` into the part's headers as it is.
|
|
69
|
+
if (typeof contentType === 'string')
|
|
70
|
+
copy.contentType = contentType;
|
|
71
|
+
else if (contentType !== undefined && contentType !== null)
|
|
72
|
+
throw refused(named, 'give its contentType as a string');
|
|
73
|
+
return copy;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Checks the attachments an agent named and returns the copies the surface sends, or throws an `Error` when one would
|
|
77
|
+
* make this process read a file or fetch an address, before anything is sent and without reading the file or fetching
|
|
78
|
+
* the address. Each attachment must be an object, and the check reads its own `filename`, `content`, `path` and
|
|
79
|
+
* `contentType` once each, refusing one given through a getter or a setter: a copy holds those values alone, so a value
|
|
80
|
+
* read again later, or any other property, never reaches a transport. An attachment passes when its `content`, if
|
|
81
|
+
* given, is a string or a Buffer (copied into a new Buffer), its `path`, if given, is a `data:` address, or an `http:`
|
|
82
|
+
* or `https:` address while the service sends through Resend, whose servers fetch it, and its `filename` and
|
|
83
|
+
* `contentType`, if given, are strings (`null` leaves either out). A path is checked even next to `content`, since
|
|
84
|
+
* nodemailer reads `path` first, and `content` of any other kind is refused, since nodemailer reads the `path` or
|
|
85
|
+
* fetches the `href` of a content object. The message names the attachment's `filename`, or its place in the list when
|
|
86
|
+
* it has none, and the rule, never its path.
|
|
87
|
+
*
|
|
88
|
+
* @param attachments The attachments as the surface took them. `undefined` or `null` passes as `undefined`, since there
|
|
89
|
+
* is nothing to send. Any other value that is not a list is refused, since nodemailer takes a single attachment object
|
|
90
|
+
* as a list of one and reads its `path`.
|
|
91
|
+
* @param throughResend Whether the service sends through Resend, as `EmailService.transport` tells.
|
|
92
|
+
* @returns The copies, in the order given, or `undefined` for no attachments.
|
|
93
|
+
*/
|
|
94
|
+
function requireAgentAttachments(attachments, throughResend) {
|
|
95
|
+
if (attachments === undefined || attachments === null)
|
|
96
|
+
return undefined;
|
|
97
|
+
if (!Array.isArray(attachments))
|
|
98
|
+
throw new Error('The attachments were refused: give them as a list');
|
|
99
|
+
const checked = [];
|
|
100
|
+
for (const [index, attachment] of attachments.entries())
|
|
101
|
+
checked.push(checkOne(attachment, index, throughResend));
|
|
102
|
+
return checked;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=agentAttachments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentAttachments.js","sourceRoot":"","sources":["../src/agentAttachments.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @fileoverview Email Channel Extension for AgentOS.
|
|
3
3
|
*
|
|
4
4
|
* Provides an IChannelAdapter + 5 tools for sending, reading, searching,
|
|
5
|
-
* extracting codes from, and replying to emails
|
|
5
|
+
* extracting codes from, and replying to emails: it sends through SMTP or
|
|
6
|
+
* Resend's HTTPS API and reads through IMAP.
|
|
6
7
|
*
|
|
7
8
|
* @module @framers/agentos-ext-channel-email
|
|
8
9
|
*/
|
|
@@ -17,6 +18,18 @@ export interface EmailChannelOptions {
|
|
|
17
18
|
imapPassword?: string;
|
|
18
19
|
imapPort?: number;
|
|
19
20
|
imapSecure?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Resend's API key. With no SMTP host, mail is sent through Resend's HTTPS API. Falls back to the secret
|
|
23
|
+
* `email.resendApiKey`, then to `RESEND_API_KEY`.
|
|
24
|
+
*/
|
|
25
|
+
resendApiKey?: string;
|
|
26
|
+
/** Resend's API origin, such as a proxy's; Resend's own when unset. */
|
|
27
|
+
resendBaseUrl?: string;
|
|
28
|
+
/**
|
|
29
|
+
* The From header, a display name allowed (`Example <hello@example.com>`). Falls back to `EMAIL_FROM`, then to the
|
|
30
|
+
* SMTP user; required when sending through Resend.
|
|
31
|
+
*/
|
|
32
|
+
from?: string;
|
|
20
33
|
secrets?: Record<string, string>;
|
|
21
34
|
}
|
|
22
35
|
export interface ExtensionContext {
|
|
@@ -38,6 +51,8 @@ export interface ExtensionPack {
|
|
|
38
51
|
export declare function createExtensionPack(context: ExtensionContext): ExtensionPack;
|
|
39
52
|
export { EmailService } from './EmailService.js';
|
|
40
53
|
export type { EmailConfig, SendEmailOptions, EmailMessage, SearchEmailOptions } from './EmailService.js';
|
|
54
|
+
export { ResendTransport, EmailApiError, retryWaitSeconds } from './ResendTransport.js';
|
|
55
|
+
export type { ResendOptions, OutgoingEmail, OutgoingAttachment } from './ResendTransport.js';
|
|
41
56
|
export { EmailChannelAdapter } from './EmailChannelAdapter.js';
|
|
42
57
|
export { EmailSendTool } from './tools/send.js';
|
|
43
58
|
export { EmailReadTool } from './tools/read.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAeH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAkFD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAMD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAgC5E;AAMD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxF,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* @fileoverview Email Channel Extension for AgentOS.
|
|
5
5
|
*
|
|
6
6
|
* Provides an IChannelAdapter + 5 tools for sending, reading, searching,
|
|
7
|
-
* extracting codes from, and replying to emails
|
|
7
|
+
* extracting codes from, and replying to emails: it sends through SMTP or
|
|
8
|
+
* Resend's HTTPS API and reads through IMAP.
|
|
8
9
|
*
|
|
9
10
|
* @module @framers/agentos-ext-channel-email
|
|
10
11
|
*/
|
|
11
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.EmailReplyTool = exports.EmailExtractCodesTool = exports.EmailSearchTool = exports.EmailReadTool = exports.EmailSendTool = exports.EmailChannelAdapter = exports.EmailService = void 0;
|
|
13
|
+
exports.EmailReplyTool = exports.EmailExtractCodesTool = exports.EmailSearchTool = exports.EmailReadTool = exports.EmailSendTool = exports.EmailChannelAdapter = exports.retryWaitSeconds = exports.EmailApiError = exports.ResendTransport = exports.EmailService = void 0;
|
|
13
14
|
exports.createExtensionPack = createExtensionPack;
|
|
14
15
|
const EmailService_js_1 = require("./EmailService.js");
|
|
15
16
|
const EmailChannelAdapter_js_1 = require("./EmailChannelAdapter.js");
|
|
@@ -40,6 +41,8 @@ function resolveConfig(opts, secrets) {
|
|
|
40
41
|
process.env.SMTP_PASSWORD ??
|
|
41
42
|
process.env.EMAIL_SMTP_PASSWORD ??
|
|
42
43
|
'';
|
|
44
|
+
const resendApiKey = opts.resendApiKey ?? secrets['email.resendApiKey'] ?? process.env.RESEND_API_KEY;
|
|
45
|
+
const from = opts.from ?? process.env.EMAIL_FROM;
|
|
43
46
|
const imapHost = opts.imapHost ??
|
|
44
47
|
secrets['email.imapHost'] ??
|
|
45
48
|
secrets['email.imap.host'] ??
|
|
@@ -55,15 +58,19 @@ function resolveConfig(opts, secrets) {
|
|
|
55
58
|
secrets['email.imap.password'] ??
|
|
56
59
|
process.env.IMAP_PASSWORD ??
|
|
57
60
|
process.env.EMAIL_IMAP_PASSWORD;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
// SMTP stays the transport whenever a host is given; Resend sends only when a key is given and no SMTP host.
|
|
62
|
+
const config = smtpHost === '' && resendApiKey
|
|
63
|
+
? { resend: { apiKey: resendApiKey, baseUrl: opts.resendBaseUrl }, from }
|
|
64
|
+
: {
|
|
65
|
+
smtp: {
|
|
66
|
+
host: smtpHost,
|
|
67
|
+
user: smtpUser,
|
|
68
|
+
password: smtpPassword,
|
|
69
|
+
port: opts.smtpPort,
|
|
70
|
+
secure: opts.smtpSecure,
|
|
71
|
+
},
|
|
72
|
+
from,
|
|
73
|
+
};
|
|
67
74
|
if (imapHost && imapUser && imapPassword) {
|
|
68
75
|
config.imap = {
|
|
69
76
|
host: imapHost,
|
|
@@ -101,7 +108,7 @@ function createExtensionPack(context) {
|
|
|
101
108
|
{ id: 'emailChannel', kind: 'messaging-channel', priority: 50, payload: adapter },
|
|
102
109
|
],
|
|
103
110
|
onActivate: async () => {
|
|
104
|
-
await adapter.initialize({ platform: 'email', credential: config.smtp
|
|
111
|
+
await adapter.initialize({ platform: 'email', credential: config.smtp?.user ?? config.from ?? '' });
|
|
105
112
|
},
|
|
106
113
|
onDeactivate: async () => {
|
|
107
114
|
await adapter.shutdown();
|
|
@@ -113,6 +120,10 @@ function createExtensionPack(context) {
|
|
|
113
120
|
// ---------------------------------------------------------------------------
|
|
114
121
|
var EmailService_js_2 = require("./EmailService.js");
|
|
115
122
|
Object.defineProperty(exports, "EmailService", { enumerable: true, get: function () { return EmailService_js_2.EmailService; } });
|
|
123
|
+
var ResendTransport_js_1 = require("./ResendTransport.js");
|
|
124
|
+
Object.defineProperty(exports, "ResendTransport", { enumerable: true, get: function () { return ResendTransport_js_1.ResendTransport; } });
|
|
125
|
+
Object.defineProperty(exports, "EmailApiError", { enumerable: true, get: function () { return ResendTransport_js_1.EmailApiError; } });
|
|
126
|
+
Object.defineProperty(exports, "retryWaitSeconds", { enumerable: true, get: function () { return ResendTransport_js_1.retryWaitSeconds; } });
|
|
116
127
|
var EmailChannelAdapter_js_2 = require("./EmailChannelAdapter.js");
|
|
117
128
|
Object.defineProperty(exports, "EmailChannelAdapter", { enumerable: true, get: function () { return EmailChannelAdapter_js_2.EmailChannelAdapter; } });
|
|
118
129
|
var send_js_2 = require("./tools/send.js");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,cAAc;AACd
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|