@qawolf/emails 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 QA Wolf Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # @qawolf/emails
2
+
3
+ `@qawolf/emails` is a TypeScript toolkit designed to help you use QA
4
+ Wolf-managed inboxes in email-driven tests.
5
+
6
+ The QA Wolf runner configures the emails client for each flow, so flow code can
7
+ call `mail.inbox()` directly. Use it to create inbox addresses, wait for
8
+ inbound messages, parse links from email content, and send outbound messages.
9
+
10
+ To learn more about how to use `@qawolf/emails`, check out the
11
+ [API Reference](https://docs.qawolf.com/qawolf/libraries/emails/api-reference/mail)
12
+ and [Documentation](https://docs.qawolf.com/qawolf/libraries/emails).
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ npm install @qawolf/emails
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ Create a fresh inbox for the current run, trigger an email in your app, and
23
+ continue with the message QA Wolf receives.
24
+
25
+ ```ts
26
+ import { mail } from "@qawolf/emails";
27
+
28
+ const inbox = await mail.inbox({ new: true });
29
+
30
+ await page.getByLabel("Email").fill(inbox.emailAddress);
31
+
32
+ const after = new Date();
33
+ await page.getByRole("button", { name: "Send magic link" }).click();
34
+
35
+ const message = await inbox.waitForMessage({ after });
36
+ const signInUrl = message.urls[0];
37
+ ```
38
+
39
+ Pass `new: true` for most tests. It creates a unique derived address so emails
40
+ from earlier runs do not affect the current flow. If your app does not support
41
+ plus addresses, pass a custom `delimiter`.
42
+
43
+ ```ts
44
+ const inbox = await mail.inbox({ new: true, delimiter: "-" });
45
+ ```
46
+
47
+ Capture `after` immediately before the app action that should send email. This
48
+ keeps `waitForMessage(...)` pinned to the message caused by that action.
49
+
50
+ Send email from the same inbox when your workflow needs an inbound message or
51
+ reply.
52
+
53
+ ```ts
54
+ await inbox.sendMessage({
55
+ to: ["support@example.com"],
56
+ subject: "Test message",
57
+ text: "Hello from a QA Wolf flow",
58
+ });
59
+ ```
60
+
61
+ For runners and local harnesses, create and configure a client before invoking
62
+ flow code.
63
+
64
+ ```ts
65
+ import { configureEmailsClient, createEmailsClient } from "@qawolf/emails";
66
+
67
+ const emails = await createEmailsClient({
68
+ emailerUrl: process.env["EMAILER_URL"]!,
69
+ pollForEmailsDefaultTimeoutMs: 300_000,
70
+ teamId: process.env["QAWOLF_TEAM_ID"],
71
+ waitForMessagesDefaultDelayMs: 15_000,
72
+ });
73
+
74
+ configureEmailsClient(emails);
75
+ ```
@@ -0,0 +1,46 @@
1
+ import type { QueryEmailsOutput, SendEmailInput } from "@qawolf/emailer-types";
2
+ import { type GetInboxOptions, type ParsedEmail, type SendMessage, type SendMessageResult, type WaitForMessage } from "./types.js";
3
+ export type GetInboxFn = {
4
+ (args?: GetInboxOptions): Promise<GetInboxResult>;
5
+ };
6
+ export type GetInboxResult = {
7
+ emailAddress: string;
8
+ sendMessage: (options: SendMessage) => Promise<SendMessageResult>;
9
+ waitForMessage: (options: WaitForMessage) => Promise<ParsedEmail>;
10
+ waitForMessages: (options: WaitForMessage) => Promise<ParsedEmail[]>;
11
+ };
12
+ /** Configuration for the emails client and inbox helpers. */
13
+ export type EmailsClientOptions = {
14
+ /** The URL of the emailer service. */
15
+ emailerUrl: string;
16
+ /** A function that can be used to log messages. */
17
+ logger?: (severity: string, message: string) => void;
18
+ /** The default timeout when polling for emails. */
19
+ pollForEmailsDefaultTimeoutMs: number;
20
+ /** The ID of the workspace to send and receive emails for. */
21
+ teamId?: string;
22
+ /** The default delay when waiting for messages. */
23
+ waitForMessagesDefaultDelayMs: number;
24
+ };
25
+ /**
26
+ * Build a `getInbox` function directly.
27
+ *
28
+ * Prefer `createEmailsClient()` for new code and use this helper only when a
29
+ * runtime still needs to inject `getInbox` for backward compatibility.
30
+ */
31
+ export declare function buildGetInboxFn({ emailerUrl, logger, pollForEmailsDefaultTimeoutMs, teamId, waitForMessagesDefaultDelayMs, }: EmailsClientOptions): Promise<GetInboxFn>;
32
+ /**
33
+ * Build a list of ParsedEmail from a QueryEmailsOutput.
34
+ * @param email The output from the emailer.
35
+ */
36
+ export declare const buildParsedEmails: (email: QueryEmailsOutput) => ParsedEmail[];
37
+ /**
38
+ * Build a SendEmailInput to be sent over to the emailer.
39
+ * @param opts The options to build the input from.
40
+ */
41
+ export declare const buildSendEmailInput: (opts: {
42
+ email: SendMessage;
43
+ from: string;
44
+ teamId: string;
45
+ }) => SendEmailInput;
46
+ //# sourceMappingURL=buildGetInboxFn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildGetInboxFn.d.ts","sourceRoot":"","sources":["../src/buildGetInboxFn.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAIV,iBAAiB,EACjB,cAAc,EAIf,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAIpB,MAAM,YAAY,CAAC;AAmCpB,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAClE,eAAe,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CACtE,CAAC;AASF,6DAA6D;AAC7D,MAAM,MAAM,mBAAmB,GAAG;IAChC,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,mDAAmD;IACnD,6BAA6B,EAAE,MAAM,CAAC;IACtC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,6BAA6B,EAAE,MAAM,CAAC;CACvC,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,EACpC,UAAU,EACV,MAAM,EACN,6BAA6B,EAC7B,MAAM,EACN,6BAA6B,GAC9B,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAkQ3C;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,iBAAiB,KAAG,WAAW,EAyBvE,CAAC;AAsFF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM;IACxC,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,KAAG,cAwBH,CAAC"}
@@ -0,0 +1,322 @@
1
+ /* eslint-disable @qawolf/max-lines -- Old technical debt */
2
+ import { init } from "@paralleldrive/cuid2";
3
+ import retry, { AbortError } from "p-retry";
4
+ import superJson, {} from "superjson";
5
+ import { getNamedAddress, getNamedAddressAsString, } from "@qawolf/emailer-types";
6
+ import { extractUrlsFromHtml } from "./extractUrlsFromHtml.js";
7
+ import { getInboxOptionsSchema, sendMessageSchema, waitForMessageSchema, } from "./types.js";
8
+ const createEmailSuffix = init({ length: 7 });
9
+ /**
10
+ * Build a `getInbox` function directly.
11
+ *
12
+ * Prefer `createEmailsClient()` for new code and use this helper only when a
13
+ * runtime still needs to inject `getInbox` for backward compatibility.
14
+ */
15
+ export async function buildGetInboxFn({ emailerUrl, logger, pollForEmailsDefaultTimeoutMs, teamId, waitForMessagesDefaultDelayMs, }) {
16
+ const trimmed = emailerUrl[emailerUrl.length - 1] === "/"
17
+ ? emailerUrl.slice(0, -1)
18
+ : emailerUrl;
19
+ // Use the emailer service's documented HTTP tRPC endpoints directly so this
20
+ // public package does not depend on our private shared tRPC client package.
21
+ // WIZ-10243 tracks replacing this with public emailer tRPC API types.
22
+ const callEmailerQuery = async (procedure, input) => {
23
+ const url = new URL(`/v1/trpc/${procedure}`, trimmed);
24
+ const encodedInput = JSON.stringify(input);
25
+ if (!encodedInput)
26
+ throw Error("Emailer query input must be JSON");
27
+ url.searchParams.set("input", encodedInput);
28
+ return callEmailer(url, { method: "GET" });
29
+ };
30
+ const callEmailerMutation = async (procedure, input) => {
31
+ return callEmailer(new URL(`/v1/trpc/${procedure}`, trimmed), {
32
+ body: JSON.stringify(input),
33
+ headers: {
34
+ "content-type": "application/json",
35
+ },
36
+ method: "POST",
37
+ });
38
+ };
39
+ /**
40
+ * Poll the emailer for all emails that match the given criteria.
41
+ * @param options Polling options
42
+ * @returns An array of emails. An empty array is returned only if the timeout is reached.
43
+ * Otherwise it will keep polling until there is at least one (or minCount) email.
44
+ */
45
+ async function pollForEmails({ createdAfter, minCount = 1, target, timeoutMs = pollForEmailsDefaultTimeoutMs, }) {
46
+ if (minCount < 1)
47
+ throw Error("minCount must be at least 1");
48
+ if (timeoutMs < 0)
49
+ throw Error("timeoutMs must be at least 0");
50
+ let timeout = false;
51
+ const requestPromise = retry(async (attempt) => {
52
+ if (timeout)
53
+ return [];
54
+ try {
55
+ if (logger) {
56
+ logger("verbose", `wait for email in mailbox of ${target}, attempt ${attempt}`);
57
+ }
58
+ const result = await callEmailerQuery("emails.query", {
59
+ createdAt: {
60
+ after: createdAfter.toISOString(),
61
+ },
62
+ isInbound: true,
63
+ ownerId: teamId,
64
+ target: getNamedAddress(target).address,
65
+ });
66
+ if (result.type === "targetOwnerDoesNotMatch")
67
+ throw new AbortError(`${target} is not allowed for this workspace`);
68
+ const { data } = result;
69
+ if (!data || data.length < minCount) {
70
+ throw Error(`${target} has not yet received ${minCount} email${minCount === 1 ? "" : "s"} after ${createdAfter.toISOString()}`);
71
+ }
72
+ if (logger)
73
+ logger("info", `found ${data.length} emails for ${target}`);
74
+ return buildParsedEmails(data);
75
+ }
76
+ catch (e) {
77
+ if (logger)
78
+ logger("verbose", `pollForEmail failed ${e}`);
79
+ throw e;
80
+ }
81
+ }, {
82
+ factor: 1,
83
+ maxTimeout: 3000,
84
+ minTimeout: 3000,
85
+ retries: Math.round(timeoutMs / 3000),
86
+ });
87
+ const timeoutPromise = (async () => {
88
+ await sleep(timeoutMs);
89
+ timeout = true;
90
+ throw Error(`No email for ${target} is found`);
91
+ })();
92
+ return Promise.race([requestPromise, timeoutPromise]);
93
+ }
94
+ return async (args = {}) => {
95
+ if (!teamId)
96
+ throw Error("teamId is required");
97
+ getInboxOptionsSchema.parse(args);
98
+ // The rest of the function cannot run if emailAddress ends up being undefined,
99
+ // so we make sure it's always string.
100
+ let emailAddress = args.address ??
101
+ (await (async () => {
102
+ const defaultAddresses = getEmailerData(await callEmailerQuery("addresses.query", {
103
+ constraints: {
104
+ limit: 1,
105
+ },
106
+ isDefault: true,
107
+ ownerId: teamId,
108
+ }));
109
+ if (defaultAddresses.length < 1) {
110
+ throw Error(`no default address has been found for workspace ${teamId}`);
111
+ }
112
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Old technical debt
113
+ return defaultAddresses[0].emailAddress;
114
+ })());
115
+ if (args.new) {
116
+ const [inbox, domain] = emailAddress.split("@");
117
+ // Emailer service handles plus addresses automatically but for
118
+ // any other delimiter we need to save the address temporarily
119
+ // for the inbound parse webhook to match to.
120
+ emailAddress = `${inbox}${args.delimiter ?? "+"}${createEmailSuffix()}@${domain}`;
121
+ if (args.delimiter && args.delimiter !== "+") {
122
+ await callEmailerMutation("addresses.upsert", {
123
+ emailAddress,
124
+ isTemporary: true,
125
+ ownerId: teamId,
126
+ });
127
+ }
128
+ }
129
+ const calledAt = new Date();
130
+ /**
131
+ * Send an email from the address you've chosen.
132
+ * @returns The stripped-down version of the email that was sent
133
+ * @param email The email to send.
134
+ */
135
+ const sendMessage = async (email) => {
136
+ sendMessageSchema.parse(email);
137
+ if (logger)
138
+ logger("verbose", `will send email to ${email.to.join(", ")}`);
139
+ const sentEmail = await retry(async () => getEmailerData(await callEmailerMutation("emails.send", buildSendEmailInput({
140
+ email,
141
+ from: emailAddress,
142
+ teamId,
143
+ }))), {
144
+ retries: 4,
145
+ });
146
+ if (!sentEmail)
147
+ throw Error("Error sending email");
148
+ if (logger)
149
+ logger("info", `sent email to ${email.to.join(", ")}`);
150
+ return {
151
+ id: sentEmail.id,
152
+ };
153
+ };
154
+ /**
155
+ * Wait for your workspace's test inbox to receive an email and return its details
156
+ * @param options Optional wait configuration
157
+ * @returns The first email received, or throws an error if none received
158
+ */
159
+ const waitForMessage = async ({ after, timeout, } = {}) => {
160
+ waitForMessageSchema.parse({ after, timeout });
161
+ const messages = await pollForEmails({
162
+ createdAfter: after || calledAt,
163
+ target: emailAddress,
164
+ timeoutMs: timeout,
165
+ });
166
+ const [message] = messages;
167
+ if (!message)
168
+ throw Error("no message received");
169
+ return message;
170
+ };
171
+ /**
172
+ * Wait for timeout and then return all emails received at your workspace's test
173
+ * inbox since this function was called. Returns an array with the last received
174
+ * email being the first item in the array.
175
+ * @param options Optional wait configuration
176
+ * @returns All messages received between `after` and `after+timeout`
177
+ */
178
+ const waitForMessages = async ({ after, delay = waitForMessagesDefaultDelayMs, minCount, timeout, } = {}) => {
179
+ waitForMessageSchema.parse({ after, timeout });
180
+ if (logger) {
181
+ logger("verbose", `delaying ${delay}ms before checking for received emails`);
182
+ }
183
+ await sleep(delay);
184
+ const parsedEmails = await pollForEmails({
185
+ createdAfter: after || calledAt,
186
+ minCount,
187
+ target: emailAddress,
188
+ timeoutMs: timeout,
189
+ });
190
+ if (logger) {
191
+ logger("verbose", "waitForMessages result: " +
192
+ JSON.stringify({
193
+ messageCount: parsedEmails.length,
194
+ target: emailAddress,
195
+ }));
196
+ }
197
+ return parsedEmails;
198
+ };
199
+ return {
200
+ emailAddress,
201
+ sendMessage,
202
+ waitForMessage,
203
+ waitForMessages,
204
+ };
205
+ };
206
+ }
207
+ /**
208
+ * Build a list of ParsedEmail from a QueryEmailsOutput.
209
+ * @param email The output from the emailer.
210
+ */
211
+ export const buildParsedEmails = (email) => {
212
+ return email
213
+ .map((message) => ({
214
+ attachments: message.attachments?.map((attachment) => {
215
+ return {
216
+ content: Buffer.from(attachment.contentBase64, "base64"),
217
+ fileName: attachment.fileName,
218
+ type: attachment.type,
219
+ };
220
+ }),
221
+ bcc: message.bcc?.map(getNamedAddressAsString),
222
+ cc: message.cc?.map(getNamedAddressAsString),
223
+ from: getNamedAddressAsString(message.from),
224
+ html: message.html ?? "",
225
+ id: message.id,
226
+ replyTo: message.replyTo?.map(getNamedAddressAsString),
227
+ subject: message.subject ?? "",
228
+ teamId: message.ownerId,
229
+ text: message.text ?? "",
230
+ to: message.to.map(getNamedAddressAsString),
231
+ }))
232
+ .map((message) => {
233
+ const urls = extractUrlsFromHtml(message.html);
234
+ return { ...message, urls };
235
+ });
236
+ };
237
+ async function callEmailer(url, init) {
238
+ const response = await fetch(url, init);
239
+ const body = await response.text();
240
+ if (!body) {
241
+ if (!response.ok)
242
+ throw Error(`Emailer request failed with status ${response.status}`);
243
+ throw Error(`Emailer response was empty with status ${response.status}`);
244
+ }
245
+ let json;
246
+ try {
247
+ json = JSON.parse(body);
248
+ }
249
+ catch {
250
+ if (!response.ok) {
251
+ throw Error(`Emailer request failed with status ${response.status}: ${body}`);
252
+ }
253
+ throw Error(`Emailer response was not valid JSON with status ${response.status}`);
254
+ }
255
+ if (json.error)
256
+ return parseEmailerError(json.error, response.status);
257
+ if (!response.ok) {
258
+ throw Error(`Emailer request failed with status ${response.status}: ${body}`);
259
+ }
260
+ if (!json.result)
261
+ throw Error("Emailer response did not include result data");
262
+ return {
263
+ data: deserializeTrpcData(json.result.data),
264
+ type: "success",
265
+ };
266
+ }
267
+ function deserializeTrpcData(data) {
268
+ if (isSuperJsonResult(data))
269
+ return superJson.deserialize(data);
270
+ return data;
271
+ }
272
+ function getEmailerData(result) {
273
+ if (result.type === "targetOwnerDoesNotMatch")
274
+ throw Error("Emailer target is not allowed for this workspace");
275
+ return result.data;
276
+ }
277
+ function isSuperJsonResult(data) {
278
+ return typeof data === "object" && data !== null && "json" in data;
279
+ }
280
+ function parseEmailerError(error, status) {
281
+ if (error.json?.data?.code === "FORBIDDEN" &&
282
+ error.json.message === "targetOwnerDoesNotMatch")
283
+ return { type: "targetOwnerDoesNotMatch" };
284
+ const message = error.json?.message ?? error.message ?? "Emailer request failed";
285
+ const httpStatus = error.json?.data?.httpStatus ?? status;
286
+ throw Error(`Emailer request failed with status ${httpStatus}: ${message}`);
287
+ }
288
+ function sleep(ms) {
289
+ return new Promise((resolve) => {
290
+ setTimeout(resolve, ms);
291
+ });
292
+ }
293
+ /**
294
+ * Build a SendEmailInput to be sent over to the emailer.
295
+ * @param opts The options to build the input from.
296
+ */
297
+ export const buildSendEmailInput = (opts) => {
298
+ const { email, from, teamId } = opts;
299
+ return {
300
+ attachments: email.attachments?.map((attachment) => {
301
+ return {
302
+ contentBase64: attachment.content.toString("base64"),
303
+ contentId: attachment.contentId,
304
+ disposition: attachment.disposition,
305
+ fileName: attachment.fileName,
306
+ type: attachment.type,
307
+ };
308
+ }),
309
+ bcc: email.bcc?.map(getNamedAddress),
310
+ cc: email.cc?.map(getNamedAddress),
311
+ from: getNamedAddress(from),
312
+ html: email.html,
313
+ ownerId: teamId,
314
+ ownerType: "TEAM",
315
+ replyTo: email.replyTo?.map(getNamedAddress),
316
+ replyToMessageId: email.replyToMessageId,
317
+ subject: email.subject,
318
+ text: email.text,
319
+ to: email.to.map(getNamedAddress),
320
+ };
321
+ };
322
+ //# sourceMappingURL=buildGetInboxFn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildGetInboxFn.js","sourceRoot":"","sources":["../src/buildGetInboxFn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { EmailsClient } from "./createEmailsClient.js";
2
+ export declare function configureEmailsClient(client: EmailsClient): void;
3
+ export declare function resetEmailsClient(): void;
4
+ export declare function getCurrentEmailsClient(): EmailsClient | undefined;
5
+ //# sourceMappingURL=clientScope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientScope.d.ts","sourceRoot":"","sources":["../src/clientScope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAI5D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAEhE;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED,wBAAgB,sBAAsB,IAAI,YAAY,GAAG,SAAS,CAEjE"}
@@ -0,0 +1,11 @@
1
+ let currentClient;
2
+ export function configureEmailsClient(client) {
3
+ currentClient = client;
4
+ }
5
+ export function resetEmailsClient() {
6
+ currentClient = undefined;
7
+ }
8
+ export function getCurrentEmailsClient() {
9
+ return currentClient;
10
+ }
11
+ //# sourceMappingURL=clientScope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientScope.js","sourceRoot":"","sources":["../src/clientScope.ts"],"names":[],"mappings":"AAEA,IAAI,aAAuC,CAAC;AAE5C,MAAM,UAAU,qBAAqB,CAAC,MAAoB;IACxD,aAAa,GAAG,MAAM,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,aAAa,GAAG,SAAS,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,aAAa,CAAC;AACvB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type EmailsClientOptions, type GetInboxFn } from "./buildGetInboxFn.js";
2
+ export type { EmailsClientOptions } from "./buildGetInboxFn.js";
3
+ export type EmailsClient = {
4
+ getInbox: GetInboxFn;
5
+ };
6
+ /**
7
+ * Create an emails client that can be used directly in runners, local tooling,
8
+ * or any other environment with access to the QA Wolf emailer service.
9
+ */
10
+ export declare function createEmailsClient(options: EmailsClientOptions): Promise<EmailsClient>;
11
+ //# sourceMappingURL=createEmailsClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createEmailsClient.d.ts","sourceRoot":"","sources":["../src/createEmailsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,UAAU,EAEhB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,UAAU,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAIvB"}
@@ -0,0 +1,11 @@
1
+ import { buildGetInboxFn, } from "./buildGetInboxFn.js";
2
+ /**
3
+ * Create an emails client that can be used directly in runners, local tooling,
4
+ * or any other environment with access to the QA Wolf emailer service.
5
+ */
6
+ export async function createEmailsClient(options) {
7
+ return {
8
+ getInbox: await buildGetInboxFn(options),
9
+ };
10
+ }
11
+ //# sourceMappingURL=createEmailsClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createEmailsClient.js","sourceRoot":"","sources":["../src/createEmailsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAO9B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAA4B;IAE5B,OAAO;QACL,QAAQ,EAAE,MAAM,eAAe,CAAC,OAAO,CAAC;KACzC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const extractUrlsFromHtml: (html: string) => string[];
2
+ //# sourceMappingURL=extractUrlsFromHtml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractUrlsFromHtml.d.ts","sourceRoot":"","sources":["../src/extractUrlsFromHtml.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,aAO/C,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { parse } from "node-html-parser";
2
+ const extractElementAttributes = (doc, ele, attr) => {
3
+ return doc
4
+ .querySelectorAll(ele)
5
+ .map((e) => e.getAttribute(attr))
6
+ .filter((v) => !!v && !v.includes("w3.org"));
7
+ };
8
+ export const extractUrlsFromHtml = (html) => {
9
+ const doc = parse(html);
10
+ const hrefUrls = extractElementAttributes(doc, "a", "href");
11
+ const srcUrls = extractElementAttributes(doc, "img", "src");
12
+ return [...hrefUrls, ...srcUrls].sort();
13
+ };
14
+ //# sourceMappingURL=extractUrlsFromHtml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractUrlsFromHtml.js","sourceRoot":"","sources":["../src/extractUrlsFromHtml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE3D,MAAM,wBAAwB,GAAG,CAC/B,GAAgB,EAChB,GAAW,EACX,IAAY,EACZ,EAAE;IACF,OAAO,GAAG;SACP,gBAAgB,CAAC,GAAG,CAAC;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;SAChC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAY,EAAE,EAAE;IAClD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAExB,MAAM,QAAQ,GAAG,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,wBAAwB,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { GetInboxResult } from "./buildGetInboxFn.js";
2
+ import type { GetInboxOptions } from "./types.js";
3
+ export { type GetInboxFn, type GetInboxResult } from "./buildGetInboxFn.js";
4
+ export { configureEmailsClient, getCurrentEmailsClient, resetEmailsClient, } from "./clientScope.js";
5
+ export { type EmailsClient, type EmailsClientOptions, createEmailsClient, } from "./createEmailsClient.js";
6
+ export type { Email, GetInboxOptions, ParsedEmail, SendMessage, SendMessageResult, WaitForMessage, } from "./types.js";
7
+ export declare const mail: {
8
+ inbox(options?: GetInboxOptions): Promise<GetInboxResult>;
9
+ };
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE5E,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EACV,KAAK,EACL,eAAe,EACf,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,IAAI;oBACO,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CAWhE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ import { getCurrentEmailsClient } from "./clientScope.js";
2
+ export {} from "./buildGetInboxFn.js";
3
+ export { configureEmailsClient, getCurrentEmailsClient, resetEmailsClient, } from "./clientScope.js";
4
+ export { createEmailsClient, } from "./createEmailsClient.js";
5
+ export const mail = {
6
+ async inbox(options) {
7
+ const client = getCurrentEmailsClient();
8
+ if (!client) {
9
+ throw Error("@qawolf/emails mail.inbox() requires a client. Call " +
10
+ "configureEmailsClient(...) once at startup before reading " +
11
+ "mail.inbox().");
12
+ }
13
+ return client.getInbox(options);
14
+ },
15
+ };
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAwC,MAAM,sBAAsB,CAAC;AAE5E,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAGL,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAWjC,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,KAAK,CAAC,KAAK,CAAC,OAAyB;QACnC,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,KAAK,CACT,sDAAsD;gBACpD,4DAA4D;gBAC5D,eAAe,CAClB,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;CACF,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ export type Email = {
3
+ attachments?: {
4
+ content: Buffer;
5
+ fileName: string;
6
+ type?: string;
7
+ }[];
8
+ bcc?: string[];
9
+ cc?: string[];
10
+ from: string;
11
+ html: string;
12
+ id: string;
13
+ replyTo?: string[];
14
+ subject: string;
15
+ teamId: string;
16
+ text: string;
17
+ to: string[];
18
+ };
19
+ export type ParsedEmail = Email & {
20
+ urls: string[];
21
+ };
22
+ export declare const getInboxOptionsSchema: z.ZodObject<{
23
+ address: z.ZodOptional<z.ZodEmail>;
24
+ delimiter: z.ZodOptional<z.ZodString>;
25
+ new: z.ZodOptional<z.ZodBoolean>;
26
+ }, z.core.$strip>;
27
+ export type GetInboxOptions = z.infer<typeof getInboxOptionsSchema>;
28
+ export declare const sendMessageSchema: z.ZodObject<{
29
+ attachments: z.ZodOptional<z.ZodArray<z.ZodObject<{
30
+ content: z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>;
31
+ contentId: z.ZodOptional<z.ZodString>;
32
+ disposition: z.ZodOptional<z.ZodEnum<{
33
+ attachment: "attachment";
34
+ inline: "inline";
35
+ }>>;
36
+ fileName: z.ZodString;
37
+ type: z.ZodOptional<z.ZodString>;
38
+ }, z.core.$strip>>>;
39
+ bcc: z.ZodOptional<z.ZodArray<z.ZodString>>;
40
+ cc: z.ZodOptional<z.ZodArray<z.ZodString>>;
41
+ html: z.ZodOptional<z.ZodString>;
42
+ replyTo: z.ZodOptional<z.ZodArray<z.ZodString>>;
43
+ replyToMessageId: z.ZodOptional<z.ZodString>;
44
+ subject: z.ZodString;
45
+ text: z.ZodOptional<z.ZodString>;
46
+ to: z.ZodArray<z.ZodString>;
47
+ }, z.core.$strip>;
48
+ export type SendMessage = z.infer<typeof sendMessageSchema>;
49
+ export declare const sendMessageResultSchema: z.ZodObject<{
50
+ id: z.ZodString;
51
+ }, z.core.$strip>;
52
+ export type SendMessageResult = z.infer<typeof sendMessageResultSchema>;
53
+ export declare const waitForMessageSchema: z.ZodObject<{
54
+ after: z.ZodOptional<z.ZodDate>;
55
+ delay: z.ZodOptional<z.ZodNumber>;
56
+ minCount: z.ZodOptional<z.ZodNumber>;
57
+ timeout: z.ZodOptional<z.ZodNumber>;
58
+ }, z.core.$strip>;
59
+ export type WaitForMessage = z.infer<typeof waitForMessageSchema>;
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,KAAK,GAAG;IAClB,WAAW,CAAC,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;IACJ,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;iBAIhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;iBAyB1B,CAAC;AACL,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,uBAAuB;;iBAElC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,oBAAoB;;;;;iBAK/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ export const getInboxOptionsSchema = z.object({
3
+ address: z.email().optional(),
4
+ delimiter: z.string().optional(),
5
+ new: z.boolean().optional(),
6
+ });
7
+ export const sendMessageSchema = z
8
+ // The first section is the original SendMessage type.
9
+ .object({
10
+ attachments: z
11
+ .array(z.object({
12
+ content: z.instanceof(Buffer),
13
+ contentId: z.string().optional(),
14
+ disposition: z.enum(["attachment", "inline"]).optional(),
15
+ fileName: z.string(),
16
+ type: z.string().optional(),
17
+ }))
18
+ .optional(),
19
+ bcc: z.array(z.string()).optional(),
20
+ cc: z.array(z.string()).optional(),
21
+ html: z.string().optional(),
22
+ replyTo: z.array(z.string()).optional(),
23
+ replyToMessageId: z.string().optional(),
24
+ subject: z.string(),
25
+ text: z.string().optional(),
26
+ to: z.array(z.string()),
27
+ })
28
+ .refine((data) => data.html || data.text, {
29
+ message: "Either html or text must be provided.",
30
+ });
31
+ export const sendMessageResultSchema = z.object({
32
+ id: z.string(),
33
+ });
34
+ export const waitForMessageSchema = z.object({
35
+ after: z.date().optional(),
36
+ delay: z.number().min(0).optional(),
37
+ minCount: z.number().min(1).optional(),
38
+ timeout: z.number().optional(),
39
+ });
40
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAwBxB,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC7B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;IAChC,sDAAsD;KACrD,MAAM,CAAC;IACN,WAAW,EAAE,CAAC;SACX,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;QAC7B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAChC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;QACxD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC5B,CAAC,CACH;SACA,QAAQ,EAAE;IACb,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACnC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACvC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACxB,CAAC;KACD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE;IACxC,OAAO,EAAE,uCAAuC;CACjD,CAAC,CAAC;AAGL,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;CACf,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACnC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@qawolf/emails",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "sideEffects": false,
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "types": "./dist/index.d.ts",
15
+ "files": [
16
+ "/dist",
17
+ "/LICENSE",
18
+ "/README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "rm -rf ./dist && tsc -p tsconfig.build.json",
22
+ "lint:ci": "npm run lint:non-fixable; NON_FIXABLE_EXIT=$?; npm run lint:fixable && exit $NON_FIXABLE_EXIT",
23
+ "lint:dev": "npm run lint:fixable",
24
+ "lint:fixable": "eslint . --ext cjs,cts,js,jsx,mjs,ts,tsx --fix --quiet && prettier --log-level=warn --write .",
25
+ "lint:non-fixable": "dpdm --exit-code circular:1 --no-tree --no-warning --transform --include='.*' --exclude='/(dist|node_modules)/' '**/*'",
26
+ "prepublishOnly": "nx run emails:build",
27
+ "test": "NODE_OPTIONS=\"--experimental-vm-modules\" NODE_NO_WARNINGS=1 jest",
28
+ "test:watch": "npm run test -- --watch",
29
+ "tsc:check": "tsc"
30
+ },
31
+ "dependencies": {
32
+ "@paralleldrive/cuid2": "^2.2.0",
33
+ "@qawolf/emailer-types": "^1.0.0",
34
+ "msw": "^2.12.14",
35
+ "node-html-parser": "^6.1.13",
36
+ "p-retry": "^6.2.1",
37
+ "superjson": "^2.2.6",
38
+ "tslib": "^2.5.3",
39
+ "zod": "^4.1.11"
40
+ },
41
+ "devDependencies": {
42
+ "typescript": "^5.9.2"
43
+ },
44
+ "engines": {
45
+ "node": ">=20.19.0 <25"
46
+ },
47
+ "nx": {
48
+ "targets": {
49
+ "npm:publish": {}
50
+ }
51
+ }
52
+ }