| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- (function cloudflareTempEmailUtilsModule(root, factory) {
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = factory();
- return;
- }
- root.CloudflareTempEmailUtils = factory();
- })(typeof self !== 'undefined' ? self : globalThis, function createCloudflareTempEmailUtils() {
- const DEFAULT_MAIL_PAGE_SIZE = 20;
- function firstNonEmptyString(values) {
- for (const value of values) {
- if (value === undefined || value === null) continue;
- const normalized = String(value).trim();
- if (normalized) return normalized;
- }
- return '';
- }
- function normalizeCloudflareTempEmailBaseUrl(rawValue = '') {
- const value = String(rawValue || '').trim();
- if (!value) return '';
- const candidate = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(value) ? value : `https://${value}`;
- try {
- const parsed = new URL(candidate);
- parsed.hash = '';
- parsed.search = '';
- const pathname = parsed.pathname === '/' ? '' : parsed.pathname.replace(/\/+$/, '');
- return `${parsed.origin}${pathname}`;
- } catch {
- return '';
- }
- }
- function normalizeCloudflareTempEmailDomain(rawValue = '') {
- let value = String(rawValue || '').trim().toLowerCase();
- if (!value) return '';
- value = value.replace(/^@+/, '');
- value = value.replace(/^https?:\/\//, '');
- value = value.replace(/\/.*$/, '');
- if (!/^[a-z0-9.-]+\.[a-z]{2,}$/i.test(value)) {
- return '';
- }
- return value;
- }
- function normalizeCloudflareTempEmailDomains(values) {
- const domains = [];
- const seen = new Set();
- for (const value of Array.isArray(values) ? values : []) {
- const normalized = normalizeCloudflareTempEmailDomain(value);
- if (!normalized || seen.has(normalized)) continue;
- seen.add(normalized);
- domains.push(normalized);
- }
- return domains;
- }
- function buildCloudflareTempEmailHeaders(config = {}, options = {}) {
- const headers = {};
- const adminAuth = firstNonEmptyString([config.adminAuth, config.cloudflareTempEmailAdminAuth]);
- const customAuth = firstNonEmptyString([config.customAuth, config.cloudflareTempEmailCustomAuth]);
- if (adminAuth) {
- headers['x-admin-auth'] = adminAuth;
- }
- if (customAuth) {
- headers['x-custom-auth'] = customAuth;
- }
- if (options.json) {
- headers['Content-Type'] = 'application/json';
- }
- if (options.acceptJson !== false) {
- headers.Accept = 'application/json';
- }
- return headers;
- }
- function joinCloudflareTempEmailUrl(baseUrl, path) {
- const normalizedBase = normalizeCloudflareTempEmailBaseUrl(baseUrl);
- const normalizedPath = String(path || '').trim();
- if (!normalizedBase || !normalizedPath) return normalizedBase || '';
- return `${normalizedBase}${normalizedPath.startsWith('/') ? '' : '/'}${normalizedPath}`;
- }
- function getCloudflareTempEmailMailRows(payload) {
- if (Array.isArray(payload)) return payload;
- if (!payload || typeof payload !== 'object') return [];
- const candidates = [
- payload.data,
- payload.items,
- payload.messages,
- payload.mails,
- payload.results,
- payload.rows,
- ];
- for (const candidate of candidates) {
- if (Array.isArray(candidate)) {
- return candidate;
- }
- }
- return [];
- }
- function normalizeCloudflareTempEmailAddress(value) {
- return String(value || '').trim().toLowerCase();
- }
- function splitRawMessage(raw = '') {
- const source = String(raw || '');
- if (!source) {
- return { headerText: '', bodyText: '' };
- }
- const normalized = source.replace(/\r\n/g, '\n');
- const separatorIndex = normalized.indexOf('\n\n');
- if (separatorIndex === -1) {
- return { headerText: normalized, bodyText: '' };
- }
- return {
- headerText: normalized.slice(0, separatorIndex),
- bodyText: normalized.slice(separatorIndex + 2),
- };
- }
- function parseRawHeaders(headerText = '') {
- const headers = {};
- const lines = String(headerText || '').split('\n');
- let currentName = '';
- for (const line of lines) {
- if (!line) continue;
- if ((line.startsWith(' ') || line.startsWith('\t')) && currentName) {
- headers[currentName] += ` ${line.trim()}`;
- continue;
- }
- const separatorIndex = line.indexOf(':');
- if (separatorIndex <= 0) continue;
- currentName = line.slice(0, separatorIndex).trim().toLowerCase();
- headers[currentName] = line.slice(separatorIndex + 1).trim();
- }
- return headers;
- }
- function decodeMimeEncodedWords(value = '') {
- const source = String(value || '');
- return source.replace(/=\?([^?]+)\?([bBqQ])\?([^?]+)\?=/g, (_match, charset, encoding, encodedText) => {
- try {
- if (String(encoding).toUpperCase() === 'B') {
- return decodeBytesToString(base64ToBytes(encodedText), charset);
- }
- return decodeBytesToString(
- quotedPrintableToBytes(String(encodedText).replace(/_/g, ' '), { headerMode: true }),
- charset
- );
- } catch {
- return encodedText;
- }
- });
- }
- function base64ToBytes(value = '') {
- const normalized = String(value || '').replace(/\s+/g, '');
- if (!normalized) return new Uint8Array();
- if (typeof atob === 'function') {
- const decoded = atob(normalized);
- const bytes = new Uint8Array(decoded.length);
- for (let i = 0; i < decoded.length; i += 1) {
- bytes[i] = decoded.charCodeAt(i);
- }
- return bytes;
- }
- if (typeof Buffer !== 'undefined') {
- return Uint8Array.from(Buffer.from(normalized, 'base64'));
- }
- throw new Error('No base64 decoder available');
- }
- function quotedPrintableToBytes(value = '', options = {}) {
- const { headerMode = false } = options;
- const source = String(value || '')
- .replace(/=\r?\n/g, '')
- .replace(headerMode ? /_/g : /$^/, ' ');
- const bytes = [];
- for (let index = 0; index < source.length; index += 1) {
- const char = source[index];
- if (char === '=' && /^[0-9A-Fa-f]{2}$/.test(source.slice(index + 1, index + 3))) {
- bytes.push(parseInt(source.slice(index + 1, index + 3), 16));
- index += 2;
- continue;
- }
- bytes.push(char.charCodeAt(0));
- }
- return Uint8Array.from(bytes);
- }
- function decodeBytesToString(bytes, charset = 'utf-8') {
- const normalizedCharset = String(charset || 'utf-8').trim().toLowerCase();
- const candidates = [normalizedCharset];
- if (normalizedCharset === 'utf8') {
- candidates.unshift('utf-8');
- }
- if (normalizedCharset === 'gb2312' || normalizedCharset === 'gbk') {
- candidates.unshift('gb18030');
- }
- for (const candidate of candidates) {
- try {
- if (typeof TextDecoder !== 'undefined') {
- return new TextDecoder(candidate, { fatal: false }).decode(bytes);
- }
- } catch {
- // ignore and try fallback
- }
- }
- if (typeof Buffer !== 'undefined') {
- return Buffer.from(bytes).toString('utf8');
- }
- let result = '';
- for (const byte of bytes) {
- result += String.fromCharCode(byte);
- }
- return result;
- }
- function getCharsetFromContentType(contentType = '') {
- const match = String(contentType || '').match(/charset="?([^";]+)"?/i);
- return match ? match[1].trim() : 'utf-8';
- }
- function getBoundaryFromContentType(contentType = '') {
- const match = String(contentType || '').match(/boundary="?([^";]+)"?/i);
- return match ? match[1] : '';
- }
- function stripHtmlTags(value = '') {
- return String(value || '')
- .replace(/<style[\s\S]*?<\/style>/gi, ' ')
- .replace(/<script[\s\S]*?<\/script>/gi, ' ')
- .replace(/<[^>]+>/g, ' ')
- .replace(/ /gi, ' ')
- .replace(/&/gi, '&')
- .replace(/</gi, '<')
- .replace(/>/gi, '>')
- .replace(/\s+/g, ' ')
- .trim();
- }
- function decodeMimeBody(bodyText = '', headers = {}) {
- const contentType = String(headers['content-type'] || '');
- const transferEncoding = String(headers['content-transfer-encoding'] || '').trim().toLowerCase();
- const charset = getCharsetFromContentType(contentType);
- let decoded = String(bodyText || '');
- if (transferEncoding === 'base64') {
- decoded = decodeBytesToString(base64ToBytes(decoded), charset);
- } else if (transferEncoding === 'quoted-printable') {
- decoded = decodeBytesToString(quotedPrintableToBytes(decoded), charset);
- }
- if (/text\/html/i.test(contentType)) {
- return stripHtmlTags(decoded);
- }
- return decoded.replace(/\s+/g, ' ').trim();
- }
- function extractTextFromMime(rawMessage = '', depth = 0) {
- const { headerText, bodyText } = splitRawMessage(rawMessage);
- const headers = parseRawHeaders(headerText);
- const contentType = String(headers['content-type'] || '');
- const boundary = getBoundaryFromContentType(contentType);
- if (/multipart\//i.test(contentType) && boundary && depth < 6) {
- const marker = `--${boundary}`;
- const sections = String(bodyText || '')
- .split(marker)
- .map((part) => part.trim())
- .filter((part) => part && part !== '--');
- const extractedParts = sections
- .map((part) => part.replace(/--\s*$/, '').trim())
- .map((part) => extractTextFromMime(part, depth + 1)?.text || '')
- .filter(Boolean);
- const plainText = extractedParts.join(' ').replace(/\s+/g, ' ').trim();
- return {
- headers,
- text: plainText,
- };
- }
- return {
- headers,
- text: decodeMimeBody(bodyText, headers),
- };
- }
- function normalizeReceivedDateTime(value) {
- if (!value && value !== 0) return '';
- if (typeof value === 'number' && Number.isFinite(value)) {
- return new Date(value).toISOString();
- }
- const source = String(value || '').trim();
- if (!source) return '';
- const parsed = Date.parse(source);
- return Number.isFinite(parsed) ? new Date(parsed).toISOString() : source;
- }
- function normalizeCloudflareTempEmailMessage(row = {}) {
- if (!row || typeof row !== 'object') return null;
- const address = normalizeCloudflareTempEmailAddress(firstNonEmptyString([
- row.address,
- row.mail_address,
- row.email,
- row.recipient,
- ]));
- const raw = firstNonEmptyString([row.raw, row.source, row.mime, row.message]);
- const parsedMime = raw ? extractTextFromMime(raw) : { headers: {}, text: '' };
- const subject = decodeMimeEncodedWords(firstNonEmptyString([
- row.subject,
- parsedMime.headers.subject,
- ]));
- const fromAddress = decodeMimeEncodedWords(firstNonEmptyString([
- row.from,
- row.sender,
- row.mail_from,
- parsedMime.headers.from,
- ]));
- const bodyPreview = firstNonEmptyString([
- row.text,
- row.preview,
- row.body,
- parsedMime.text,
- raw,
- ]).replace(/\s+/g, ' ').trim();
- return {
- id: firstNonEmptyString([row.id, row.mail_id]),
- address,
- addressId: firstNonEmptyString([row.address_id, row.addressId]),
- subject,
- from: {
- emailAddress: {
- address: fromAddress,
- },
- },
- bodyPreview,
- raw,
- receivedDateTime: normalizeReceivedDateTime(firstNonEmptyString([
- row.receivedDateTime,
- row.received_at,
- row.created_at,
- row.createdAt,
- row.updated_at,
- row.date,
- ])),
- };
- }
- function normalizeCloudflareTempEmailMailApiMessages(payload) {
- return getCloudflareTempEmailMailRows(payload)
- .map((row) => normalizeCloudflareTempEmailMessage(row))
- .filter(Boolean);
- }
- function getCloudflareTempEmailAddressFromResponse(payload = {}) {
- return firstNonEmptyString([
- payload.address,
- payload.email,
- payload?.data?.address,
- payload?.data?.email,
- ]);
- }
- return {
- DEFAULT_MAIL_PAGE_SIZE,
- buildCloudflareTempEmailHeaders,
- getCloudflareTempEmailAddressFromResponse,
- joinCloudflareTempEmailUrl,
- normalizeCloudflareTempEmailAddress,
- normalizeCloudflareTempEmailBaseUrl,
- normalizeCloudflareTempEmailDomain,
- normalizeCloudflareTempEmailDomains,
- normalizeCloudflareTempEmailMailApiMessages,
- normalizeCloudflareTempEmailMessage,
- };
- });
|