@letsrunit/mailbox 0.21.1 → 0.23.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/README.md CHANGED
@@ -20,7 +20,7 @@ Generates a deterministic email address based on a seed (UUID).
20
20
 
21
21
  - **`seed`**: A UUID used to ensure the email is unique but reproducible.
22
22
  - **`name`**: Optional sub-address name.
23
- - **`domain`**: Optional domain. Defaults to the configured `MAILBOX_DOMAIN`.
23
+ - **`domain`**: Optional domain. Defaults to the configured `LETSRUNIT_MAILBOX_DOMAIN`.
24
24
 
25
25
  ### `receiveMail(emailAddress, options)`
26
26
 
@@ -28,8 +28,8 @@ Retrieves emails sent to a specific address.
28
28
 
29
29
  - **`emailAddress`**: The address to check.
30
30
  - **`options`**:
31
- - `timeout`: How long to wait for emails.
32
- - `until`: A predicate function to stop polling when an email is found.
31
+ - `timeout`: How long to wait for emails.
32
+ - `until`: A predicate function to stop polling when an email is found.
33
33
 
34
34
  ### `toEml(email)`
35
35
 
@@ -41,19 +41,25 @@ Convert a string in `.eml` from to an `Email` object.
41
41
 
42
42
  ## Supported Services
43
43
 
44
- The package automatically selects the service based on the `MAILBOX_SERVICE` environment variable.
44
+ The package automatically selects the service based on the `LETSRUNIT_MAILBOX_SERVICE` environment variable.
45
45
 
46
46
  ### [Mailpit](https://mailpit.axllent.org/)
47
+
47
48
  Recommended for local development. It provides a fast, lightweight way to capture and view emails.
48
- - **Environment Variables**: `MAILPIT_BASE_URL` (defaults to `http://localhost:8025`).
49
+
50
+ - **Environment Variables**: `LETSRUNIT_MAILPIT_BASE_URL` (defaults to `http://localhost:8025`).
49
51
 
50
52
  ### [Testmail.app](https://testmail.app/)
53
+
51
54
  Recommended for production/GCP. It provides infinite private email addresses and a powerful GraphQL API.
52
- - **Environment Variables**: `TESTMAIL_API_KEY`, `TESTMAIL_NAMESPACE`, `MAILBOX_DOMAIN` (optional, defaults to `inbox.testmail.app`).
55
+
56
+ - **Environment Variables**: `LETSRUNIT_TESTMAIL_API_KEY`, `LETSRUNIT_TESTMAIL_NAMESPACE`, `LETSRUNIT_MAILBOX_DOMAIN` (optional, defaults to `inbox.testmail.app`).
53
57
 
54
58
  ### [Mailhog](https://github.com/mailhog/MailHog)
59
+
55
60
  Supported for legacy environments.
56
- - **Environment Variables**: `MAILHOG_BASE_URL` (defaults to `http://localhost:8025`).
61
+
62
+ - **Environment Variables**: `LETSRUNIT_MAILHOG_BASE_URL` (defaults to `http://localhost:8025`).
57
63
 
58
64
  ## Testing
59
65
 
package/dist/index.js CHANGED
@@ -6,13 +6,13 @@ import { GraphQLClient } from 'graphql-request';
6
6
  // src/constants.ts
7
7
  var testValue = (value) => process.env.NODE_ENV === "test" ? value : null;
8
8
  var TESTMAIL_DOMAIN = "inbox.testmail.app";
9
- var TESTMAIL_API_KEY = process.env.TESTMAIL_API_KEY || testValue("test_key");
10
- var TESTMAIL_NAMESPACE = process.env.TESTMAIL_NAMESPACE || testValue("test_ns");
9
+ var TESTMAIL_API_KEY = process.env.LETSRUNIT_TESTMAIL_API_KEY || testValue("test_key");
10
+ var TESTMAIL_NAMESPACE = process.env.LETSRUNIT_TESTMAIL_NAMESPACE || testValue("test_ns");
11
11
  var TESTMAIL_GRAPHQL_URL = "https://api.testmail.app/api/graphql";
12
- var MAILHOG_BASE_URL = process.env.MAILHOG_BASE_URL || "http://localhost:8025";
13
- var MAILPIT_BASE_URL = process.env.MAILPIT_BASE_URL || "http://localhost:8025";
14
- var MAILBOX_SERVICE = process.env.MAILBOX_SERVICE || "mailpit";
15
- var MAILBOX_DOMAIN = process.env.MAILBOX_DOMAIN || (MAILBOX_SERVICE === "testmail" ? TESTMAIL_DOMAIN : "example.com");
12
+ var MAILHOG_BASE_URL = process.env.LETSRUNIT_MAILHOG_BASE_URL || "http://localhost:8025";
13
+ var MAILPIT_BASE_URL = process.env.LETSRUNIT_MAILPIT_BASE_URL || "http://localhost:8025";
14
+ var MAILBOX_SERVICE = process.env.LETSRUNIT_MAILBOX_SERVICE || "mailpit";
15
+ var MAILBOX_DOMAIN = process.env.LETSRUNIT_MAILBOX_DOMAIN || (MAILBOX_SERVICE === "testmail" ? TESTMAIL_DOMAIN : "example.com");
16
16
 
17
17
  // src/mailbox.ts
18
18
  function getMailbox(seed, name, domain) {
@@ -183,7 +183,7 @@ async function receiveMail2(emailAddress, options = {}) {
183
183
  return [];
184
184
  }
185
185
  async function receiveMail3(emailAddress, options = {}) {
186
- if (!TESTMAIL_API_KEY) throw new Error("TESTMAIL_API_KEY environment var not set");
186
+ if (!TESTMAIL_API_KEY) throw new Error("LETSRUNIT_TESTMAIL_API_KEY environment var not set");
187
187
  const match = emailAddress.match(/^(?<namespace>[^.@]+)\.(?<tag>[^@]+)@/);
188
188
  if (!match) throw new Error("Email address is not a valid testmail address");
189
189
  const namespace = match.groups.namespace;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/mailbox.ts","../src/mailhog/receive.ts","../src/mailpit/receive.ts","../src/testmail/receive.ts","../src/receive.ts","../src/serialize.ts"],"names":["receiveMail","sleep","clean","unfolded","ct"],"mappings":"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","file":"index.js","sourcesContent":["const testValue = (value: string) => process.env.NODE_ENV === 'test' ? value : null;\n\nexport const TESTMAIL_DOMAIN = 'inbox.testmail.app';\nexport const TESTMAIL_API_KEY = process.env.TESTMAIL_API_KEY || testValue('test_key');\nexport const TESTMAIL_NAMESPACE = process.env.TESTMAIL_NAMESPACE || testValue('test_ns');\nexport const TESTMAIL_GRAPHQL_URL = 'https://api.testmail.app/api/graphql';\n\nexport const MAILHOG_BASE_URL = process.env.MAILHOG_BASE_URL || 'http://localhost:8025';\n\nexport const MAILPIT_BASE_URL = process.env.MAILPIT_BASE_URL || 'http://localhost:8025';\n\nexport const MAILBOX_SERVICE = process.env.MAILBOX_SERVICE || 'mailpit';\nexport const MAILBOX_DOMAIN = process.env.MAILBOX_DOMAIN\n || (MAILBOX_SERVICE === 'testmail' ? TESTMAIL_DOMAIN : 'example.com');\n","import type { UUID } from '@letsrunit/utils';\nimport { clean, uuidToTag } from '@letsrunit/utils';\nimport { MAILBOX_DOMAIN, TESTMAIL_DOMAIN, TESTMAIL_NAMESPACE } from './constants';\n\nexport function getMailbox(seed: UUID, name?: string, domain?: string) {\n domain ??= MAILBOX_DOMAIN;\n\n const ns = domain === TESTMAIL_DOMAIN ? TESTMAIL_NAMESPACE : null;\n const local = clean([ns, uuidToTag(seed), name]).join('.');\n\n return `${local}@${domain}`;\n}\n","import { sleep } from '@letsrunit/utils';\nimport { MAILHOG_BASE_URL } from '../constants';\nimport type { Email, ReceiveOptions } from '../types';\n\nasync function fetchOnce(emailAddress: string, signal: AbortSignal): Promise<any[]> {\n const url = `${MAILHOG_BASE_URL.replace(/\\/$/, '')}/api/v2/search?kind=to&query=${encodeURIComponent(emailAddress)}`;\n const res = await fetch(url, { signal });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Failed to fetch response from mailhog: ${res.status} ${text}`);\n }\n const body = await res.json();\n return body?.items ?? body?.Items ?? [];\n}\n\nfunction getHeaderValue(headers: Record<string, string[] | string> | undefined, name: string): string | undefined {\n if (!headers) return undefined;\n const v = headers[name] ?? headers[name.toLowerCase() as keyof typeof headers];\n if (!v) return undefined;\n return Array.isArray(v) ? v[0] : v;\n}\n\nfunction mapItemsToEmails(items: any[]): Email[] {\n return items.map((item) => {\n // timestamp\n const created = item.Created || item.created || item.Time;\n const timestamp = typeof created === 'number' ? created : Date.parse(created);\n\n // headers\n const headers: Record<string, string[] | string> | undefined = item.Content?.Headers || item.Content?.headers;\n\n // bodies from parts\n const parts: any[] = item.MIME?.Parts || item.MIME?.parts || [];\n const htmlPart = parts.find((p) => (p.ContentType || p.contentType || '').startsWith('text/html'));\n const textPart = parts.find((p) => (p.ContentType || p.contentType || '').startsWith('text/plain'));\n\n const html = htmlPart?.Body || htmlPart?.body || undefined;\n const text = (textPart?.Body || textPart?.body || item.Content?.Body || item.Content?.body || '').toString();\n\n // basic fields\n const subject = getHeaderValue(headers, 'Subject') || '';\n const from = getHeaderValue(headers, 'From') || '';\n const to = getHeaderValue(headers, 'To') || '';\n const cc = getHeaderValue(headers, 'Cc') || undefined;\n\n // attachments\n const attachments = parts\n .filter((p) => {\n const ct = (p.ContentType || p.contentType || '').toString();\n const filename = p.FileName || p.Filename || p.filename;\n if (filename) return true;\n return ct && !ct.startsWith('text/');\n })\n .map((p) => ({\n filename: p.FileName || p.Filename || p.filename || 'attachment',\n contentType: p.ContentType || p.contentType || 'application/octet-stream',\n }));\n\n const email: Email = {\n timestamp,\n from,\n to,\n cc,\n subject,\n html,\n text,\n attachments: attachments.length ? attachments : undefined,\n };\n\n return email;\n });\n}\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n const deadline = Date.now() + (options.timeout || (options.wait ? 120_000 : 5_000));\n const pollInterval = 1_000;\n const signal: AbortSignal = options.signal ?? AbortSignal.timeout(Math.max(0, deadline - Date.now()));\n\n while (!signal.aborted) {\n try {\n const items = await fetchOnce(emailAddress, signal);\n let emails = mapItemsToEmails(items);\n\n if (options.after) emails = emails.filter((e) => e.timestamp > options.after!);\n if (options.subject) emails = emails.filter((e) => e.subject.includes(options.subject!));\n if (options.limit && options.limit > 0) emails = emails.slice(0, options.limit);\n\n if (emails.length > 0) {\n return emails;\n }\n } catch (e) {\n // bubble up fetch errors except when aborted due to signal; then just end loop\n if (!signal.aborted) throw e;\n }\n\n if (!options.wait) break;\n await sleep(pollInterval, { signal });\n }\n\n return [];\n}\n","import { sleep } from '@letsrunit/utils';\nimport { MAILPIT_BASE_URL } from '../constants';\nimport type { Email, ReceiveOptions } from '../types';\n\nfunction buildSearchQuery(emailAddress: string, options: ReceiveOptions): string {\n const terms: string[] = [`to:${emailAddress}`];\n if (options.subject) {\n const escaped = options.subject.replace(/\"/g, '\\\\\"');\n terms.push(`subject:\"${escaped}\"`);\n }\n if (options.after) {\n const iso = new Date(options.after).toISOString();\n terms.push(`after:${iso}`);\n }\n return terms.join(' ');\n}\n\nasync function search(emailAddress: string, options: ReceiveOptions, signal: AbortSignal): Promise<any[]> {\n const base = MAILPIT_BASE_URL.replace(/\\/$/, '');\n const query = buildSearchQuery(emailAddress, options);\n const limitParam = options.limit && options.limit > 0 ? `&limit=${encodeURIComponent(String(options.limit))}` : '';\n const url = `${base}/api/v1/search?query=${encodeURIComponent(query)}${limitParam}`;\n const res = await fetch(url, { signal });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Failed to fetch response from mailpit: ${res.status} ${text}`);\n }\n const body = await res.json();\n return body?.messages ?? [];\n}\n\nasync function fetchFullMessage(\n id: string,\n signal: AbortSignal,\n): Promise<{\n Html?: string;\n Text?: string;\n Attachments?: any[];\n Created?: string | number;\n Subject?: string;\n From?: any;\n To?: any[];\n Cc?: any[];\n} | null> {\n const base = MAILPIT_BASE_URL.replace(/\\/$/, '');\n const url = `${base}/api/v1/message/${encodeURIComponent(id)}`;\n const res = await fetch(url, { signal });\n if (!res.ok) return null;\n try {\n return await res.json();\n } catch {\n return null;\n }\n}\n\nfunction pickAddress(obj: any): string {\n if (!obj) return '';\n if (typeof obj === 'string') return obj;\n const name = obj.Name;\n const addr = obj.Address || '';\n return name ? `${name} <${addr}>` : addr;\n}\n\nfunction joinAddresses(list?: any[]): string {\n if (!Array.isArray(list) || list.length === 0) return '';\n return list.map(pickAddress).filter(Boolean).join(', ');\n}\n\nfunction mapMessageToEmail(m: any): Email {\n const attachments = Array.isArray(m.Attachments)\n ? m.Attachments.map((a: any) => ({\n filename: a.FileName,\n contentType: a.ContentType,\n }))\n : undefined;\n\n return {\n timestamp: Date.parse(m.Created ?? m.Date),\n from: pickAddress(m.From),\n to: joinAddresses(m.To),\n cc: m.Cc && joinAddresses(m.Cc),\n subject: m.Subject,\n html: m.HTML,\n text: m.Text,\n attachments,\n };\n}\n\nasync function fetchFullEmails(messages: any[], signal: AbortSignal): Promise<Email[]> {\n const ids: string[] = messages.map((m: any) => m.ID).filter(Boolean);\n const details = await Promise.all(ids.map((id) => fetchFullMessage(id, signal)));\n return details.filter(Boolean).map((d) => mapMessageToEmail(d));\n}\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n const pollInterval = 1_000;\n const timeout = options.timeout || (options.wait ? 60_000 : 5_000);\n const signal: AbortSignal = options.signal ?? AbortSignal.timeout(timeout);\n\n while (!signal.aborted) {\n try {\n const messages = await search(emailAddress, options, signal);\n const emails = options.full\n ? await fetchFullEmails(messages, signal)\n : messages.map((m) => mapMessageToEmail(m));\n\n if (emails.length > 0) {\n return emails;\n }\n } catch (e) {\n if (!signal.aborted) throw e;\n }\n\n if (!options.wait) break;\n await sleep(pollInterval, { signal });\n }\n\n return [];\n}\n","import { clean } from '@letsrunit/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { TESTMAIL_API_KEY, TESTMAIL_GRAPHQL_URL } from '../constants';\nimport type { Email, ReceiveOptions } from '../types';\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n if (!TESTMAIL_API_KEY) throw new Error('TESTMAIL_API_KEY environment var not set');\n\n const match = emailAddress.match(/^(?<namespace>[^.@]+)\\.(?<tag>[^@]+)@/);\n if (!match) throw new Error('Email address is not a valid testmail address');\n\n const namespace = match.groups!.namespace;\n const tag = match.groups!.tag;\n\n const signal = options.signal ?? AbortSignal.timeout(options.timeout || (options.wait ? 120_000 : 5000));\n\n const client = new GraphQLClient(TESTMAIL_GRAPHQL_URL, {\n headers: { apikey: TESTMAIL_API_KEY },\n fetch: (input, init = {}) => {\n return fetch(input as RequestInfo, { ...init, signal });\n },\n });\n\n const fields = ['timestamp', 'from', 'to', 'cc', 'subject'];\n if (options.full) fields.push('html', 'text', 'attachments { filename contentType }');\n\n const query = `\n query Inbox($namespace: String!, $tag: String!, $timestampFrom: Long, $subject: String, $limit: Int) {\n inbox(\n namespace: $namespace\n tag: $tag\n ${options.wait ? 'livequery: true' : ''}\n ${options.after ? 'timestamp_from: $timestampFrom' : ''}\n ${options.subject ? `advanced_filters: [{ field: subject, match: exact, action: include, value: $subject }]` : ''}\n ${options.limit ? 'limit: $limit' : ''}\n advanced_sorts: [{ field: timestamp, order: desc }]\n ) {\n emails {\n ${fields.join('\\n ')}\n }\n }\n }\n `;\n\n const variables: Record<string, any> = clean({\n namespace,\n tag,\n timestampFrom: options.after,\n subject: options.subject,\n limit: options.limit,\n });\n\n try {\n const data: any = await client.request(query, variables);\n return data?.inbox?.emails || [];\n } catch (err: any) {\n const message = err?.response?.errors?.[0]?.message || err?.message || 'Unknown error';\n throw new Error(`Failed to fetch response from testmail: ${message}`);\n }\n}\n","import { MAILBOX_SERVICE } from './constants';\nimport { receiveMail as mailhogReceive } from './mailhog/receive';\nimport { receiveMail as mailpitReceive } from './mailpit/receive';\nimport { receiveMail as testmailReceive } from './testmail/receive';\nimport type { Email, ReceiveOptions } from './types';\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n switch (MAILBOX_SERVICE) {\n case 'testmail':\n return await testmailReceive(emailAddress, options);\n case 'mailhog':\n return await mailhogReceive(emailAddress, options);\n case 'mailpit':\n return await mailpitReceive(emailAddress, options);\n default:\n throw new Error(`Unsupported mailbox service ${MAILBOX_SERVICE}`);\n }\n}\n","import type { Email } from './types';\n\nexport function toEml(email: Email): string {\n const lines: string[] = [];\n const crlf = (s: string) => s.replace(/\\n/g, '\\r\\n');\n\n const date = new Date(email.timestamp);\n // Use RFC 2822 format via toUTCString\n lines.push(`Date: ${date.toUTCString()}`);\n lines.push(`From: ${email.from}`);\n lines.push(`To: ${email.to}`);\n if (email.cc) lines.push(`Cc: ${email.cc}`);\n lines.push(`Subject: ${email.subject}`);\n lines.push('MIME-Version: 1.0');\n\n const hasText = typeof email.text === 'string' && email.text.length > 0;\n const hasHtml = typeof email.html === 'string' && email.html.length > 0;\n const hasAttachments = Array.isArray(email.attachments) && email.attachments.length > 0;\n\n const boundary = `===============lr_${Math.random().toString(36).slice(2)}_${Date.now()}==`;\n const altBoundary = `===============lr_alt_${Math.random().toString(36).slice(2)}_${Date.now()}==`;\n\n function pushTextPart() {\n lines.push(`Content-Type: text/plain; charset=utf-8`);\n lines.push('Content-Transfer-Encoding: 7bit');\n lines.push('');\n lines.push(crlf(hasText ? email.text! : ''));\n }\n\n function pushHtmlPart() {\n lines.push(`Content-Type: text/html; charset=utf-8`);\n lines.push('Content-Transfer-Encoding: 7bit');\n lines.push('');\n lines.push(crlf(hasHtml ? email.html! : ''));\n }\n\n // Build structure\n if (hasAttachments) {\n // multipart/mixed enclosing either single/alternative plus attachments\n lines.push(`Content-Type: multipart/mixed; boundary=\"${boundary}\"`);\n lines.push('');\n lines.push(`--${boundary}`);\n if (hasText && hasHtml) {\n // nested multipart/alternative\n lines.push(`Content-Type: multipart/alternative; boundary=\"${altBoundary}\"`);\n lines.push('');\n // text part\n lines.push(`--${altBoundary}`);\n pushTextPart();\n // html part\n lines.push(`--${altBoundary}`);\n pushHtmlPart();\n // end alternative\n lines.push(`--${altBoundary}--`);\n } else if (hasText) {\n pushTextPart();\n } else {\n pushHtmlPart();\n }\n\n // attachments (metadata only; empty bodies)\n for (const a of email.attachments || []) {\n lines.push(`--${boundary}`);\n const disp = `attachment; filename=\"${a.filename}\"`;\n lines.push(`Content-Type: ${a.contentType}; name=\"${a.filename}\"`);\n lines.push(`Content-Disposition: ${disp}`);\n lines.push('Content-Transfer-Encoding: base64');\n lines.push('');\n // No content stored in type, emit empty body to keep structure valid\n lines.push('');\n }\n lines.push(`--${boundary}--`);\n } else if (hasText && hasHtml) {\n // multipart/alternative\n lines.push(`Content-Type: multipart/alternative; boundary=\"${altBoundary}\"`);\n lines.push('');\n lines.push(`--${altBoundary}`);\n pushTextPart();\n lines.push(`--${altBoundary}`);\n pushHtmlPart();\n lines.push(`--${altBoundary}--`);\n } else if (hasText) {\n pushTextPart();\n } else {\n pushHtmlPart();\n }\n\n // Ensure CRLF endings\n return lines.join('\\r\\n');\n}\n\nexport function fromEml(contents: string): Email {\n // Normalize line endings to \\n for parsing\n const raw = contents.replace(/\\r\\n/g, '\\n');\n const [rawHeader, ...rest] = raw.split(/\\n\\n/);\n const headerLines = rawHeader.split('\\n');\n // Handle folded headers (lines starting with space or tab)\n const unfolded: string[] = [];\n for (const line of headerLines) {\n if (/^[ \\t]/.test(line) && unfolded.length > 0) {\n unfolded[unfolded.length - 1] += line.replace(/^\\s+/, ' ');\n } else {\n unfolded.push(line);\n }\n }\n const headers = new Map<string, string>();\n for (const l of unfolded) {\n const idx = l.indexOf(':');\n if (idx === -1) continue;\n const key = l.slice(0, idx).trim().toLowerCase();\n const val = l.slice(idx + 1).trim();\n headers.set(key, val);\n }\n const body = rest.join('\\n\\n');\n\n const email: Email = {\n timestamp: Date.parse(headers.get('date') || new Date().toUTCString()),\n from: headers.get('from') || '',\n to: headers.get('to') || '',\n cc: headers.get('cc') || undefined,\n subject: headers.get('subject') || '',\n } as Email;\n\n // Parse body depending on content-type\n const ct = (headers.get('content-type') || '').toLowerCase();\n\n function parseParts(contentType: string, data: string): { text?: string; html?: string; attachments?: { filename: string; contentType: string }[] } {\n const result: { text?: string; html?: string; attachments?: { filename: string; contentType: string }[] } = { attachments: [] };\n if (contentType.startsWith('multipart/')) {\n const m = contentType.match(/boundary=\"?([^\";]+)\"?/);\n const boundary = m ? m[1] : '';\n if (!boundary) return result;\n // Line-oriented multipart parsing\n const lines = data.split('\\n');\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n if (line === `--${boundary}`) {\n // Parse headers\n i++;\n const pHeaders = new Map<string, string>();\n const headAccum: string[] = [];\n for (; i < lines.length; i++) {\n const l = lines[i];\n if (l === '') break;\n headAccum.push(l);\n }\n // skip empty line\n if (i < lines.length && lines[i] === '') i++;\n // unfold and map headers\n const unfolded: string[] = [];\n for (const h of headAccum) {\n if ((h.startsWith(' ') || h.startsWith('\\t')) && unfolded.length) {\n unfolded[unfolded.length - 1] += h.replace(/^\\s+/, ' ');\n } else {\n unfolded.push(h);\n }\n }\n for (const h of unfolded) {\n const idx = h.indexOf(':');\n if (idx !== -1) pHeaders.set(h.slice(0, idx).trim().toLowerCase(), h.slice(idx + 1).trim());\n }\n // Collect body until next boundary marker\n const bodyLines: string[] = [];\n for (; i < lines.length; i++) {\n const l = lines[i];\n if (l === `--${boundary}` || l === `--${boundary}--`) break;\n bodyLines.push(l);\n }\n const pBody = bodyLines.join('\\n');\n\n const pct = (pHeaders.get('content-type') || '').toLowerCase();\n const disp = (pHeaders.get('content-disposition') || '').toLowerCase();\n if (pct.startsWith('multipart/')) {\n const nested = parseParts(pct, pBody);\n if (nested.text && !result.text) result.text = nested.text;\n if (nested.html && !result.html) result.html = nested.html;\n if (nested.attachments && nested.attachments.length) result.attachments!.push(...nested.attachments);\n } else if (pct.startsWith('text/plain')) {\n result.text = pBody;\n } else if (pct.startsWith('text/html')) {\n result.html = pBody;\n } else if (disp.startsWith('attachment') || disp.includes('filename=')) {\n let filename = '';\n const fnm = disp.match(/filename=\"?([^\";]+)\"?/);\n if (fnm) filename = fnm[1];\n if (!filename) {\n const nm = pct.match(/name=\"?([^\";]+)\"?/);\n if (nm) filename = nm[1];\n }\n const contentTypeHeader = pHeaders.get('content-type') || 'application/octet-stream';\n result.attachments!.push({ filename, contentType: contentTypeHeader.split(';')[0] });\n }\n\n // If current line is closing boundary, advance past it and stop\n if (i < lines.length && lines[i] === `--${boundary}--`) {\n break;\n }\n // continue to next line (which is next boundary or end)\n } else if (line === `--${boundary}--`) {\n break;\n } else {\n i++;\n }\n }\n // Fallback pass: ensure we didn't miss any attachment headers\n const segs = (`\\n${data}`).split(`\\n--${boundary}`);\n const have = new Set(result.attachments!.map((a) => `${a.filename}|${a.contentType}`));\n for (let seg of segs) {\n seg = seg.replace(/^\\n/, '');\n if (!seg || seg.startsWith('--')) continue;\n const [head] = seg.split(/\\n\\n/);\n const disp = (head.match(/(^|\\n)content-disposition:\\s*([^\\n]+)/i)?.[2] || '').toLowerCase();\n if (!disp.includes('attachment')) continue;\n let filename = '';\n const fnm = disp.match(/filename=\"?([^\";]+)\"?/);\n if (fnm) filename = fnm[1];\n const ct = (head.match(/(^|\\n)content-type:\\s*([^\\n]+)/i)?.[2] || 'application/octet-stream').split(';')[0];\n const key = `${filename}|${ct}`;\n if (!have.has(key)) {\n have.add(key);\n result.attachments!.push({ filename, contentType: ct });\n }\n }\n // Order attachments by first appearance in the original data\n if (result.attachments && result.attachments.length > 1) {\n const positions = new Map<string, number>();\n for (const a of result.attachments) {\n const key = `${a.filename}|${a.contentType}`;\n if (!positions.has(key)) {\n const re = new RegExp(`filename=\\\"?${a.filename.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\"?`, 'i');\n const idx = data.search(re);\n positions.set(key, idx === -1 ? Number.MAX_SAFE_INTEGER : idx);\n }\n }\n result.attachments.sort((a, b) => {\n const ka = `${a.filename}|${a.contentType}`;\n const kb = `${b.filename}|${b.contentType}`;\n return (positions.get(ka) ?? 0) - (positions.get(kb) ?? 0);\n });\n }\n return result;\n }\n // single part\n if (contentType.startsWith('text/plain')) {\n result.text = data;\n } else if (contentType.startsWith('text/html')) {\n result.html = data;\n }\n return result;\n }\n\n const parsed = parseParts(ct, body);\n if (parsed.text !== undefined) email.text = parsed.text;\n if (parsed.html !== undefined) email.html = parsed.html;\n if (parsed.attachments && parsed.attachments.length) email.attachments = parsed.attachments;\n\n return email;\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/mailbox.ts","../src/mailhog/receive.ts","../src/mailpit/receive.ts","../src/testmail/receive.ts","../src/receive.ts","../src/serialize.ts"],"names":["receiveMail","sleep","clean","unfolded","ct"],"mappings":"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","file":"index.js","sourcesContent":["const testValue = (value: string) => (process.env.NODE_ENV === 'test' ? value : null);\n\nexport const TESTMAIL_DOMAIN = 'inbox.testmail.app';\nexport const TESTMAIL_API_KEY = process.env.LETSRUNIT_TESTMAIL_API_KEY || testValue('test_key');\nexport const TESTMAIL_NAMESPACE = process.env.LETSRUNIT_TESTMAIL_NAMESPACE || testValue('test_ns');\nexport const TESTMAIL_GRAPHQL_URL = 'https://api.testmail.app/api/graphql';\n\nexport const MAILHOG_BASE_URL = process.env.LETSRUNIT_MAILHOG_BASE_URL || 'http://localhost:8025';\n\nexport const MAILPIT_BASE_URL = process.env.LETSRUNIT_MAILPIT_BASE_URL || 'http://localhost:8025';\n\nexport const MAILBOX_SERVICE = process.env.LETSRUNIT_MAILBOX_SERVICE || 'mailpit';\nexport const MAILBOX_DOMAIN =\n process.env.LETSRUNIT_MAILBOX_DOMAIN || (MAILBOX_SERVICE === 'testmail' ? TESTMAIL_DOMAIN : 'example.com');\n","import type { UUID } from '@letsrunit/utils';\nimport { clean, uuidToTag } from '@letsrunit/utils';\nimport { MAILBOX_DOMAIN, TESTMAIL_DOMAIN, TESTMAIL_NAMESPACE } from './constants';\n\nexport function getMailbox(seed: UUID, name?: string, domain?: string) {\n domain ??= MAILBOX_DOMAIN;\n\n const ns = domain === TESTMAIL_DOMAIN ? TESTMAIL_NAMESPACE : null;\n const local = clean([ns, uuidToTag(seed), name]).join('.');\n\n return `${local}@${domain}`;\n}\n","import { sleep } from '@letsrunit/utils';\nimport { MAILHOG_BASE_URL } from '../constants';\nimport type { Email, ReceiveOptions } from '../types';\n\nasync function fetchOnce(emailAddress: string, signal: AbortSignal): Promise<any[]> {\n const url = `${MAILHOG_BASE_URL.replace(/\\/$/, '')}/api/v2/search?kind=to&query=${encodeURIComponent(emailAddress)}`;\n const res = await fetch(url, { signal });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Failed to fetch response from mailhog: ${res.status} ${text}`);\n }\n const body = await res.json();\n return body?.items ?? body?.Items ?? [];\n}\n\nfunction getHeaderValue(headers: Record<string, string[] | string> | undefined, name: string): string | undefined {\n if (!headers) return undefined;\n const v = headers[name] ?? headers[name.toLowerCase() as keyof typeof headers];\n if (!v) return undefined;\n return Array.isArray(v) ? v[0] : v;\n}\n\nfunction mapItemsToEmails(items: any[]): Email[] {\n return items.map((item) => {\n // timestamp\n const created = item.Created || item.created || item.Time;\n const timestamp = typeof created === 'number' ? created : Date.parse(created);\n\n // headers\n const headers: Record<string, string[] | string> | undefined = item.Content?.Headers || item.Content?.headers;\n\n // bodies from parts\n const parts: any[] = item.MIME?.Parts || item.MIME?.parts || [];\n const htmlPart = parts.find((p) => (p.ContentType || p.contentType || '').startsWith('text/html'));\n const textPart = parts.find((p) => (p.ContentType || p.contentType || '').startsWith('text/plain'));\n\n const html = htmlPart?.Body || htmlPart?.body || undefined;\n const text = (textPart?.Body || textPart?.body || item.Content?.Body || item.Content?.body || '').toString();\n\n // basic fields\n const subject = getHeaderValue(headers, 'Subject') || '';\n const from = getHeaderValue(headers, 'From') || '';\n const to = getHeaderValue(headers, 'To') || '';\n const cc = getHeaderValue(headers, 'Cc') || undefined;\n\n // attachments\n const attachments = parts\n .filter((p) => {\n const ct = (p.ContentType || p.contentType || '').toString();\n const filename = p.FileName || p.Filename || p.filename;\n if (filename) return true;\n return ct && !ct.startsWith('text/');\n })\n .map((p) => ({\n filename: p.FileName || p.Filename || p.filename || 'attachment',\n contentType: p.ContentType || p.contentType || 'application/octet-stream',\n }));\n\n const email: Email = {\n timestamp,\n from,\n to,\n cc,\n subject,\n html,\n text,\n attachments: attachments.length ? attachments : undefined,\n };\n\n return email;\n });\n}\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n const deadline = Date.now() + (options.timeout || (options.wait ? 120_000 : 5_000));\n const pollInterval = 1_000;\n const signal: AbortSignal = options.signal ?? AbortSignal.timeout(Math.max(0, deadline - Date.now()));\n\n while (!signal.aborted) {\n try {\n const items = await fetchOnce(emailAddress, signal);\n let emails = mapItemsToEmails(items);\n\n if (options.after) emails = emails.filter((e) => e.timestamp > options.after!);\n if (options.subject) emails = emails.filter((e) => e.subject.includes(options.subject!));\n if (options.limit && options.limit > 0) emails = emails.slice(0, options.limit);\n\n if (emails.length > 0) {\n return emails;\n }\n } catch (e) {\n // bubble up fetch errors except when aborted due to signal; then just end loop\n if (!signal.aborted) throw e;\n }\n\n if (!options.wait) break;\n await sleep(pollInterval, { signal });\n }\n\n return [];\n}\n","import { sleep } from '@letsrunit/utils';\nimport { MAILPIT_BASE_URL } from '../constants';\nimport type { Email, ReceiveOptions } from '../types';\n\nfunction buildSearchQuery(emailAddress: string, options: ReceiveOptions): string {\n const terms: string[] = [`to:${emailAddress}`];\n if (options.subject) {\n const escaped = options.subject.replace(/\"/g, '\\\\\"');\n terms.push(`subject:\"${escaped}\"`);\n }\n if (options.after) {\n const iso = new Date(options.after).toISOString();\n terms.push(`after:${iso}`);\n }\n return terms.join(' ');\n}\n\nasync function search(emailAddress: string, options: ReceiveOptions, signal: AbortSignal): Promise<any[]> {\n const base = MAILPIT_BASE_URL.replace(/\\/$/, '');\n const query = buildSearchQuery(emailAddress, options);\n const limitParam = options.limit && options.limit > 0 ? `&limit=${encodeURIComponent(String(options.limit))}` : '';\n const url = `${base}/api/v1/search?query=${encodeURIComponent(query)}${limitParam}`;\n const res = await fetch(url, { signal });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Failed to fetch response from mailpit: ${res.status} ${text}`);\n }\n const body = await res.json();\n return body?.messages ?? [];\n}\n\nasync function fetchFullMessage(\n id: string,\n signal: AbortSignal,\n): Promise<{\n Html?: string;\n Text?: string;\n Attachments?: any[];\n Created?: string | number;\n Subject?: string;\n From?: any;\n To?: any[];\n Cc?: any[];\n} | null> {\n const base = MAILPIT_BASE_URL.replace(/\\/$/, '');\n const url = `${base}/api/v1/message/${encodeURIComponent(id)}`;\n const res = await fetch(url, { signal });\n if (!res.ok) return null;\n try {\n return await res.json();\n } catch {\n return null;\n }\n}\n\nfunction pickAddress(obj: any): string {\n if (!obj) return '';\n if (typeof obj === 'string') return obj;\n const name = obj.Name;\n const addr = obj.Address || '';\n return name ? `${name} <${addr}>` : addr;\n}\n\nfunction joinAddresses(list?: any[]): string {\n if (!Array.isArray(list) || list.length === 0) return '';\n return list.map(pickAddress).filter(Boolean).join(', ');\n}\n\nfunction mapMessageToEmail(m: any): Email {\n const attachments = Array.isArray(m.Attachments)\n ? m.Attachments.map((a: any) => ({\n filename: a.FileName,\n contentType: a.ContentType,\n }))\n : undefined;\n\n return {\n timestamp: Date.parse(m.Created ?? m.Date),\n from: pickAddress(m.From),\n to: joinAddresses(m.To),\n cc: m.Cc && joinAddresses(m.Cc),\n subject: m.Subject,\n html: m.HTML,\n text: m.Text,\n attachments,\n };\n}\n\nasync function fetchFullEmails(messages: any[], signal: AbortSignal): Promise<Email[]> {\n const ids: string[] = messages.map((m: any) => m.ID).filter(Boolean);\n const details = await Promise.all(ids.map((id) => fetchFullMessage(id, signal)));\n return details.filter(Boolean).map((d) => mapMessageToEmail(d));\n}\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n const pollInterval = 1_000;\n const timeout = options.timeout || (options.wait ? 60_000 : 5_000);\n const signal: AbortSignal = options.signal ?? AbortSignal.timeout(timeout);\n\n while (!signal.aborted) {\n try {\n const messages = await search(emailAddress, options, signal);\n const emails = options.full\n ? await fetchFullEmails(messages, signal)\n : messages.map((m) => mapMessageToEmail(m));\n\n if (emails.length > 0) {\n return emails;\n }\n } catch (e) {\n if (!signal.aborted) throw e;\n }\n\n if (!options.wait) break;\n await sleep(pollInterval, { signal });\n }\n\n return [];\n}\n","import { clean } from '@letsrunit/utils';\nimport { GraphQLClient } from 'graphql-request';\nimport { TESTMAIL_API_KEY, TESTMAIL_GRAPHQL_URL } from '../constants';\nimport type { Email, ReceiveOptions } from '../types';\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n if (!TESTMAIL_API_KEY) throw new Error('LETSRUNIT_TESTMAIL_API_KEY environment var not set');\n\n const match = emailAddress.match(/^(?<namespace>[^.@]+)\\.(?<tag>[^@]+)@/);\n if (!match) throw new Error('Email address is not a valid testmail address');\n\n const namespace = match.groups!.namespace;\n const tag = match.groups!.tag;\n\n const signal = options.signal ?? AbortSignal.timeout(options.timeout || (options.wait ? 120_000 : 5000));\n\n const client = new GraphQLClient(TESTMAIL_GRAPHQL_URL, {\n headers: { apikey: TESTMAIL_API_KEY },\n fetch: (input, init = {}) => {\n return fetch(input as RequestInfo, { ...init, signal });\n },\n });\n\n const fields = ['timestamp', 'from', 'to', 'cc', 'subject'];\n if (options.full) fields.push('html', 'text', 'attachments { filename contentType }');\n\n const query = `\n query Inbox($namespace: String!, $tag: String!, $timestampFrom: Long, $subject: String, $limit: Int) {\n inbox(\n namespace: $namespace\n tag: $tag\n ${options.wait ? 'livequery: true' : ''}\n ${options.after ? 'timestamp_from: $timestampFrom' : ''}\n ${options.subject ? `advanced_filters: [{ field: subject, match: exact, action: include, value: $subject }]` : ''}\n ${options.limit ? 'limit: $limit' : ''}\n advanced_sorts: [{ field: timestamp, order: desc }]\n ) {\n emails {\n ${fields.join('\\n ')}\n }\n }\n }\n `;\n\n const variables: Record<string, any> = clean({\n namespace,\n tag,\n timestampFrom: options.after,\n subject: options.subject,\n limit: options.limit,\n });\n\n try {\n const data: any = await client.request(query, variables);\n return data?.inbox?.emails || [];\n } catch (err: any) {\n const message = err?.response?.errors?.[0]?.message || err?.message || 'Unknown error';\n throw new Error(`Failed to fetch response from testmail: ${message}`);\n }\n}\n","import { MAILBOX_SERVICE } from './constants';\nimport { receiveMail as mailhogReceive } from './mailhog/receive';\nimport { receiveMail as mailpitReceive } from './mailpit/receive';\nimport { receiveMail as testmailReceive } from './testmail/receive';\nimport type { Email, ReceiveOptions } from './types';\n\nexport async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {\n switch (MAILBOX_SERVICE) {\n case 'testmail':\n return await testmailReceive(emailAddress, options);\n case 'mailhog':\n return await mailhogReceive(emailAddress, options);\n case 'mailpit':\n return await mailpitReceive(emailAddress, options);\n default:\n throw new Error(`Unsupported mailbox service ${MAILBOX_SERVICE}`);\n }\n}\n","import type { Email } from './types';\n\nexport function toEml(email: Email): string {\n const lines: string[] = [];\n const crlf = (s: string) => s.replace(/\\n/g, '\\r\\n');\n\n const date = new Date(email.timestamp);\n // Use RFC 2822 format via toUTCString\n lines.push(`Date: ${date.toUTCString()}`);\n lines.push(`From: ${email.from}`);\n lines.push(`To: ${email.to}`);\n if (email.cc) lines.push(`Cc: ${email.cc}`);\n lines.push(`Subject: ${email.subject}`);\n lines.push('MIME-Version: 1.0');\n\n const hasText = typeof email.text === 'string' && email.text.length > 0;\n const hasHtml = typeof email.html === 'string' && email.html.length > 0;\n const hasAttachments = Array.isArray(email.attachments) && email.attachments.length > 0;\n\n const boundary = `===============lr_${Math.random().toString(36).slice(2)}_${Date.now()}==`;\n const altBoundary = `===============lr_alt_${Math.random().toString(36).slice(2)}_${Date.now()}==`;\n\n function pushTextPart() {\n lines.push(`Content-Type: text/plain; charset=utf-8`);\n lines.push('Content-Transfer-Encoding: 7bit');\n lines.push('');\n lines.push(crlf(hasText ? email.text! : ''));\n }\n\n function pushHtmlPart() {\n lines.push(`Content-Type: text/html; charset=utf-8`);\n lines.push('Content-Transfer-Encoding: 7bit');\n lines.push('');\n lines.push(crlf(hasHtml ? email.html! : ''));\n }\n\n // Build structure\n if (hasAttachments) {\n // multipart/mixed enclosing either single/alternative plus attachments\n lines.push(`Content-Type: multipart/mixed; boundary=\"${boundary}\"`);\n lines.push('');\n lines.push(`--${boundary}`);\n if (hasText && hasHtml) {\n // nested multipart/alternative\n lines.push(`Content-Type: multipart/alternative; boundary=\"${altBoundary}\"`);\n lines.push('');\n // text part\n lines.push(`--${altBoundary}`);\n pushTextPart();\n // html part\n lines.push(`--${altBoundary}`);\n pushHtmlPart();\n // end alternative\n lines.push(`--${altBoundary}--`);\n } else if (hasText) {\n pushTextPart();\n } else {\n pushHtmlPart();\n }\n\n // attachments (metadata only; empty bodies)\n for (const a of email.attachments || []) {\n lines.push(`--${boundary}`);\n const disp = `attachment; filename=\"${a.filename}\"`;\n lines.push(`Content-Type: ${a.contentType}; name=\"${a.filename}\"`);\n lines.push(`Content-Disposition: ${disp}`);\n lines.push('Content-Transfer-Encoding: base64');\n lines.push('');\n // No content stored in type, emit empty body to keep structure valid\n lines.push('');\n }\n lines.push(`--${boundary}--`);\n } else if (hasText && hasHtml) {\n // multipart/alternative\n lines.push(`Content-Type: multipart/alternative; boundary=\"${altBoundary}\"`);\n lines.push('');\n lines.push(`--${altBoundary}`);\n pushTextPart();\n lines.push(`--${altBoundary}`);\n pushHtmlPart();\n lines.push(`--${altBoundary}--`);\n } else if (hasText) {\n pushTextPart();\n } else {\n pushHtmlPart();\n }\n\n // Ensure CRLF endings\n return lines.join('\\r\\n');\n}\n\nexport function fromEml(contents: string): Email {\n // Normalize line endings to \\n for parsing\n const raw = contents.replace(/\\r\\n/g, '\\n');\n const [rawHeader, ...rest] = raw.split(/\\n\\n/);\n const headerLines = rawHeader.split('\\n');\n // Handle folded headers (lines starting with space or tab)\n const unfolded: string[] = [];\n for (const line of headerLines) {\n if (/^[ \\t]/.test(line) && unfolded.length > 0) {\n unfolded[unfolded.length - 1] += line.replace(/^\\s+/, ' ');\n } else {\n unfolded.push(line);\n }\n }\n const headers = new Map<string, string>();\n for (const l of unfolded) {\n const idx = l.indexOf(':');\n if (idx === -1) continue;\n const key = l.slice(0, idx).trim().toLowerCase();\n const val = l.slice(idx + 1).trim();\n headers.set(key, val);\n }\n const body = rest.join('\\n\\n');\n\n const email: Email = {\n timestamp: Date.parse(headers.get('date') || new Date().toUTCString()),\n from: headers.get('from') || '',\n to: headers.get('to') || '',\n cc: headers.get('cc') || undefined,\n subject: headers.get('subject') || '',\n } as Email;\n\n // Parse body depending on content-type\n const ct = (headers.get('content-type') || '').toLowerCase();\n\n function parseParts(contentType: string, data: string): { text?: string; html?: string; attachments?: { filename: string; contentType: string }[] } {\n const result: { text?: string; html?: string; attachments?: { filename: string; contentType: string }[] } = { attachments: [] };\n if (contentType.startsWith('multipart/')) {\n const m = contentType.match(/boundary=\"?([^\";]+)\"?/);\n const boundary = m ? m[1] : '';\n if (!boundary) return result;\n // Line-oriented multipart parsing\n const lines = data.split('\\n');\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n if (line === `--${boundary}`) {\n // Parse headers\n i++;\n const pHeaders = new Map<string, string>();\n const headAccum: string[] = [];\n for (; i < lines.length; i++) {\n const l = lines[i];\n if (l === '') break;\n headAccum.push(l);\n }\n // skip empty line\n if (i < lines.length && lines[i] === '') i++;\n // unfold and map headers\n const unfolded: string[] = [];\n for (const h of headAccum) {\n if ((h.startsWith(' ') || h.startsWith('\\t')) && unfolded.length) {\n unfolded[unfolded.length - 1] += h.replace(/^\\s+/, ' ');\n } else {\n unfolded.push(h);\n }\n }\n for (const h of unfolded) {\n const idx = h.indexOf(':');\n if (idx !== -1) pHeaders.set(h.slice(0, idx).trim().toLowerCase(), h.slice(idx + 1).trim());\n }\n // Collect body until next boundary marker\n const bodyLines: string[] = [];\n for (; i < lines.length; i++) {\n const l = lines[i];\n if (l === `--${boundary}` || l === `--${boundary}--`) break;\n bodyLines.push(l);\n }\n const pBody = bodyLines.join('\\n');\n\n const pct = (pHeaders.get('content-type') || '').toLowerCase();\n const disp = (pHeaders.get('content-disposition') || '').toLowerCase();\n if (pct.startsWith('multipart/')) {\n const nested = parseParts(pct, pBody);\n if (nested.text && !result.text) result.text = nested.text;\n if (nested.html && !result.html) result.html = nested.html;\n if (nested.attachments && nested.attachments.length) result.attachments!.push(...nested.attachments);\n } else if (pct.startsWith('text/plain')) {\n result.text = pBody;\n } else if (pct.startsWith('text/html')) {\n result.html = pBody;\n } else if (disp.startsWith('attachment') || disp.includes('filename=')) {\n let filename = '';\n const fnm = disp.match(/filename=\"?([^\";]+)\"?/);\n if (fnm) filename = fnm[1];\n if (!filename) {\n const nm = pct.match(/name=\"?([^\";]+)\"?/);\n if (nm) filename = nm[1];\n }\n const contentTypeHeader = pHeaders.get('content-type') || 'application/octet-stream';\n result.attachments!.push({ filename, contentType: contentTypeHeader.split(';')[0] });\n }\n\n // If current line is closing boundary, advance past it and stop\n if (i < lines.length && lines[i] === `--${boundary}--`) {\n break;\n }\n // continue to next line (which is next boundary or end)\n } else if (line === `--${boundary}--`) {\n break;\n } else {\n i++;\n }\n }\n // Fallback pass: ensure we didn't miss any attachment headers\n const segs = (`\\n${data}`).split(`\\n--${boundary}`);\n const have = new Set(result.attachments!.map((a) => `${a.filename}|${a.contentType}`));\n for (let seg of segs) {\n seg = seg.replace(/^\\n/, '');\n if (!seg || seg.startsWith('--')) continue;\n const [head] = seg.split(/\\n\\n/);\n const disp = (head.match(/(^|\\n)content-disposition:\\s*([^\\n]+)/i)?.[2] || '').toLowerCase();\n if (!disp.includes('attachment')) continue;\n let filename = '';\n const fnm = disp.match(/filename=\"?([^\";]+)\"?/);\n if (fnm) filename = fnm[1];\n const ct = (head.match(/(^|\\n)content-type:\\s*([^\\n]+)/i)?.[2] || 'application/octet-stream').split(';')[0];\n const key = `${filename}|${ct}`;\n if (!have.has(key)) {\n have.add(key);\n result.attachments!.push({ filename, contentType: ct });\n }\n }\n // Order attachments by first appearance in the original data\n if (result.attachments && result.attachments.length > 1) {\n const positions = new Map<string, number>();\n for (const a of result.attachments) {\n const key = `${a.filename}|${a.contentType}`;\n if (!positions.has(key)) {\n const re = new RegExp(`filename=\\\"?${a.filename.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\"?`, 'i');\n const idx = data.search(re);\n positions.set(key, idx === -1 ? Number.MAX_SAFE_INTEGER : idx);\n }\n }\n result.attachments.sort((a, b) => {\n const ka = `${a.filename}|${a.contentType}`;\n const kb = `${b.filename}|${b.contentType}`;\n return (positions.get(ka) ?? 0) - (positions.get(kb) ?? 0);\n });\n }\n return result;\n }\n // single part\n if (contentType.startsWith('text/plain')) {\n result.text = data;\n } else if (contentType.startsWith('text/html')) {\n result.html = data;\n }\n return result;\n }\n\n const parsed = parseParts(ct, body);\n if (parsed.text !== undefined) email.text = parsed.text;\n if (parsed.html !== undefined) email.html = parsed.html;\n if (parsed.attachments && parsed.attachments.length) email.attachments = parsed.attachments;\n\n return email;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letsrunit/mailbox",
3
- "version": "0.21.1",
3
+ "version": "0.23.0",
4
4
  "description": "Test email mailbox integration for letsrunit",
5
5
  "keywords": [
6
6
  "testing",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "packageManager": "yarn@4.10.3",
44
44
  "dependencies": {
45
- "@letsrunit/utils": "0.21.1",
45
+ "@letsrunit/utils": "0.23.0",
46
46
  "graphql": "^16.12.0",
47
47
  "graphql-request": "^7.4.0"
48
48
  },
package/src/constants.ts CHANGED
@@ -1,14 +1,14 @@
1
- const testValue = (value: string) => process.env.NODE_ENV === 'test' ? value : null;
1
+ const testValue = (value: string) => (process.env.NODE_ENV === 'test' ? value : null);
2
2
 
3
3
  export const TESTMAIL_DOMAIN = 'inbox.testmail.app';
4
- export const TESTMAIL_API_KEY = process.env.TESTMAIL_API_KEY || testValue('test_key');
5
- export const TESTMAIL_NAMESPACE = process.env.TESTMAIL_NAMESPACE || testValue('test_ns');
4
+ export const TESTMAIL_API_KEY = process.env.LETSRUNIT_TESTMAIL_API_KEY || testValue('test_key');
5
+ export const TESTMAIL_NAMESPACE = process.env.LETSRUNIT_TESTMAIL_NAMESPACE || testValue('test_ns');
6
6
  export const TESTMAIL_GRAPHQL_URL = 'https://api.testmail.app/api/graphql';
7
7
 
8
- export const MAILHOG_BASE_URL = process.env.MAILHOG_BASE_URL || 'http://localhost:8025';
8
+ export const MAILHOG_BASE_URL = process.env.LETSRUNIT_MAILHOG_BASE_URL || 'http://localhost:8025';
9
9
 
10
- export const MAILPIT_BASE_URL = process.env.MAILPIT_BASE_URL || 'http://localhost:8025';
10
+ export const MAILPIT_BASE_URL = process.env.LETSRUNIT_MAILPIT_BASE_URL || 'http://localhost:8025';
11
11
 
12
- export const MAILBOX_SERVICE = process.env.MAILBOX_SERVICE || 'mailpit';
13
- export const MAILBOX_DOMAIN = process.env.MAILBOX_DOMAIN
14
- || (MAILBOX_SERVICE === 'testmail' ? TESTMAIL_DOMAIN : 'example.com');
12
+ export const MAILBOX_SERVICE = process.env.LETSRUNIT_MAILBOX_SERVICE || 'mailpit';
13
+ export const MAILBOX_DOMAIN =
14
+ process.env.LETSRUNIT_MAILBOX_DOMAIN || (MAILBOX_SERVICE === 'testmail' ? TESTMAIL_DOMAIN : 'example.com');
@@ -4,7 +4,7 @@ import { TESTMAIL_API_KEY, TESTMAIL_GRAPHQL_URL } from '../constants';
4
4
  import type { Email, ReceiveOptions } from '../types';
5
5
 
6
6
  export async function receiveMail(emailAddress: string, options: ReceiveOptions = {}): Promise<Email[]> {
7
- if (!TESTMAIL_API_KEY) throw new Error('TESTMAIL_API_KEY environment var not set');
7
+ if (!TESTMAIL_API_KEY) throw new Error('LETSRUNIT_TESTMAIL_API_KEY environment var not set');
8
8
 
9
9
  const match = emailAddress.match(/^(?<namespace>[^.@]+)\.(?<tag>[^@]+)@/);
10
10
  if (!match) throw new Error('Email address is not a valid testmail address');