@dbx-tools/email 0.3.44 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,303 @@
1
+ /**
2
+ * The email runtime: a lazily-built, process-wide dispatcher plus its
3
+ * resolved config, and {@link sendEmail} which sends one
4
+ * {@link EmailMessage} through it. In SMTP mode the runtime holds a
5
+ * memoized nodemailer transport (shared by the plugin's setup and the
6
+ * agent tool, so they reuse one connection pool); in file/outbox mode it
7
+ * holds no transport and {@link sendEmail} writes HTML to disk instead.
8
+ * The first caller (normally the plugin at setup) primes it with the
9
+ * plugin's config; later callers reuse it.
10
+ *
11
+ * The runtime also carries the {@link EmailExecutor} every outbound send runs
12
+ * through. The plugin installs its own `execute()` there at setup, which is
13
+ * how the Mastra tool - a plain function with no plugin instance in scope -
14
+ * still gets AppKit's retry / timeout / telemetry chain. Without a registered
15
+ * plugin (a direct call from a script or a test) the send still runs, just
16
+ * without interceptors.
17
+ *
18
+ * Every entry point takes an optional {@link AbortSignal} so the plugin's
19
+ * `execute()` timeout and a client disconnect both stop the caller waiting
20
+ * on SMTP.
21
+ *
22
+ * @module
23
+ */
24
+ import { AppKitError, ConfigurationError, ExecutionError, ValidationError, } from "@databricks/appkit";
25
+ import { async, error, log } from "@dbx-tools/shared-core";
26
+ import nodemailer from "nodemailer";
27
+ import { resolveEmailConfig } from "./config.js";
28
+ import { EMAIL_SEND_SETTINGS, MAX_ATTACHMENT_BYTES, MAX_ATTACHMENT_COUNT, MAX_ATTACHMENTS_TOTAL_BYTES, MAX_BODY_CHARS, } from "./defaults.js";
29
+ import { renderEmailHtml } from "./email-html.js";
30
+ import { writeOutboxEmail } from "./outbox.js";
31
+ import { assertSenderAllowed } from "./sender.js";
32
+ const logger = log.logger("email/transport");
33
+ /**
34
+ * Executor used until (or unless) the plugin installs its own: run the send
35
+ * directly, mapping a throw onto the same {@link ExecutionResult} shape so
36
+ * call sites branch on `ok` either way.
37
+ */
38
+ const directExecute = async (fn) => {
39
+ try {
40
+ return { ok: true, data: await fn() };
41
+ }
42
+ catch (err) {
43
+ return {
44
+ ok: false,
45
+ status: err instanceof AppKitError ? err.statusCode : 500,
46
+ message: error.errorMessage(err),
47
+ };
48
+ }
49
+ };
50
+ let runtime;
51
+ /**
52
+ * Return the shared runtime, building it on first use by resolving
53
+ * `overrides` over the environment (`SMTP_HOST`, `SMTP_PORT`,
54
+ * `SMTP_SECURE`, `SMTP_USER`, `SMTP_PASSWORD`, `EMAIL_DOMAIN`,
55
+ * `EMAIL_FROM`, `EMAIL_ALLOWED_SENDERS`, `EMAIL_SENDER_POLICY`,
56
+ * `EMAIL_OUTBOX_MODE`, `EMAIL_OUTBOX_DIR`) through
57
+ * {@link resolveEmailConfig}. With SMTP credentials present it holds a
58
+ * nodemailer transport and its connection pool; otherwise it is in
59
+ * file/outbox mode and holds none.
60
+ *
61
+ * `overrides` is read only on the call that builds the runtime, so prime it
62
+ * from the plugin's config at setup; later callers (the tool's `execute`,
63
+ * the sender-options route) pass nothing and get the same instance. Throws
64
+ * whatever {@link resolveEmailConfig} throws for an unusable configuration.
65
+ */
66
+ export function getEmailRuntime(overrides) {
67
+ if (!runtime) {
68
+ const config = resolveEmailConfig(overrides);
69
+ runtime = {
70
+ config,
71
+ execute: directExecute,
72
+ ...(config.mode === "smtp"
73
+ ? {
74
+ transporter: nodemailer.createTransport({
75
+ host: config.host,
76
+ port: config.port,
77
+ secure: config.secure,
78
+ auth: config.auth,
79
+ }),
80
+ }
81
+ : {}),
82
+ };
83
+ }
84
+ return runtime;
85
+ }
86
+ /**
87
+ * Install the executor outbound sends run through. The plugin calls this at
88
+ * setup with its own `execute()`; a second call replaces the previous one, so
89
+ * a re-registered plugin does not leave the tools bound to a dead instance.
90
+ */
91
+ export function setEmailExecutor(execute) {
92
+ getEmailRuntime().execute = execute;
93
+ }
94
+ /**
95
+ * Drop the memoized runtime, closing the SMTP connection pool, so the next
96
+ * {@link getEmailRuntime} rebuilds it from fresh config and stops calling
97
+ * through a torn-down plugin's `execute()`. Idempotent, and the plugin's
98
+ * `shutdown()` hook.
99
+ */
100
+ export function resetEmailRuntime() {
101
+ runtime?.transporter?.close();
102
+ runtime = undefined;
103
+ }
104
+ /**
105
+ * Run one non-idempotent write through the shared executor and unwrap it.
106
+ *
107
+ * `execute()` never throws, so a failed send arrives as `{ ok: false }` with a
108
+ * status the interceptors already sanitized; it is logged here and re-raised
109
+ * as a stable {@link ExecutionError} so an upstream message never becomes the
110
+ * caller's error text. `signal` is the caller's own cancellation (an agent
111
+ * run, a request teardown); it is merged with the signal the timeout
112
+ * interceptor supplies so either one unwinds the I/O.
113
+ */
114
+ export async function executeWrite(operation, settings, fn, signal) {
115
+ const { execute } = getEmailRuntime();
116
+ const result = await execute((executeSignal) => fn(async.combineAbortSignals(executeSignal, signal)), settings);
117
+ if (result.ok)
118
+ return result.data;
119
+ // A caller that cancelled is not a failure worth reporting as one.
120
+ if (signal?.aborted)
121
+ throw ExecutionError.canceled();
122
+ logger.warn("execution-failed", {
123
+ operation,
124
+ status: result.status,
125
+ error: result.message,
126
+ });
127
+ throw new ExecutionError(`email: ${operation} failed`, {
128
+ context: { operation, status: result.status },
129
+ });
130
+ }
131
+ /**
132
+ * Open and tear down one SMTP connection to prove the host, port, and
133
+ * credentials work. Called at plugin setup so a bad relay shows up in the
134
+ * boot logs rather than on the first approved send.
135
+ */
136
+ export async function verifyEmailTransport(transporter, signal) {
137
+ if (!transporter) {
138
+ throw ConfigurationError.invalidConnection("SMTP", "The runtime resolved to outbox mode, so there is no transport to verify.");
139
+ }
140
+ await abortable(transporter.verify(), signal);
141
+ }
142
+ /**
143
+ * Stop awaiting `promise` as soon as `signal` aborts. nodemailer exposes no
144
+ * cancellation hook, so the SMTP conversation itself finishes on its own
145
+ * connection; what unwinds is the caller and everything downstream of it.
146
+ */
147
+ function abortable(promise, signal) {
148
+ if (!signal)
149
+ return promise;
150
+ signal.throwIfAborted();
151
+ // The listener is detached once the race settles so a long-lived run signal
152
+ // does not accumulate one per send.
153
+ const listener = new AbortController();
154
+ const aborted = new Promise((_, reject) => {
155
+ signal.addEventListener("abort", () => reject(signal.reason), {
156
+ once: true,
157
+ signal: listener.signal,
158
+ });
159
+ });
160
+ return Promise.race([promise, aborted]).finally(() => listener.abort());
161
+ }
162
+ /** The comma-joined recipient string echoed back in {@link EmailResult}. */
163
+ function recipientEcho(to) {
164
+ return to.join(", ");
165
+ }
166
+ /**
167
+ * Node buffer encodings a wire attachment may name for its inline `content`.
168
+ * Anything else is measured as UTF-8, which over-counts rather than letting
169
+ * an unrecognized encoding slip past the size cap.
170
+ */
171
+ const CONTENT_ENCODINGS = new Set([
172
+ "ascii",
173
+ "base64",
174
+ "base64url",
175
+ "binary",
176
+ "hex",
177
+ "latin1",
178
+ "ucs2",
179
+ "ucs-2",
180
+ "utf8",
181
+ "utf-8",
182
+ "utf16le",
183
+ "utf-16le",
184
+ ]);
185
+ /**
186
+ * Decoded byte size of one attachment's inline content. A `path` attachment
187
+ * contributes nothing: nodemailer streams it, so its bytes never sit in this
188
+ * process and cannot be measured here.
189
+ */
190
+ function attachmentBytes(attachment) {
191
+ const { content, encoding } = attachment;
192
+ if (content === undefined)
193
+ return 0;
194
+ const declared = encoding?.toLowerCase();
195
+ const resolved = declared && CONTENT_ENCODINGS.has(declared) ? declared : "utf8";
196
+ return Buffer.byteLength(content, resolved);
197
+ }
198
+ /**
199
+ * Reject a message whose body or attachments exceed the plugin's caps. The
200
+ * body and attachment list arrive from a model, so they are unbounded until
201
+ * something bounds them; most SMTP relays also reject an oversized message
202
+ * only after the whole payload has been uploaded.
203
+ */
204
+ function assertMessageWithinCaps(message) {
205
+ if (message.body.length > MAX_BODY_CHARS) {
206
+ throw ValidationError.invalidValue("body", message.body.length, `at most ${MAX_BODY_CHARS} characters`);
207
+ }
208
+ const attachments = message.attachments ?? [];
209
+ if (attachments.length > MAX_ATTACHMENT_COUNT) {
210
+ throw ValidationError.invalidValue("attachments", attachments.length, `at most ${MAX_ATTACHMENT_COUNT} files`);
211
+ }
212
+ let total = 0;
213
+ for (const attachment of attachments) {
214
+ const bytes = attachmentBytes(attachment);
215
+ if (bytes > MAX_ATTACHMENT_BYTES) {
216
+ throw ValidationError.invalidValue("attachments[].content", bytes, `at most ${MAX_ATTACHMENT_BYTES} bytes per file`);
217
+ }
218
+ total += bytes;
219
+ }
220
+ if (total > MAX_ATTACHMENTS_TOTAL_BYTES) {
221
+ throw ValidationError.invalidValue("attachments", total, `at most ${MAX_ATTACHMENTS_TOTAL_BYTES} bytes across all files`);
222
+ }
223
+ }
224
+ /**
225
+ * Map the wire-format {@link EmailAttachment}s onto nodemailer's
226
+ * attachment shape, dropping unset optional keys so nodemailer applies
227
+ * its own defaults (utf-8 encoding, filename-inferred content type). The
228
+ * wire fields are a deliberate subset of nodemailer's, so this is a
229
+ * straight structural pass-through.
230
+ */
231
+ function toMailAttachments(attachments) {
232
+ if (!attachments || attachments.length === 0)
233
+ return undefined;
234
+ return attachments.map((att) => ({
235
+ filename: att.filename,
236
+ ...(att.content !== undefined ? { content: att.content } : {}),
237
+ ...(att.encoding !== undefined ? { encoding: att.encoding } : {}),
238
+ ...(att.path !== undefined ? { path: att.path } : {}),
239
+ ...(att.contentType !== undefined ? { contentType: att.contentType } : {}),
240
+ }));
241
+ }
242
+ /**
243
+ * Hand one already-validated message to SMTP, or write it to the outbox when
244
+ * no credentials are configured. The half of a send that performs I/O, so it
245
+ * is what runs inside the interceptor chain.
246
+ */
247
+ async function dispatch(message, from, signal) {
248
+ const { config, transporter } = getEmailRuntime();
249
+ const recipient = recipientEcho(message.to);
250
+ signal?.throwIfAborted();
251
+ if (config.mode === "file") {
252
+ const path = await writeOutboxEmail(message, from, config.outDir, config.brand);
253
+ return { sent: true, recipient, from, messageId: path };
254
+ }
255
+ if (!transporter) {
256
+ throw ConfigurationError.invalidConnection("SMTP", "No transport was built for the resolved configuration.");
257
+ }
258
+ const attachments = toMailAttachments(message.attachments);
259
+ const info = await abortable(transporter.sendMail({
260
+ from,
261
+ to: message.to,
262
+ subject: message.subject,
263
+ text: message.body,
264
+ html: renderEmailHtml({
265
+ subject: message.subject,
266
+ body: message.body,
267
+ ...(config.brand ? { brand: config.brand } : {}),
268
+ }),
269
+ ...(message.cc && message.cc.length > 0 ? { cc: message.cc } : {}),
270
+ ...(message.bcc && message.bcc.length > 0 ? { bcc: message.bcc } : {}),
271
+ ...(attachments ? { attachments } : {}),
272
+ }), signal);
273
+ return {
274
+ sent: true,
275
+ recipient,
276
+ from,
277
+ ...(info.messageId ? { messageId: info.messageId } : {}),
278
+ };
279
+ }
280
+ /**
281
+ * Send (SMTP mode) or persist (file/outbox mode) one message from the
282
+ * resolved `from` address. `to` (and optional `cc` / `bcc`) each accept
283
+ * one or more addresses, and `attachments` are forwarded as files. The
284
+ * body is markdown: SMTP sends it as both a plain-text part (the raw
285
+ * source) and an HTML part (rendered), and the outbox embeds the
286
+ * rendered HTML in a document. In file mode the returned `messageId` is
287
+ * the path written. Throws when `to` carries no recipient, when the body
288
+ * or attachments exceed the plugin's caps, or when `from` is not permitted
289
+ * by the effective sender allow-list.
290
+ *
291
+ * The recipient, cap, and sender checks run before the interceptor chain so
292
+ * their specific status and actionable message reach the caller instead of
293
+ * the chain's stable failure text. `signal` cancels the send.
294
+ */
295
+ export async function sendEmail(message, from, signal) {
296
+ if (message.to.length === 0) {
297
+ throw ValidationError.missingField("to");
298
+ }
299
+ assertMessageWithinCaps(message);
300
+ assertSenderAllowed(from, getEmailRuntime().config.allowedSenders);
301
+ return executeWrite("send", EMAIL_SEND_SETTINGS, (executeSignal) => dispatch(message, from, executeSignal), signal);
302
+ }
303
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RyYW5zcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVILE9BQU8sRUFDTCxXQUFXLEVBQ1gsa0JBQWtCLEVBQ2xCLGNBQWMsRUFDZCxlQUFlLEdBRWhCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFM0QsT0FBTyxVQUFzRCxNQUFNLFlBQVksQ0FBQztBQUNoRixPQUFPLEVBQUUsa0JBQWtCLEVBQW9ELE1BQU0sVUFBVSxDQUFDO0FBQ2hHLE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsb0JBQW9CLEVBQ3BCLG9CQUFvQixFQUNwQiwyQkFBMkIsRUFDM0IsY0FBYyxHQUVmLE1BQU0sWUFBWSxDQUFDO0FBQ3BCLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDL0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUUvQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUM7QUFvQjdDOzs7O0dBSUc7QUFDSCxNQUFNLGFBQWEsR0FBa0IsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFO0lBQ2hELElBQUksQ0FBQztRQUNILE9BQU8sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDeEMsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixPQUFPO1lBQ0wsRUFBRSxFQUFFLEtBQUs7WUFDVCxNQUFNLEVBQUUsR0FBRyxZQUFZLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxD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ZSxFQUFFLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQ25FLE9BQU8sWUFBWSxDQUNqQixNQUFNLEVBQ04sbUJBQW1CLEVBQ25CLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxhQUFhLENBQUMsRUFDekQsTUFBTSxDQUNQLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGUgZW1haWwgcnVudGltZTogYSBsYXppbHktYnVpbHQsIHByb2Nlc3Mtd2lkZSBkaXNwYXRjaGVyIHBsdXMgaXRzXG4gKiByZXNvbHZlZCBjb25maWcsIGFuZCB7QGxpbmsgc2VuZEVtYWlsfSB3aGljaCBzZW5kcyBvbmVcbiAqIHtAbGluayBFbWFpbE1lc3NhZ2V9IHRocm91Z2ggaXQuIEluIFNNVFAgbW9kZSB0aGUgcnVudGltZSBob2xkcyBhXG4gKiBtZW1vaXplZCBub2RlbWFpbGVyIHRyYW5zcG9ydCAoc2hhcmVkIGJ5IHRoZSBwbHVnaW4ncyBzZXR1cCBhbmQgdGhlXG4gKiBhZ2VudCB0b29sLCBzbyB0aGV5IHJldXNlIG9uZSBjb25uZWN0aW9uIHBvb2wpOyBpbiBmaWxlL291dGJveCBtb2RlIGl0XG4gKiBob2xkcyBubyB0cmFuc3BvcnQgYW5kIHtAbGluayBzZW5kRW1haWx9IHdyaXRlcyBIVE1MIHRvIGRpc2sgaW5zdGVhZC5cbiAqIFRoZSBmaXJzdCBjYWxsZXIgKG5vcm1hbGx5IHRoZSBwbHVnaW4gYXQgc2V0dXApIHByaW1lcyBpdCB3aXRoIHRoZVxuICogcGx1Z2luJ3MgY29uZmlnOyBsYXRlciBjYWxsZXJzIHJldXNlIGl0LlxuICpcbiAqIFRoZSBydW50aW1lIGFsc28gY2FycmllcyB0aGUge0BsaW5rIEVtYWlsRXhlY3V0b3J9IGV2ZXJ5IG91dGJvdW5kIHNlbmQgcnVuc1xuICogdGhyb3VnaC4gVGhlIHBsdWdpbiBpbnN0YWxscyBpdHMgb3duIGBleGVjdXRlKClgIHRoZXJlIGF0IHNldHVwLCB3aGljaCBpc1xuICogaG93IHRoZSBNYXN0cmEgdG9vbCAtIGEgcGxhaW4gZnVuY3Rpb24gd2l0aCBubyBwbHVnaW4gaW5zdGFuY2UgaW4gc2NvcGUgLVxuICogc3RpbGwgZ2V0cyBBcHBLaXQncyByZXRyeSAvIHRpbWVvdXQgLyB0ZWxlbWV0cnkgY2hhaW4uIFdpdGhvdXQgYSByZWdpc3RlcmVkXG4gKiBwbHVnaW4gKGEgZGlyZWN0IGNhbGwgZnJvbSBhIHNjcmlwdCBvciBhIHRlc3QpIHRoZSBzZW5kIHN0aWxsIHJ1bnMsIGp1c3RcbiAqIHdpdGhvdXQgaW50ZXJjZXB0b3JzLlxuICpcbiAqIEV2ZXJ5IGVudHJ5IHBvaW50IHRha2VzIGFuIG9wdGlvbmFsIHtAbGluayBBYm9ydFNpZ25hbH0gc28gdGhlIHBsdWdpbidzXG4gKiBgZXhlY3V0ZSgpYCB0aW1lb3V0IGFuZCBhIGNsaWVudCBkaXNjb25uZWN0IGJvdGggc3RvcCB0aGUgY2FsbGVyIHdhaXRpbmdcbiAqIG9uIFNNVFAuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7XG4gIEFwcEtpdEVycm9yLFxuICBDb25maWd1cmF0aW9uRXJyb3IsXG4gIEV4ZWN1dGlvbkVycm9yLFxuICBWYWxpZGF0aW9uRXJyb3IsXG4gIHR5cGUgRXhlY3V0aW9uUmVzdWx0LFxufSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBhc3luYywgZXJyb3IsIGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IEVtYWlsQXR0YWNobWVudCwgRW1haWxNZXNzYWdlLCBFbWFpbFJlc3VsdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1lbWFpbFwiO1xuaW1wb3J0IG5vZGVtYWlsZXIsIHsgdHlwZSBTZW5kTWFpbE9wdGlvbnMsIHR5cGUgVHJhbnNwb3J0ZXIgfSBmcm9tIFwibm9kZW1haWxlclwiO1xuaW1wb3J0IHsgcmVzb2x2ZUVtYWlsQ29uZmlnLCB0eXBlIEVtYWlsUGx1Z2luQ29uZmlnLCB0eXBlIFJlc29sdmVkRW1haWxDb25maWcgfSBmcm9tIFwiLi9jb25maWdcIjtcbmltcG9ydCB7XG4gIEVNQUlMX1NFTkRfU0VUVElOR1MsXG4gIE1BWF9BVFRBQ0hNRU5UX0JZVEVTLFxuICBNQVhfQVRUQUNITUVOVF9DT1VOVCxcbiAgTUFYX0FUVEFDSE1FTlRTX1RPVEFMX0JZVEVTLFxuICBNQVhfQk9EWV9DSEFSUyxcbiAgdHlwZSBFbWFpbEV4ZWN1dGlvblNldHRpbmdzLFxufSBmcm9tIFwiLi9kZWZhdWx0c1wiO1xuaW1wb3J0IHsgcmVuZGVyRW1haWxIdG1sIH0gZnJvbSBcIi4vZW1haWwtaHRtbFwiO1xuaW1wb3J0IHsgd3JpdGVPdXRib3hFbWFpbCB9IGZyb20gXCIuL291dGJveFwiO1xuaW1wb3J0IHsgYXNzZXJ0U2VuZGVyQWxsb3dlZCB9IGZyb20gXCIuL3NlbmRlclwiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiZW1haWwvdHJhbnNwb3J0XCIpO1xuXG4vKipcbiAqIFJ1bnMgb25lIG91dGJvdW5kIHNlbmQgdGhyb3VnaCBBcHBLaXQncyBpbnRlcmNlcHRvciBjaGFpbi4gTWF0Y2hlc1xuICogYFBsdWdpbi5leGVjdXRlKClgLCB3aGljaCBuZXZlciB0aHJvd3M6IGEgZmFpbHVyZSBjb21lcyBiYWNrIGFzXG4gKiBgeyBvazogZmFsc2UgfWAuXG4gKi9cbmV4cG9ydCB0eXBlIEVtYWlsRXhlY3V0b3IgPSA8VD4oXG4gIGZuOiAoc2lnbmFsPzogQWJvcnRTaWduYWwpID0+IFByb21pc2U8VD4sXG4gIHNldHRpbmdzOiBFbWFpbEV4ZWN1dGlvblNldHRpbmdzLFxuKSA9PiBQcm9taXNlPEV4ZWN1dGlvblJlc3VsdDxUPj47XG5cbi8qKiBUaGUgc2hhcmVkIGRpc3BhdGNoZXIsIGl0cyByZXNvbHZlZCBjb25maWcsIGFuZCB0aGUgc2VuZCBleGVjdXRvci4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRW1haWxSdW50aW1lIHtcbiAgLyoqIFByZXNlbnQgb25seSBpbiBTTVRQIG1vZGUuICovXG4gIHRyYW5zcG9ydGVyPzogVHJhbnNwb3J0ZXI7XG4gIGNvbmZpZzogUmVzb2x2ZWRFbWFpbENvbmZpZztcbiAgZXhlY3V0ZTogRW1haWxFeGVjdXRvcjtcbn1cblxuLyoqXG4gKiBFeGVjdXRvciB1c2VkIHVudGlsIChvciB1bmxlc3MpIHRoZSBwbHVnaW4gaW5zdGFsbHMgaXRzIG93bjogcnVuIHRoZSBzZW5kXG4gKiBkaXJlY3RseSwgbWFwcGluZyBhIHRocm93IG9udG8gdGhlIHNhbWUge0BsaW5rIEV4ZWN1dGlvblJlc3VsdH0gc2hhcGUgc29cbiAqIGNhbGwgc2l0ZXMgYnJhbmNoIG9uIGBva2AgZWl0aGVyIHdheS5cbiAqL1xuY29uc3QgZGlyZWN0RXhlY3V0ZTogRW1haWxFeGVjdXRvciA9IGFzeW5jIChmbikgPT4ge1xuICB0cnkge1xuICAgIHJldHVybiB7IG9rOiB0cnVlLCBkYXRhOiBhd2FpdCBmbigpIH07XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHJldHVybiB7XG4gICAgICBvazogZmFsc2UsXG4gICAgICBzdGF0dXM6IGVyciBpbnN0YW5jZW9mIEFwcEtpdEVycm9yID8gZXJyLnN0YXR1c0NvZGUgOiA1MDAsXG4gICAgICBtZXNzYWdlOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSxcbiAgICB9O1xuICB9XG59O1xuXG5sZXQgcnVudGltZTogRW1haWxSdW50aW1lIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIFJldHVybiB0aGUgc2hhcmVkIHJ1bnRpbWUsIGJ1aWxkaW5nIGl0IG9uIGZpcnN0IHVzZSBieSByZXNvbHZpbmdcbiAqIGBvdmVycmlkZXNgIG92ZXIgdGhlIGVudmlyb25tZW50IChgU01UUF9IT1NUYCwgYFNNVFBfUE9SVGAsXG4gKiBgU01UUF9TRUNVUkVgLCBgU01UUF9VU0VSYCwgYFNNVFBfUEFTU1dPUkRgLCBgRU1BSUxfRE9NQUlOYCxcbiAqIGBFTUFJTF9GUk9NYCwgYEVNQUlMX0FMTE9XRURfU0VOREVSU2AsIGBFTUFJTF9TRU5ERVJfUE9MSUNZYCxcbiAqIGBFTUFJTF9PVVRCT1hfTU9ERWAsIGBFTUFJTF9PVVRCT1hfRElSYCkgdGhyb3VnaFxuICoge0BsaW5rIHJlc29sdmVFbWFpbENvbmZpZ30uIFdpdGggU01UUCBjcmVkZW50aWFscyBwcmVzZW50IGl0IGhvbGRzIGFcbiAqIG5vZGVtYWlsZXIgdHJhbnNwb3J0IGFuZCBpdHMgY29ubmVjdGlvbiBwb29sOyBvdGhlcndpc2UgaXQgaXMgaW5cbiAqIGZpbGUvb3V0Ym94IG1vZGUgYW5kIGhvbGRzIG5vbmUuXG4gKlxuICogYG92ZXJyaWRlc2AgaXMgcmVhZCBvbmx5IG9uIHRoZSBjYWxsIHRoYXQgYnVpbGRzIHRoZSBydW50aW1lLCBzbyBwcmltZSBpdFxuICogZnJvbSB0aGUgcGx1Z2luJ3MgY29uZmlnIGF0IHNldHVwOyBsYXRlciBjYWxsZXJzICh0aGUgdG9vbCdzIGBleGVjdXRlYCxcbiAqIHRoZSBzZW5kZXItb3B0aW9ucyByb3V0ZSkgcGFzcyBub3RoaW5nIGFuZCBnZXQgdGhlIHNhbWUgaW5zdGFuY2UuIFRocm93c1xuICogd2hhdGV2ZXIge0BsaW5rIHJlc29sdmVFbWFpbENvbmZpZ30gdGhyb3dzIGZvciBhbiB1bnVzYWJsZSBjb25maWd1cmF0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RW1haWxSdW50aW1lKG92ZXJyaWRlcz86IEVtYWlsUGx1Z2luQ29uZmlnKTogRW1haWxSdW50aW1lIHtcbiAgaWYgKCFydW50aW1lKSB7XG4gICAgY29uc3QgY29uZmlnID0gcmVzb2x2ZUVtYWlsQ29uZmlnKG92ZXJyaWRlcyk7XG4gICAgcnVudGltZSA9IHtcbiAgICAgIGNvbmZpZyxcbiAgICAgIGV4ZWN1dGU6IGRpcmVjdEV4ZWN1dGUsXG4gICAgICAuLi4oY29uZmlnLm1vZGUgPT09IFwic210cFwiXG4gICAgICAgID8ge1xuICAgICAgICAgICAgdHJhbnNwb3J0ZXI6IG5vZGVtYWlsZXIuY3JlYXRlVHJhbnNwb3J0KHtcbiAgICAgICAgICAgICAgaG9zdDogY29uZmlnLmhvc3QsXG4gICAgICAgICAgICAgIHBvcnQ6IGNvbmZpZy5wb3J0LFxuICAgICAgICAgICAgICBzZWN1cmU6IGNvbmZpZy5zZWN1cmUsXG4gICAgICAgICAgICAgIGF1dGg6IGNvbmZpZy5hdXRoLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgfVxuICAgICAgICA6IHt9KSxcbiAgICB9O1xuICB9XG4gIHJldHVybiBydW50aW1lO1xufVxuXG4vKipcbiAqIEluc3RhbGwgdGhlIGV4ZWN1dG9yIG91dGJvdW5kIHNlbmRzIHJ1biB0aHJvdWdoLiBUaGUgcGx1Z2luIGNhbGxzIHRoaXMgYXRcbiAqIHNldHVwIHdpdGggaXRzIG93biBgZXhlY3V0ZSgpYDsgYSBzZWNvbmQgY2FsbCByZXBsYWNlcyB0aGUgcHJldmlvdXMgb25lLCBzb1xuICogYSByZS1yZWdpc3RlcmVkIHBsdWdpbiBkb2VzIG5vdCBsZWF2ZSB0aGUgdG9vbHMgYm91bmQgdG8gYSBkZWFkIGluc3RhbmNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0RW1haWxFeGVjdXRvcihleGVjdXRlOiBFbWFpbEV4ZWN1dG9yKTogdm9pZCB7XG4gIGdldEVtYWlsUnVudGltZSgpLmV4ZWN1dGUgPSBleGVjdXRlO1xufVxuXG4vKipcbiAqIERyb3AgdGhlIG1lbW9pemVkIHJ1bnRpbWUsIGNsb3NpbmcgdGhlIFNNVFAgY29ubmVjdGlvbiBwb29sLCBzbyB0aGUgbmV4dFxuICoge0BsaW5rIGdldEVtYWlsUnVudGltZX0gcmVidWlsZHMgaXQgZnJvbSBmcmVzaCBjb25maWcgYW5kIHN0b3BzIGNhbGxpbmdcbiAqIHRocm91Z2ggYSB0b3JuLWRvd24gcGx1Z2luJ3MgYGV4ZWN1dGUoKWAuIElkZW1wb3RlbnQsIGFuZCB0aGUgcGx1Z2luJ3NcbiAqIGBzaHV0ZG93bigpYCBob29rLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRFbWFpbFJ1bnRpbWUoKTogdm9pZCB7XG4gIHJ1bnRpbWU/LnRyYW5zcG9ydGVyPy5jbG9zZSgpO1xuICBydW50aW1lID0gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJ1biBvbmUgbm9uLWlkZW1wb3RlbnQgd3JpdGUgdGhyb3VnaCB0aGUgc2hhcmVkIGV4ZWN1dG9yIGFuZCB1bndyYXAgaXQuXG4gKlxuICogYGV4ZWN1dGUoKWAgbmV2ZXIgdGhyb3dzLCBzbyBhIGZhaWxlZCBzZW5kIGFycml2ZXMgYXMgYHsgb2s6IGZhbHNlIH1gIHdpdGggYVxuICogc3RhdHVzIHRoZSBpbnRlcmNlcHRvcnMgYWxyZWFkeSBzYW5pdGl6ZWQ7IGl0IGlzIGxvZ2dlZCBoZXJlIGFuZCByZS1yYWlzZWRcbiAqIGFzIGEgc3RhYmxlIHtAbGluayBFeGVjdXRpb25FcnJvcn0gc28gYW4gdXBzdHJlYW0gbWVzc2FnZSBuZXZlciBiZWNvbWVzIHRoZVxuICogY2FsbGVyJ3MgZXJyb3IgdGV4dC4gYHNpZ25hbGAgaXMgdGhlIGNhbGxlcidzIG93biBjYW5jZWxsYXRpb24gKGFuIGFnZW50XG4gKiBydW4sIGEgcmVxdWVzdCB0ZWFyZG93bik7IGl0IGlzIG1lcmdlZCB3aXRoIHRoZSBzaWduYWwgdGhlIHRpbWVvdXRcbiAqIGludGVyY2VwdG9yIHN1cHBsaWVzIHNvIGVpdGhlciBvbmUgdW53aW5kcyB0aGUgSS9PLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhlY3V0ZVdyaXRlPFQ+KFxuICBvcGVyYXRpb246IHN0cmluZyxcbiAgc2V0dGluZ3M6IEVtYWlsRXhlY3V0aW9uU2V0dGluZ3MsXG4gIGZuOiAoc2lnbmFsPzogQWJvcnRTaWduYWwpID0+IFByb21pc2U8VD4sXG4gIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuKTogUHJvbWlzZTxUPiB7XG4gIGNvbnN0IHsgZXhlY3V0ZSB9ID0gZ2V0RW1haWxSdW50aW1lKCk7XG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4ZWN1dGUoXG4gICAgKGV4ZWN1dGVTaWduYWwpID0+IGZuKGFzeW5jLmNvbWJpbmVBYm9ydFNpZ25hbHMoZXhlY3V0ZVNpZ25hbCwgc2lnbmFsKSksXG4gICAgc2V0dGluZ3MsXG4gICk7XG4gIGlmIChyZXN1bHQub2spIHJldHVybiByZXN1bHQuZGF0YTtcbiAgLy8gQSBjYWxsZXIgdGhhdCBjYW5jZWxsZWQgaXMgbm90IGEgZmFpbHVyZSB3b3J0aCByZXBvcnRpbmcgYXMgb25lLlxuICBpZiAoc2lnbmFsPy5hYm9ydGVkKSB0aHJvdyBFeGVjdXRpb25FcnJvci5jYW5jZWxlZCgpO1xuICBsb2dnZXIud2FybihcImV4ZWN1dGlvbi1mYWlsZWRcIiwge1xuICAgIG9wZXJhdGlvbixcbiAgICBzdGF0dXM6IHJlc3VsdC5zdGF0dXMsXG4gICAgZXJyb3I6IHJlc3VsdC5tZXNzYWdlLFxuICB9KTtcbiAgdGhyb3cgbmV3IEV4ZWN1dGlvbkVycm9yKGBlbWFpbDogJHtvcGVyYXRpb259IGZhaWxlZGAsIHtcbiAgICBjb250ZXh0OiB7IG9wZXJhdGlvbiwgc3RhdHVzOiByZXN1bHQuc3RhdHVzIH0sXG4gIH0pO1xufVxuXG4vKipcbiAqIE9wZW4gYW5kIHRlYXIgZG93biBvbmUgU01UUCBjb25uZWN0aW9uIHRvIHByb3ZlIHRoZSBob3N0LCBwb3J0LCBhbmRcbiAqIGNyZWRlbnRpYWxzIHdvcmsuIENhbGxlZCBhdCBwbHVnaW4gc2V0dXAgc28gYSBiYWQgcmVsYXkgc2hvd3MgdXAgaW4gdGhlXG4gKiBib290IGxvZ3MgcmF0aGVyIHRoYW4gb24gdGhlIGZpcnN0IGFwcHJvdmVkIHNlbmQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2ZXJpZnlFbWFpbFRyYW5zcG9ydChcbiAgdHJhbnNwb3J0ZXI6IFRyYW5zcG9ydGVyIHwgdW5kZWZpbmVkLFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoIXRyYW5zcG9ydGVyKSB7XG4gICAgdGhyb3cgQ29uZmlndXJhdGlvbkVycm9yLmludmFsaWRDb25uZWN0aW9uKFxuICAgICAgXCJTTVRQXCIsXG4gICAgICBcIlRoZSBydW50aW1lIHJlc29sdmVkIHRvIG91dGJveCBtb2RlLCBzbyB0aGVyZSBpcyBubyB0cmFuc3BvcnQgdG8gdmVyaWZ5LlwiLFxuICAgICk7XG4gIH1cbiAgYXdhaXQgYWJvcnRhYmxlKHRyYW5zcG9ydGVyLnZlcmlmeSgpLCBzaWduYWwpO1xufVxuXG4vKipcbiAqIFN0b3AgYXdhaXRpbmcgYHByb21pc2VgIGFzIHNvb24gYXMgYHNpZ25hbGAgYWJvcnRzLiBub2RlbWFpbGVyIGV4cG9zZXMgbm9cbiAqIGNhbmNlbGxhdGlvbiBob29rLCBzbyB0aGUgU01UUCBjb252ZXJzYXRpb24gaXRzZWxmIGZpbmlzaGVzIG9uIGl0cyBvd25cbiAqIGNvbm5lY3Rpb247IHdoYXQgdW53aW5kcyBpcyB0aGUgY2FsbGVyIGFuZCBldmVyeXRoaW5nIGRvd25zdHJlYW0gb2YgaXQuXG4gKi9cbmZ1bmN0aW9uIGFib3J0YWJsZTxUPihwcm9taXNlOiBQcm9taXNlPFQ+LCBzaWduYWw6IEFib3J0U2lnbmFsIHwgdW5kZWZpbmVkKTogUHJvbWlzZTxUPiB7XG4gIGlmICghc2lnbmFsKSByZXR1cm4gcHJvbWlzZTtcbiAgc2lnbmFsLnRocm93SWZBYm9ydGVkKCk7XG4gIC8vIFRoZSBsaXN0ZW5lciBpcyBkZXRhY2hlZCBvbmNlIHRoZSByYWNlIHNldHRsZXMgc28gYSBsb25nLWxpdmVkIHJ1biBzaWduYWxcbiAgLy8gZG9lcyBub3QgYWNjdW11bGF0ZSBvbmUgcGVyIHNlbmQuXG4gIGNvbnN0IGxpc3RlbmVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICBjb25zdCBhYm9ydGVkID0gbmV3IFByb21pc2U8bmV2ZXI+KChfLCByZWplY3QpID0+IHtcbiAgICBzaWduYWwuYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsICgpID0+IHJlamVjdChzaWduYWwucmVhc29uKSwge1xuICAgICAgb25jZTogdHJ1ZSxcbiAgICAgIHNpZ25hbDogbGlzdGVuZXIuc2lnbmFsLFxuICAgIH0pO1xuICB9KTtcbiAgcmV0dXJuIFByb21pc2UucmFjZShbcHJvbWlzZSwgYWJvcnRlZF0pLmZpbmFsbHkoKCkgPT4gbGlzdGVuZXIuYWJvcnQoKSk7XG59XG5cbi8qKiBUaGUgY29tbWEtam9pbmVkIHJlY2lwaWVudCBzdHJpbmcgZWNob2VkIGJhY2sgaW4ge0BsaW5rIEVtYWlsUmVzdWx0fS4gKi9cbmZ1bmN0aW9uIHJlY2lwaWVudEVjaG8odG86IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgcmV0dXJuIHRvLmpvaW4oXCIsIFwiKTtcbn1cblxuLyoqXG4gKiBOb2RlIGJ1ZmZlciBlbmNvZGluZ3MgYSB3aXJlIGF0dGFjaG1lbnQgbWF5IG5hbWUgZm9yIGl0cyBpbmxpbmUgYGNvbnRlbnRgLlxuICogQW55dGhpbmcgZWxzZSBpcyBtZWFzdXJlZCBhcyBVVEYtOCwgd2hpY2ggb3Zlci1jb3VudHMgcmF0aGVyIHRoYW4gbGV0dGluZ1xuICogYW4gdW5yZWNvZ25pemVkIGVuY29kaW5nIHNsaXAgcGFzdCB0aGUgc2l6ZSBjYXAuXG4gKi9cbmNvbnN0IENPTlRFTlRfRU5DT0RJTkdTOiBSZWFkb25seVNldDxzdHJpbmc+ID0gbmV3IFNldChbXG4gIFwiYXNjaWlcIixcbiAgXCJiYXNlNjRcIixcbiAgXCJiYXNlNjR1cmxcIixcbiAgXCJiaW5hcnlcIixcbiAgXCJoZXhcIixcbiAgXCJsYXRpbjFcIixcbiAgXCJ1Y3MyXCIsXG4gIFwidWNzLTJcIixcbiAgXCJ1dGY4XCIsXG4gIFwidXRmLThcIixcbiAgXCJ1dGYxNmxlXCIsXG4gIFwidXRmLTE2bGVcIixcbl0pO1xuXG4vKipcbiAqIERlY29kZWQgYnl0ZSBzaXplIG9mIG9uZSBhdHRhY2htZW50J3MgaW5saW5lIGNvbnRlbnQuIEEgYHBhdGhgIGF0dGFjaG1lbnRcbiAqIGNvbnRyaWJ1dGVzIG5vdGhpbmc6IG5vZGVtYWlsZXIgc3RyZWFtcyBpdCwgc28gaXRzIGJ5dGVzIG5ldmVyIHNpdCBpbiB0aGlzXG4gKiBwcm9jZXNzIGFuZCBjYW5ub3QgYmUgbWVhc3VyZWQgaGVyZS5cbiAqL1xuZnVuY3Rpb24gYXR0YWNobWVudEJ5dGVzKGF0dGFjaG1lbnQ6IEVtYWlsQXR0YWNobWVudCk6IG51bWJlciB7XG4gIGNvbnN0IHsgY29udGVudCwgZW5jb2RpbmcgfSA9IGF0dGFjaG1lbnQ7XG4gIGlmIChjb250ZW50ID09PSB1bmRlZmluZWQpIHJldHVybiAwO1xuICBjb25zdCBkZWNsYXJlZCA9IGVuY29kaW5nPy50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCByZXNvbHZlZCA9XG4gICAgZGVjbGFyZWQgJiYgQ09OVEVOVF9FTkNPRElOR1MuaGFzKGRlY2xhcmVkKSA/IChkZWNsYXJlZCBhcyBCdWZmZXJFbmNvZGluZykgOiBcInV0ZjhcIjtcbiAgcmV0dXJuIEJ1ZmZlci5ieXRlTGVuZ3RoKGNvbnRlbnQsIHJlc29sdmVkKTtcbn1cblxuLyoqXG4gKiBSZWplY3QgYSBtZXNzYWdlIHdob3NlIGJvZHkgb3IgYXR0YWNobWVudHMgZXhjZWVkIHRoZSBwbHVnaW4ncyBjYXBzLiBUaGVcbiAqIGJvZHkgYW5kIGF0dGFjaG1lbnQgbGlzdCBhcnJpdmUgZnJvbSBhIG1vZGVsLCBzbyB0aGV5IGFyZSB1bmJvdW5kZWQgdW50aWxcbiAqIHNvbWV0aGluZyBib3VuZHMgdGhlbTsgbW9zdCBTTVRQIHJlbGF5cyBhbHNvIHJlamVjdCBhbiBvdmVyc2l6ZWQgbWVzc2FnZVxuICogb25seSBhZnRlciB0aGUgd2hvbGUgcGF5bG9hZCBoYXMgYmVlbiB1cGxvYWRlZC5cbiAqL1xuZnVuY3Rpb24gYXNzZXJ0TWVzc2FnZVdpdGhpbkNhcHMobWVzc2FnZTogRW1haWxNZXNzYWdlKTogdm9pZCB7XG4gIGlmIChtZXNzYWdlLmJvZHkubGVuZ3RoID4gTUFYX0JPRFlfQ0hBUlMpIHtcbiAgICB0aHJvdyBWYWxpZGF0aW9uRXJyb3IuaW52YWxpZFZhbHVlKFxuICAgICAgXCJib2R5XCIsXG4gICAgICBtZXNzYWdlLmJvZHkubGVuZ3RoLFxuICAgICAgYGF0IG1vc3QgJHtNQVhfQk9EWV9DSEFSU30gY2hhcmFjdGVyc2AsXG4gICAgKTtcbiAgfVxuICBjb25zdCBhdHRhY2htZW50cyA9IG1lc3NhZ2UuYXR0YWNobWVudHMgPz8gW107XG4gIGlmIChhdHRhY2htZW50cy5sZW5ndGggPiBNQVhfQVRUQUNITUVOVF9DT1VOVCkge1xuICAgIHRocm93IFZhbGlkYXRpb25FcnJvci5pbnZhbGlkVmFsdWUoXG4gICAgICBcImF0dGFjaG1lbnRzXCIsXG4gICAgICBhdHRhY2htZW50cy5sZW5ndGgsXG4gICAgICBgYXQgbW9zdCAke01BWF9BVFRBQ0hNRU5UX0NPVU5UfSBmaWxlc2AsXG4gICAgKTtcbiAgfVxuICBsZXQgdG90YWwgPSAwO1xuICBmb3IgKGNvbnN0IGF0dGFjaG1lbnQgb2YgYXR0YWNobWVudHMpIHtcbiAgICBjb25zdCBieXRlcyA9IGF0dGFjaG1lbnRCeXRlcyhhdHRhY2htZW50KTtcbiAgICBpZiAoYnl0ZXMgPiBNQVhfQVRUQUNITUVOVF9CWVRFUykge1xuICAgICAgdGhyb3cgVmFsaWRhdGlvbkVycm9yLmludmFsaWRWYWx1ZShcbiAgICAgICAgXCJhdHRhY2htZW50c1tdLmNvbnRlbnRcIixcbiAgICAgICAgYnl0ZXMsXG4gICAgICAgIGBhdCBtb3N0ICR7TUFYX0FUVEFDSE1FTlRfQllURVN9IGJ5dGVzIHBlciBmaWxlYCxcbiAgICAgICk7XG4gICAgfVxuICAgIHRvdGFsICs9IGJ5dGVzO1xuICB9XG4gIGlmICh0b3RhbCA+IE1BWF9BVFRBQ0hNRU5UU19UT1RBTF9CWVRFUykge1xuICAgIHRocm93IFZhbGlkYXRpb25FcnJvci5pbnZhbGlkVmFsdWUoXG4gICAgICBcImF0dGFjaG1lbnRzXCIsXG4gICAgICB0b3RhbCxcbiAgICAgIGBhdCBtb3N0ICR7TUFYX0FUVEFDSE1FTlRTX1RPVEFMX0JZVEVTfSBieXRlcyBhY3Jvc3MgYWxsIGZpbGVzYCxcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogTWFwIHRoZSB3aXJlLWZvcm1hdCB7QGxpbmsgRW1haWxBdHRhY2htZW50fXMgb250byBub2RlbWFpbGVyJ3NcbiAqIGF0dGFjaG1lbnQgc2hhcGUsIGRyb3BwaW5nIHVuc2V0IG9wdGlvbmFsIGtleXMgc28gbm9kZW1haWxlciBhcHBsaWVzXG4gKiBpdHMgb3duIGRlZmF1bHRzICh1dGYtOCBlbmNvZGluZywgZmlsZW5hbWUtaW5mZXJyZWQgY29udGVudCB0eXBlKS4gVGhlXG4gKiB3aXJlIGZpZWxkcyBhcmUgYSBkZWxpYmVyYXRlIHN1YnNldCBvZiBub2RlbWFpbGVyJ3MsIHNvIHRoaXMgaXMgYVxuICogc3RyYWlnaHQgc3RydWN0dXJhbCBwYXNzLXRocm91Z2guXG4gKi9cbmZ1bmN0aW9uIHRvTWFpbEF0dGFjaG1lbnRzKFxuICBhdHRhY2htZW50czogRW1haWxBdHRhY2htZW50W10gfCB1bmRlZmluZWQsXG4pOiBTZW5kTWFpbE9wdGlvbnNbXCJhdHRhY2htZW50c1wiXSB7XG4gIGlmICghYXR0YWNobWVudHMgfHwgYXR0YWNobWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4gYXR0YWNobWVudHMubWFwKChhdHQpID0+ICh7XG4gICAgZmlsZW5hbWU6IGF0dC5maWxlbmFtZSxcbiAgICAuLi4oYXR0LmNvbnRlbnQgIT09IHVuZGVmaW5lZCA/IHsgY29udGVudDogYXR0LmNvbnRlbnQgfSA6IHt9KSxcbiAgICAuLi4oYXR0LmVuY29kaW5nICE9PSB1bmRlZmluZWQgPyB7IGVuY29kaW5nOiBhdHQuZW5jb2RpbmcgfSA6IHt9KSxcbiAgICAuLi4oYXR0LnBhdGggIT09IHVuZGVmaW5lZCA/IHsgcGF0aDogYXR0LnBhdGggfSA6IHt9KSxcbiAgICAuLi4oYXR0LmNvbnRlbnRUeXBlICE9PSB1bmRlZmluZWQgPyB7IGNvbnRlbnRUeXBlOiBhdHQuY29udGVudFR5cGUgfSA6IHt9KSxcbiAgfSkpO1xufVxuXG4vKipcbiAqIEhhbmQgb25lIGFscmVhZHktdmFsaWRhdGVkIG1lc3NhZ2UgdG8gU01UUCwgb3Igd3JpdGUgaXQgdG8gdGhlIG91dGJveCB3aGVuXG4gKiBubyBjcmVkZW50aWFscyBhcmUgY29uZmlndXJlZC4gVGhlIGhhbGYgb2YgYSBzZW5kIHRoYXQgcGVyZm9ybXMgSS9PLCBzbyBpdFxuICogaXMgd2hhdCBydW5zIGluc2lkZSB0aGUgaW50ZXJjZXB0b3IgY2hhaW4uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGRpc3BhdGNoKFxuICBtZXNzYWdlOiBFbWFpbE1lc3NhZ2UsXG4gIGZyb206IHN0cmluZyxcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPEVtYWlsUmVzdWx0PiB7XG4gIGNvbnN0IHsgY29uZmlnLCB0cmFuc3BvcnRlciB9ID0gZ2V0RW1haWxSdW50aW1lKCk7XG4gIGNvbnN0IHJlY2lwaWVudCA9IHJlY2lwaWVudEVjaG8obWVzc2FnZS50byk7XG4gIHNpZ25hbD8udGhyb3dJZkFib3J0ZWQoKTtcblxuICBpZiAoY29uZmlnLm1vZGUgPT09IFwiZmlsZVwiKSB7XG4gICAgY29uc3QgcGF0aCA9IGF3YWl0IHdyaXRlT3V0Ym94RW1haWwobWVzc2FnZSwgZnJvbSwgY29uZmlnLm91dERpciwgY29uZmlnLmJyYW5kKTtcbiAgICByZXR1cm4geyBzZW50OiB0cnVlLCByZWNpcGllbnQsIGZyb20sIG1lc3NhZ2VJZDogcGF0aCB9O1xuICB9XG5cbiAgaWYgKCF0cmFuc3BvcnRlcikge1xuICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5pbnZhbGlkQ29ubmVjdGlvbihcbiAgICAgIFwiU01UUFwiLFxuICAgICAgXCJObyB0cmFuc3BvcnQgd2FzIGJ1aWx0IGZvciB0aGUgcmVzb2x2ZWQgY29uZmlndXJhdGlvbi5cIixcbiAgICApO1xuICB9XG4gIGNvbnN0IGF0dGFjaG1lbnRzID0gdG9NYWlsQXR0YWNobWVudHMobWVzc2FnZS5hdHRhY2htZW50cyk7XG4gIGNvbnN0IGluZm8gPSBhd2FpdCBhYm9ydGFibGUoXG4gICAgdHJhbnNwb3J0ZXIuc2VuZE1haWwoe1xuICAgICAgZnJvbSxcbiAgICAgIHRvOiBtZXNzYWdlLnRvLFxuICAgICAgc3ViamVjdDogbWVzc2FnZS5zdWJqZWN0LFxuICAgICAgdGV4dDogbWVzc2FnZS5ib2R5LFxuICAgICAgaHRtbDogcmVuZGVyRW1haWxIdG1sKHtcbiAgICAgICAgc3ViamVjdDogbWVzc2FnZS5zdWJqZWN0LFxuICAgICAgICBib2R5OiBtZXNzYWdlLmJvZHksXG4gICAgICAgIC4uLihjb25maWcuYnJhbmQgPyB7IGJyYW5kOiBjb25maWcuYnJhbmQgfSA6IHt9KSxcbiAgICAgIH0pLFxuICAgICAgLi4uKG1lc3NhZ2UuY2MgJiYgbWVzc2FnZS5jYy5sZW5ndGggPiAwID8geyBjYzogbWVzc2FnZS5jYyB9IDoge30pLFxuICAgICAgLi4uKG1lc3NhZ2UuYmNjICYmIG1lc3NhZ2UuYmNjLmxlbmd0aCA+IDAgPyB7IGJjYzogbWVzc2FnZS5iY2MgfSA6IHt9KSxcbiAgICAgIC4uLihhdHRhY2htZW50cyA/IHsgYXR0YWNobWVudHMgfSA6IHt9KSxcbiAgICB9KSxcbiAgICBzaWduYWwsXG4gICk7XG4gIHJldHVybiB7XG4gICAgc2VudDogdHJ1ZSxcbiAgICByZWNpcGllbnQsXG4gICAgZnJvbSxcbiAgICAuLi4oaW5mby5tZXNzYWdlSWQgPyB7IG1lc3NhZ2VJZDogaW5mby5tZXNzYWdlSWQgfSA6IHt9KSxcbiAgfTtcbn1cblxuLyoqXG4gKiBTZW5kIChTTVRQIG1vZGUpIG9yIHBlcnNpc3QgKGZpbGUvb3V0Ym94IG1vZGUpIG9uZSBtZXNzYWdlIGZyb20gdGhlXG4gKiByZXNvbHZlZCBgZnJvbWAgYWRkcmVzcy4gYHRvYCAoYW5kIG9wdGlvbmFsIGBjY2AgLyBgYmNjYCkgZWFjaCBhY2NlcHRcbiAqIG9uZSBvciBtb3JlIGFkZHJlc3NlcywgYW5kIGBhdHRhY2htZW50c2AgYXJlIGZvcndhcmRlZCBhcyBmaWxlcy4gVGhlXG4gKiBib2R5IGlzIG1hcmtkb3duOiBTTVRQIHNlbmRzIGl0IGFzIGJvdGggYSBwbGFpbi10ZXh0IHBhcnQgKHRoZSByYXdcbiAqIHNvdXJjZSkgYW5kIGFuIEhUTUwgcGFydCAocmVuZGVyZWQpLCBhbmQgdGhlIG91dGJveCBlbWJlZHMgdGhlXG4gKiByZW5kZXJlZCBIVE1MIGluIGEgZG9jdW1lbnQuIEluIGZpbGUgbW9kZSB0aGUgcmV0dXJuZWQgYG1lc3NhZ2VJZGAgaXNcbiAqIHRoZSBwYXRoIHdyaXR0ZW4uIFRocm93cyB3aGVuIGB0b2AgY2FycmllcyBubyByZWNpcGllbnQsIHdoZW4gdGhlIGJvZHlcbiAqIG9yIGF0dGFjaG1lbnRzIGV4Y2VlZCB0aGUgcGx1Z2luJ3MgY2Fwcywgb3Igd2hlbiBgZnJvbWAgaXMgbm90IHBlcm1pdHRlZFxuICogYnkgdGhlIGVmZmVjdGl2ZSBzZW5kZXIgYWxsb3ctbGlzdC5cbiAqXG4gKiBUaGUgcmVjaXBpZW50LCBjYXAsIGFuZCBzZW5kZXIgY2hlY2tzIHJ1biBiZWZvcmUgdGhlIGludGVyY2VwdG9yIGNoYWluIHNvXG4gKiB0aGVpciBzcGVjaWZpYyBzdGF0dXMgYW5kIGFjdGlvbmFibGUgbWVzc2FnZSByZWFjaCB0aGUgY2FsbGVyIGluc3RlYWQgb2ZcbiAqIHRoZSBjaGFpbidzIHN0YWJsZSBmYWlsdXJlIHRleHQuIGBzaWduYWxgIGNhbmNlbHMgdGhlIHNlbmQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZW5kRW1haWwoXG4gIG1lc3NhZ2U6IEVtYWlsTWVzc2FnZSxcbiAgZnJvbTogc3RyaW5nLFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8RW1haWxSZXN1bHQ+IHtcbiAgaWYgKG1lc3NhZ2UudG8ubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgVmFsaWRhdGlvbkVycm9yLm1pc3NpbmdGaWVsZChcInRvXCIpO1xuICB9XG4gIGFzc2VydE1lc3NhZ2VXaXRoaW5DYXBzKG1lc3NhZ2UpO1xuICBhc3NlcnRTZW5kZXJBbGxvd2VkKGZyb20sIGdldEVtYWlsUnVudGltZSgpLmNvbmZpZy5hbGxvd2VkU2VuZGVycyk7XG4gIHJldHVybiBleGVjdXRlV3JpdGUoXG4gICAgXCJzZW5kXCIsXG4gICAgRU1BSUxfU0VORF9TRVRUSU5HUyxcbiAgICAoZXhlY3V0ZVNpZ25hbCkgPT4gZGlzcGF0Y2gobWVzc2FnZSwgZnJvbSwgZXhlY3V0ZVNpZ25hbCksXG4gICAgc2lnbmFsLFxuICApO1xufVxuIl19
@@ -0,0 +1 @@
1
+ {"root":["../src/brand.ts","../src/config.ts","../src/defaults.ts","../src/email-html.ts","../src/juice.d.ts","../src/markdown.ts","../src/outbox.ts","../src/plugin.ts","../src/sender.ts","../src/tool.ts","../src/transport.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -19,24 +19,28 @@
19
19
  "juice": "^12.1.1",
20
20
  "marked": "^18.0.5",
21
21
  "nodemailer": "^7.0.13",
22
- "@dbx-tools/shared-core": "0.3.44",
23
- "@dbx-tools/shared-email": "0.3.44"
22
+ "@dbx-tools/shared-core": "0.4.0",
23
+ "@dbx-tools/shared-email": "0.4.0"
24
24
  },
25
- "main": "index.ts",
25
+ "main": "./lib/index.js",
26
26
  "license": "UNLICENSED",
27
27
  "publishConfig": {
28
28
  "access": "public"
29
29
  },
30
- "version": "0.3.44",
31
- "types": "index.ts",
30
+ "version": "0.4.0",
31
+ "types": "./lib/index.d.ts",
32
32
  "type": "module",
33
33
  "exports": {
34
- ".": "./index.ts",
34
+ ".": {
35
+ "types": "./lib/index.d.ts",
36
+ "default": "./lib/index.js"
37
+ },
35
38
  "./package.json": "./package.json"
36
39
  },
37
40
  "files": [
38
41
  "index.ts",
39
- "src"
42
+ "src",
43
+ "lib"
40
44
  ],
41
45
  "dbxToolsConfig": {
42
46
  "tags": [