@emailcheck/email-validator-js 5.0.0-beta.2 → 5.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -4
- package/dist/cli/index.js +34 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +36 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/dist/sender-strategy.d.ts +26 -0
- package/dist/serverless/adapters/aws-lambda.cjs.js +5 -5
- package/dist/serverless/adapters/aws-lambda.cjs.js.map +1 -1
- package/dist/serverless/adapters/aws-lambda.esm.js +5 -5
- package/dist/serverless/adapters/aws-lambda.esm.js.map +1 -1
- package/dist/serverless/adapters/azure.cjs.js +5 -5
- package/dist/serverless/adapters/azure.cjs.js.map +1 -1
- package/dist/serverless/adapters/azure.esm.js +5 -5
- package/dist/serverless/adapters/azure.esm.js.map +1 -1
- package/dist/serverless/adapters/cloudflare.cjs.js +5 -5
- package/dist/serverless/adapters/cloudflare.cjs.js.map +1 -1
- package/dist/serverless/adapters/cloudflare.esm.js +5 -5
- package/dist/serverless/adapters/cloudflare.esm.js.map +1 -1
- package/dist/serverless/adapters/gcp.cjs.js +5 -5
- package/dist/serverless/adapters/gcp.cjs.js.map +1 -1
- package/dist/serverless/adapters/gcp.esm.js +5 -5
- package/dist/serverless/adapters/gcp.esm.js.map +1 -1
- package/dist/serverless/adapters/netlify.cjs.js +5 -5
- package/dist/serverless/adapters/netlify.cjs.js.map +1 -1
- package/dist/serverless/adapters/netlify.esm.js +5 -5
- package/dist/serverless/adapters/netlify.esm.js.map +1 -1
- package/dist/serverless/adapters/vercel.cjs.js +5 -5
- package/dist/serverless/adapters/vercel.cjs.js.map +1 -1
- package/dist/serverless/adapters/vercel.esm.js +5 -5
- package/dist/serverless/adapters/vercel.esm.js.map +1 -1
- package/dist/serverless/index.cjs.js +5 -5
- package/dist/serverless/index.cjs.js.map +1 -1
- package/dist/serverless/index.esm.js +5 -5
- package/dist/serverless/index.esm.js.map +1 -1
- package/dist/serverless/verifier.cjs.js +5 -5
- package/dist/serverless/verifier.cjs.js.map +1 -1
- package/dist/serverless/verifier.esm.js +5 -5
- package/dist/serverless/verifier.esm.js.map +1 -1
- package/dist/serverless/verifier.min.js +1 -1
- package/dist/types.d.ts +72 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws-lambda.cjs.js","sources":["../../../src/serverless/_shared/cors.ts","../../../node_modules/string-similarity-js/dist/string-similarity.js","../../../src/serverless/verifier.ts","../../../src/serverless/_shared/dispatch.ts","../../../src/serverless/_shared/validation.ts","../../../src/serverless/adapters/aws-lambda.ts"],"sourcesContent":["/**\n * Standard CORS header set used by every adapter. `methods` lets each platform\n * advertise the verbs it actually supports without re-declaring the rest.\n */\nexport function corsHeaders(methods: string = 'GET, POST, OPTIONS'): Record<string, string> {\n return {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': methods,\n 'Access-Control-Allow-Headers': 'Content-Type',\n };\n}\n\nexport function jsonHeaders(extra?: Record<string, string>): Record<string, string> {\n return { 'Content-Type': 'application/json', ...extra };\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.stringSimilarity = void 0;\n/* global exports, Map */\n/**\n * Calculate similarity between two strings\n * @param {string} str1 First string to match\n * @param {string} str2 Second string to match\n * @param {number} [substringLength=2] Optional. Length of substring to be used in calculating similarity. Default 2.\n * @param {boolean} [caseSensitive=false] Optional. Whether you want to consider case in string matching. Default false;\n * @returns Number between 0 and 1, with 0 being a low match score.\n */\nvar stringSimilarity = function (str1, str2, substringLength, caseSensitive) {\n if (substringLength === void 0) { substringLength = 2; }\n if (caseSensitive === void 0) { caseSensitive = false; }\n if (!caseSensitive) {\n str1 = str1.toLowerCase();\n str2 = str2.toLowerCase();\n }\n if (str1.length < substringLength || str2.length < substringLength)\n return 0;\n var map = new Map();\n for (var i = 0; i < str1.length - (substringLength - 1); i++) {\n var substr1 = str1.substr(i, substringLength);\n map.set(substr1, map.has(substr1) ? map.get(substr1) + 1 : 1);\n }\n var match = 0;\n for (var j = 0; j < str2.length - (substringLength - 1); j++) {\n var substr2 = str2.substr(j, substringLength);\n var count = map.has(substr2) ? map.get(substr2) : 0;\n if (count > 0) {\n map.set(substr2, count - 1);\n match++;\n }\n }\n return (match * 2) / (str1.length + str2.length - ((substringLength - 1) * 2));\n};\nexports.stringSimilarity = stringSimilarity;\nexports.default = exports.stringSimilarity;\n//# sourceMappingURL=string-similarity.js.map","/**\n * Edge-runtime / serverless email validator.\n *\n * No Node.js APIs (no `node:net`, no `node:dns`) — DNS is delegated to a\n * caller-supplied `DNSResolver`, so the same code runs on Cloudflare Workers,\n * Vercel Edge, Lambda@Edge, and Deno Deploy.\n *\n * Shares data with the main validator: `commonEmailDomains` and the typo map\n * are imported from `src/data/`, so we never drift between the two surfaces.\n */\n\nimport { stringSimilarity } from 'string-similarity-js';\nimport commonEmailDomainsJson from '../data/common-email-domains.json';\nimport typoPatternsJson from '../data/typo-patterns.json';\nimport disposableProviders from '../disposable-email-providers.json';\nimport freeProviders from '../free-email-providers.json';\nimport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n\n/** Compact LRU/TTL cache. One Map, expiry stamp per entry, batched eviction. */\nexport class EdgeCache<T> {\n private readonly cache = new Map<string, { value: T; expires: number }>();\n\n constructor(\n private readonly maxSize = 1000,\n private readonly ttl = 3_600_000\n ) {}\n\n get(key: string): T | undefined {\n const item = this.cache.get(key);\n if (!item) return undefined;\n if (Date.now() > item.expires) {\n this.cache.delete(key);\n return undefined;\n }\n return item.value;\n }\n\n set(key: string, value: T): void {\n if (this.cache.size >= this.maxSize) this.evict();\n this.cache.set(key, { value, expires: Date.now() + this.ttl });\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n size(): number {\n return this.cache.size;\n }\n\n private evict(): void {\n // Drop the oldest 10% in one pass — Map preserves insertion order so\n // `keys()` walks oldest-first.\n const drop = Math.max(1, Math.floor(this.maxSize * 0.1));\n let n = 0;\n for (const key of this.cache.keys()) {\n if (n++ >= drop) break;\n this.cache.delete(key);\n }\n }\n}\n\n// Module-level per-isolate caches. Edge runtimes get cold-start fresh; warm\n// invocations benefit from the in-memory hits.\nexport const validationCache = new EdgeCache<EmailValidationResult>(1000);\nexport const mxCache = new EdgeCache<string[]>(500);\n\n/** Same regex the main validator uses — kept inline because edge runtimes don't auto-resolve psl. */\nconst VALID_EMAIL_REGEX =\n /^(([a-zA-Z0-9_+'-]+(\\.[a-zA-Z0-9_+'-]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}))$/;\n\n/**\n * Common email domains — re-exported so callers (Vercel Edge, etc.) can pass a\n * custom subset via `DomainSuggesterOptions.customDomains`.\n */\nexport const COMMON_DOMAINS: readonly string[] = commonEmailDomainsJson as string[];\n\nconst TYPO_PATTERNS = typoPatternsJson as Record<string, string[]>;\n/** Reverse index for O(1) typo → canonical lookup. */\nconst TYPO_LOOKUP = new Map<string, string>();\nfor (const [canonical, typos] of Object.entries(TYPO_PATTERNS)) {\n for (const typo of typos) TYPO_LOOKUP.set(typo, canonical);\n}\n\n/** DNS resolver contract — caller-supplied so we don't import `node:dns`. */\nexport interface DNSResolver {\n resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>>;\n resolveTxt(domain: string): Promise<string[]>;\n}\n\n/** No-op resolver for environments where DNS isn't available. */\nexport class StubDNSResolver implements DNSResolver {\n async resolveMx(): Promise<Array<{ exchange: string; priority: number }>> {\n return [];\n }\n async resolveTxt(): Promise<string[]> {\n return [];\n }\n}\n\n/**\n * DNS-over-HTTPS resolver — works in any runtime with `fetch` (Cloudflare\n * Workers, Vercel Edge, Deno, browsers, Node 18+). Defaults to Cloudflare's\n * 1.1.1.1 endpoint; pass `endpoint` to use Google (8.8.8.8), NextDNS, or\n * a self-hosted resolver.\n *\n * Compatible with [`cf-doh`](https://www.npmjs.com/package/cf-doh) — if you\n * already use that, drop it in directly. This built-in keeps the package\n * zero-dep so the same code works on every edge runtime without an extra\n * install step.\n */\nexport interface DoHResolverOptions {\n /** DoH endpoint URL. Default: https://cloudflare-dns.com/dns-query */\n endpoint?: string;\n /** Per-query request timeout, ms. Default: 5000 */\n timeoutMs?: number;\n /** Custom fetch (e.g. to add headers / proxy). Default: globalThis.fetch */\n fetch?: typeof fetch;\n}\n\ninterface DoHAnswer {\n name: string;\n type: number;\n TTL: number;\n data: string;\n}\n\ninterface DoHResponse {\n Status: number;\n Answer?: DoHAnswer[];\n}\n\nconst DOH_RECORD_TYPE = { MX: 15, TXT: 16 } as const;\n\nexport class DoHResolver implements DNSResolver {\n private readonly endpoint: string;\n private readonly timeoutMs: number;\n private readonly fetchFn: typeof fetch;\n\n constructor(options: DoHResolverOptions = {}) {\n this.endpoint = options.endpoint ?? 'https://cloudflare-dns.com/dns-query';\n this.timeoutMs = options.timeoutMs ?? 5000;\n this.fetchFn = options.fetch ?? globalThis.fetch;\n }\n\n async resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>> {\n const records = await this.query(domain, DOH_RECORD_TYPE.MX);\n if (!records) return [];\n return records\n .map((answer) => {\n // MX answer data: \"<priority> <exchange>\" (with optional trailing dot).\n const match = answer.data.match(/^(\\d+)\\s+(.+?)\\.?$/);\n if (!match) return null;\n return { priority: Number(match[1]), exchange: match[2] as string };\n })\n .filter((r): r is { exchange: string; priority: number } => r !== null)\n .sort((a, b) => a.priority - b.priority);\n }\n\n async resolveTxt(domain: string): Promise<string[]> {\n const records = await this.query(domain, DOH_RECORD_TYPE.TXT);\n if (!records) return [];\n // TXT answers come back as quoted strings — strip the surrounding quotes.\n return records.map((answer) => answer.data.replace(/^\"(.*)\"$/, '$1'));\n }\n\n private async query(domain: string, type: number): Promise<DoHAnswer[] | null> {\n const url = `${this.endpoint}?name=${encodeURIComponent(domain)}&type=${type}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const response = await this.fetchFn(url, {\n headers: { Accept: 'application/dns-json' },\n signal: controller.signal,\n });\n if (!response.ok) return null;\n const json = (await response.json()) as DoHResponse;\n // Status 0 = NOERROR. Anything else (NXDOMAIN, SERVFAIL, etc.) → no answers.\n if (json.Status !== 0) return [];\n return json.Answer ?? [];\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n/**\n * Suggest a corrected domain. Returns the canonical for a known typo,\n * otherwise the closest match within the threshold, otherwise null.\n */\nexport function suggestDomain(domain: string, options?: DomainSuggesterOptions): string | null {\n const lower = domain.toLowerCase();\n\n // Hand-curated typo map first — beats similarity for common cases.\n const known = TYPO_LOOKUP.get(lower);\n if (known) return known;\n\n const domains = options?.customDomains ?? COMMON_DOMAINS;\n if (domains.includes(lower)) return null;\n\n const threshold = options?.threshold ?? 2;\n let minDistance = Infinity;\n let suggestion: string | null = null;\n\n for (const candidate of domains) {\n const candidateLower = candidate.toLowerCase();\n if (lower === candidateLower) return null;\n const similarity = stringSimilarity(lower, candidateLower);\n const distance = Math.round((1 - similarity) * Math.max(domain.length, candidate.length));\n if (distance > 0 && distance <= threshold && distance < minDistance) {\n minDistance = distance;\n suggestion = candidate;\n }\n }\n return suggestion;\n}\n\n/**\n * Validate one email — syntax / typo / disposable / free / MX (if a resolver\n * is supplied). Each step is independently flag-gated so callers pay only for\n * what they use.\n */\nexport async function validateEmailCore(\n email: string,\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult> {\n const normalized = email.toLowerCase().trim();\n\n if (!options?.skipCache) {\n const cached = validationCache.get(normalized);\n if (cached) return cached;\n }\n\n const result: EmailValidationResult = { valid: false, email: normalized, validators: {} };\n\n if (options?.validateSyntax !== false) {\n const syntaxValid = VALID_EMAIL_REGEX.test(normalized);\n result.validators.syntax = { valid: syntaxValid };\n if (!syntaxValid) {\n validationCache.set(normalized, result);\n return result;\n }\n }\n\n const [local, domain] = normalized.split('@');\n result.local = local;\n result.domain = domain;\n\n if (options?.validateTypo !== false) {\n const suggestion = suggestDomain(domain, options?.domainSuggesterOptions);\n result.validators.typo = { valid: !suggestion, suggestion: suggestion ?? undefined };\n }\n\n if (options?.validateDisposable !== false) {\n result.validators.disposable = { valid: !disposableProviders.includes(domain) };\n }\n\n if (options?.validateFree !== false) {\n result.validators.free = { valid: !freeProviders.includes(domain) };\n }\n\n if (options?.validateMx && options.dnsResolver) {\n try {\n const records = await options.dnsResolver.resolveMx(domain);\n const hasMx = records.length > 0;\n result.validators.mx = {\n valid: hasMx,\n records: hasMx ? records.map((r) => r.exchange) : undefined,\n };\n } catch (error) {\n result.validators.mx = {\n valid: false,\n error: error instanceof Error ? error.message : 'MX validation failed',\n };\n }\n }\n\n // Free-provider detection is informational; only the hard validators gate validity.\n result.valid = (['syntax', 'typo', 'disposable', 'mx'] as const).every((key) => {\n const validator = result.validators[key];\n return !validator || validator.valid !== false;\n });\n\n if (!options?.skipCache) validationCache.set(normalized, result);\n return result;\n}\n\nexport async function validateEmailBatch(\n emails: string[],\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult[]> {\n const chunkSize = options?.batchSize ?? 10;\n const results: EmailValidationResult[] = [];\n for (let i = 0; i < emails.length; i += chunkSize) {\n const chunk = emails.slice(i, i + chunkSize);\n const chunkResults = await Promise.all(chunk.map((email) => validateEmailCore(email, options)));\n results.push(...chunkResults);\n }\n return results;\n}\n\nexport function clearCache(): void {\n validationCache.clear();\n mxCache.clear();\n}\n\nexport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n","import type { EmailValidationResult } from '../../types';\nimport { validateEmailBatch, validateEmailCore } from '../verifier';\nimport type { ValidationDispatch } from './validation';\n\n/**\n * Execute a classified request against the core validator. Single-email\n * requests yield one result; batch requests yield an array.\n */\nexport async function executeValidation(\n dispatch: ValidationDispatch\n): Promise<EmailValidationResult | EmailValidationResult[]> {\n if (dispatch.kind === 'single') {\n return validateEmailCore(dispatch.email, dispatch.options);\n }\n return validateEmailBatch(dispatch.emails, dispatch.options);\n}\n","import type { ValidateEmailOptions } from '../../types';\n\n/** Hard limit on batch size enforced by every adapter. */\nexport const MAX_BATCH_SIZE = 100;\n\n/** Shape of POST bodies and Lambda invocations across all serverless adapters. */\nexport interface ValidationRequestBody {\n email?: string;\n emails?: string[];\n options?: ValidateEmailOptions;\n}\n\nexport type ValidationDispatch =\n | { kind: 'single'; email: string; options?: ValidateEmailOptions }\n | { kind: 'batch'; emails: string[]; options?: ValidateEmailOptions };\n\nexport interface ValidationFailure {\n kind: 'invalid';\n status: 400;\n message: string;\n}\n\n/**\n * Validation for endpoints that accept ONLY a batch (`emails`). Returns\n * a 400 failure if emails is missing/empty/oversized, or null when valid.\n * Routed `/validate/batch` paths use this so error messages stay batch-specific.\n */\nexport type BatchValidation = { ok: true; emails: string[] } | { ok: false; status: 400; message: string };\n\nexport function validateBatchEmailsField(emails: unknown): BatchValidation {\n if (!Array.isArray(emails) || emails.length === 0) {\n return { ok: false, status: 400, message: 'Emails array is required' };\n }\n if (emails.length > MAX_BATCH_SIZE) {\n return { ok: false, status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { ok: true, emails: emails as string[] };\n}\n\n/**\n * Apply the rules every serverless adapter shares:\n * 1. body must request either `email` or `emails`\n * 2. `emails` must be a non-empty array of ≤ MAX_BATCH_SIZE entries\n *\n * Centralising this means a future rule change (say, raising the cap) lands\n * in one place instead of three.\n */\nexport function classifyRequest(\n body: ValidationRequestBody | null | undefined\n): ValidationDispatch | ValidationFailure {\n if (!body || (!body.email && !body.emails)) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n if (body.emails) {\n if (!Array.isArray(body.emails) || body.emails.length === 0) {\n return { kind: 'invalid', status: 400, message: 'Emails array is required' };\n }\n if (body.emails.length > MAX_BATCH_SIZE) {\n return { kind: 'invalid', status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { kind: 'batch', emails: body.emails, options: body.options };\n }\n // body.email must be set per the first guard (which checks both fields).\n if (!body.email) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n return { kind: 'single', email: body.email, options: body.options };\n}\n","/**\n * AWS Lambda adapter — three handler shapes for three deploy modes:\n *\n * - `handler` — routed (recommended) — `/health`, `/validate`,\n * `/validate/batch`. Wire to API Gateway with\n * `{proxy+}` so all three paths land on one Lambda.\n * - `apiGatewayHandler` — single-route — accepts API Gateway proxy events\n * but never inspects `event.path`. Pick this when\n * you want one Lambda per URL.\n * - `lambdaHandler` — direct invocation — no API Gateway envelope.\n * Pick this when calling from another AWS service\n * (Step Functions, EventBridge, …).\n *\n * Shared validation rules + CORS headers come from `../_shared/` so all three\n * agree on what's accepted.\n */\nimport type { ValidateEmailOptions } from '../../types';\nimport { corsHeaders, jsonHeaders } from '../_shared/cors';\nimport { executeValidation } from '../_shared/dispatch';\nimport { classifyRequest, type ValidationRequestBody, validateBatchEmailsField } from '../_shared/validation';\nimport { clearCache, validateEmailCore } from '../verifier';\n\n/**\n * Loose API-Gateway event/result/context shapes — `headers` and similar maps\n * intentionally widen to `string | undefined` so they line up with the\n * official `@types/aws-lambda` definitions used by callers/tests.\n */\nexport interface APIGatewayProxyEvent {\n body: string | null;\n headers: { [key: string]: string | undefined };\n httpMethod: string;\n path: string;\n queryStringParameters: { [key: string]: string | undefined } | null;\n pathParameters: { [key: string]: string | undefined } | null;\n isBase64Encoded?: boolean;\n}\n\nexport interface APIGatewayProxyResult {\n statusCode: number;\n headers?: { [key: string]: string };\n body: string;\n}\n\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n awsRequestId: string;\n remainingTimeInMillis: number;\n}\n\ninterface ValidateResponse {\n success: boolean;\n data?: unknown;\n error?: string;\n}\n\nconst POST_HEADERS = jsonHeaders(corsHeaders('POST, OPTIONS'));\nconst ROUTED_HEADERS = jsonHeaders(corsHeaders());\n\nfunction jsonResponse(statusCode: number, body: unknown, headers: Record<string, string>): APIGatewayProxyResult {\n return { statusCode, headers, body: JSON.stringify(body) };\n}\n\n// Single-route API Gateway handler — accepts proxy events but doesn't inspect `event.path`.\nexport async function apiGatewayHandler(\n event: APIGatewayProxyEvent,\n _context: LambdaContext\n): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 200, headers: corsHeaders('POST, OPTIONS'), body: '' };\n }\n\n try {\n const request: ValidationRequestBody = event.body ? JSON.parse(event.body) : {};\n const classified = classifyRequest(request);\n if (classified.kind === 'invalid') {\n return jsonResponse(classified.status, { success: false, error: classified.message }, POST_HEADERS);\n }\n const data = await executeValidation(classified);\n return jsonResponse(200, { success: true, data }, POST_HEADERS);\n } catch (error) {\n console.error('Lambda error:', error);\n const message = error instanceof Error ? error.message : 'Internal server error';\n return jsonResponse(500, { success: false, error: message }, POST_HEADERS);\n }\n}\n\n// Direct Lambda handler (no API Gateway envelope).\nexport async function lambdaHandler(event: ValidationRequestBody, _context: LambdaContext): Promise<ValidateResponse> {\n try {\n const classified = classifyRequest(event);\n if (classified.kind === 'invalid') {\n return { success: false, error: classified.message };\n }\n return { success: true, data: await executeValidation(classified) };\n } catch (error) {\n console.error('Lambda error:', error);\n return { success: false, error: error instanceof Error ? error.message : 'Internal server error' };\n }\n}\n\n// Cache management handler.\nexport async function cacheHandler(\n event: { action: 'clear' | 'stats' },\n _context: LambdaContext\n): Promise<{ success: boolean; message?: string; stats?: unknown }> {\n switch (event.action) {\n case 'clear':\n clearCache();\n return { success: true, message: 'Cache cleared' };\n case 'stats':\n return { success: true, message: 'Cache stats not implemented' };\n default:\n return { success: false, message: 'Invalid action' };\n }\n}\n\n/** Decode the API Gateway body, supporting base64-encoded payloads. */\nfunction decodeBody(event: APIGatewayProxyEvent): unknown {\n if (!event.body) return {};\n const raw = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString('utf-8') : event.body;\n return JSON.parse(raw);\n}\n\n// Routed handler — supports /health, /validate, /validate/batch. The context\n// argument is intentionally `unknown` so callers can pass either our minimal\n// LambdaContext or the official `aws-lambda#Context` without a cast.\nexport async function handler(event: APIGatewayProxyEvent, _context?: unknown): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 204, headers: corsHeaders(), body: '' };\n }\n\n if (event.path === '/health' && event.httpMethod === 'GET') {\n return jsonResponse(200, { status: 'healthy', timestamp: new Date().toISOString() }, ROUTED_HEADERS);\n }\n\n const isValidatePath = event.path === '/validate' || event.path === '/validate/batch';\n if (isValidatePath && event.httpMethod !== 'POST') {\n return jsonResponse(405, { error: 'Method not allowed' }, ROUTED_HEADERS);\n }\n\n if (event.path === '/validate' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as { email?: string };\n if (!body.email) return jsonResponse(400, { error: 'Email is required' }, ROUTED_HEADERS);\n\n const options = parseValidateOptions(event.queryStringParameters);\n const result = await validateEmailCore(body.email, options);\n return jsonResponse(200, result, ROUTED_HEADERS);\n } catch (error) {\n if (error instanceof SyntaxError) {\n return jsonResponse(400, { error: 'Invalid request body' }, ROUTED_HEADERS);\n }\n console.error('Validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n if (event.path === '/validate/batch' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as ValidationRequestBody;\n const validated = validateBatchEmailsField(body.emails);\n if (!validated.ok) return jsonResponse(validated.status, { error: validated.message }, ROUTED_HEADERS);\n const results = await executeValidation({ kind: 'batch', emails: validated.emails });\n return jsonResponse(200, { results }, ROUTED_HEADERS);\n } catch (error) {\n console.error('Batch validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n return jsonResponse(404, { error: 'Not found' }, ROUTED_HEADERS);\n}\n\nfunction parseValidateOptions(query: { [key: string]: string | undefined } | null): Partial<ValidateEmailOptions> {\n if (!query) return {};\n const options: Partial<ValidateEmailOptions> = {};\n if (query.skipCache === 'true') options.skipCache = true;\n if (query.validateTypo === 'false') options.validateTypo = false;\n return options;\n}\n\nexport default {\n apiGatewayHandler,\n lambdaHandler,\n cacheHandler,\n handler,\n};\n"],"names":["exports","stringSimilarity","__async"],"mappings":"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","x_google_ignoreList":[1]}
|
|
1
|
+
{"version":3,"file":"aws-lambda.cjs.js","sources":["../../../src/serverless/_shared/cors.ts","../../../node_modules/string-similarity-js/dist/string-similarity.js","../../../src/serverless/verifier.ts","../../../src/serverless/_shared/dispatch.ts","../../../src/serverless/_shared/validation.ts","../../../src/serverless/adapters/aws-lambda.ts"],"sourcesContent":["/**\n * Standard CORS header set used by every adapter. `methods` lets each platform\n * advertise the verbs it actually supports without re-declaring the rest.\n */\nexport function corsHeaders(methods: string = 'GET, POST, OPTIONS'): Record<string, string> {\n return {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': methods,\n 'Access-Control-Allow-Headers': 'Content-Type',\n };\n}\n\nexport function jsonHeaders(extra?: Record<string, string>): Record<string, string> {\n return { 'Content-Type': 'application/json', ...extra };\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.stringSimilarity = void 0;\n/* global exports, Map */\n/**\n * Calculate similarity between two strings\n * @param {string} str1 First string to match\n * @param {string} str2 Second string to match\n * @param {number} [substringLength=2] Optional. Length of substring to be used in calculating similarity. Default 2.\n * @param {boolean} [caseSensitive=false] Optional. Whether you want to consider case in string matching. Default false;\n * @returns Number between 0 and 1, with 0 being a low match score.\n */\nvar stringSimilarity = function (str1, str2, substringLength, caseSensitive) {\n if (substringLength === void 0) { substringLength = 2; }\n if (caseSensitive === void 0) { caseSensitive = false; }\n if (!caseSensitive) {\n str1 = str1.toLowerCase();\n str2 = str2.toLowerCase();\n }\n if (str1.length < substringLength || str2.length < substringLength)\n return 0;\n var map = new Map();\n for (var i = 0; i < str1.length - (substringLength - 1); i++) {\n var substr1 = str1.substr(i, substringLength);\n map.set(substr1, map.has(substr1) ? map.get(substr1) + 1 : 1);\n }\n var match = 0;\n for (var j = 0; j < str2.length - (substringLength - 1); j++) {\n var substr2 = str2.substr(j, substringLength);\n var count = map.has(substr2) ? map.get(substr2) : 0;\n if (count > 0) {\n map.set(substr2, count - 1);\n match++;\n }\n }\n return (match * 2) / (str1.length + str2.length - ((substringLength - 1) * 2));\n};\nexports.stringSimilarity = stringSimilarity;\nexports.default = exports.stringSimilarity;\n//# sourceMappingURL=string-similarity.js.map","/**\n * Edge-runtime / serverless email validator.\n *\n * No Node.js APIs (no `node:net`, no `node:dns`) — DNS is delegated to a\n * caller-supplied `DNSResolver`, so the same code runs on Cloudflare Workers,\n * Vercel Edge, Lambda@Edge, and Deno Deploy.\n *\n * Shares data with the main validator: `commonEmailDomains` and the typo map\n * are imported from `src/data/`, so we never drift between the two surfaces.\n */\n\nimport { stringSimilarity } from 'string-similarity-js';\nimport commonEmailDomainsJson from '../data/common-email-domains.json';\nimport typoPatternsJson from '../data/typo-patterns.json';\nimport disposableProviders from '../disposable-email-providers.json';\nimport freeProviders from '../free-email-providers.json';\nimport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n\n/** Compact LRU/TTL cache. One Map, expiry stamp per entry, batched eviction. */\nexport class EdgeCache<T> {\n private readonly cache = new Map<string, { value: T; expires: number }>();\n\n constructor(\n private readonly maxSize = 1000,\n private readonly ttl = 3_600_000\n ) {}\n\n get(key: string): T | undefined {\n const item = this.cache.get(key);\n if (!item) return undefined;\n if (Date.now() > item.expires) {\n this.cache.delete(key);\n return undefined;\n }\n return item.value;\n }\n\n set(key: string, value: T): void {\n if (this.cache.size >= this.maxSize) this.evict();\n this.cache.set(key, { value, expires: Date.now() + this.ttl });\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n size(): number {\n return this.cache.size;\n }\n\n private evict(): void {\n // Drop the oldest 10% in one pass — Map preserves insertion order so\n // `keys()` walks oldest-first.\n const drop = Math.max(1, Math.floor(this.maxSize * 0.1));\n let n = 0;\n for (const key of this.cache.keys()) {\n if (n++ >= drop) break;\n this.cache.delete(key);\n }\n }\n}\n\n// Module-level per-isolate caches. Edge runtimes get cold-start fresh; warm\n// invocations benefit from the in-memory hits.\nexport const validationCache = new EdgeCache<EmailValidationResult>(1000);\nexport const mxCache = new EdgeCache<string[]>(500);\n\n/** Same regex the main validator uses — kept inline because edge runtimes don't auto-resolve psl. */\nconst VALID_EMAIL_REGEX =\n /^(([a-zA-Z0-9_+'-]+(\\.[a-zA-Z0-9_+'-]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}))$/;\n\n/**\n * Common email domains — re-exported so callers (Vercel Edge, etc.) can pass a\n * custom subset via `DomainSuggesterOptions.customDomains`.\n */\nexport const COMMON_DOMAINS: readonly string[] = commonEmailDomainsJson as string[];\n\nconst TYPO_PATTERNS = typoPatternsJson as Record<string, string[]>;\n/** Reverse index for O(1) typo → canonical lookup. */\nconst TYPO_LOOKUP = new Map<string, string>();\nfor (const [canonical, typos] of Object.entries(TYPO_PATTERNS)) {\n for (const typo of typos) TYPO_LOOKUP.set(typo, canonical);\n}\n\n/** DNS resolver contract — caller-supplied so we don't import `node:dns`. */\nexport interface DNSResolver {\n resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>>;\n resolveTxt(domain: string): Promise<string[]>;\n}\n\n/** No-op resolver for environments where DNS isn't available. */\nexport class StubDNSResolver implements DNSResolver {\n async resolveMx(): Promise<Array<{ exchange: string; priority: number }>> {\n return [];\n }\n async resolveTxt(): Promise<string[]> {\n return [];\n }\n}\n\n/**\n * DNS-over-HTTPS resolver — works in any runtime with `fetch` (Cloudflare\n * Workers, Vercel Edge, Deno, browsers, Node 18+). Defaults to Cloudflare's\n * 1.1.1.1 endpoint; pass `endpoint` to use Google (8.8.8.8), NextDNS, or\n * a self-hosted resolver.\n *\n * Compatible with [`cf-doh`](https://www.npmjs.com/package/cf-doh) — if you\n * already use that, drop it in directly. This built-in keeps the package\n * zero-dep so the same code works on every edge runtime without an extra\n * install step.\n */\nexport interface DoHResolverOptions {\n /** DoH endpoint URL. Default: https://cloudflare-dns.com/dns-query */\n endpoint?: string;\n /** Per-query request timeout, ms. Default: 5000 */\n timeoutMs?: number;\n /** Custom fetch (e.g. to add headers / proxy). Default: globalThis.fetch */\n fetch?: typeof fetch;\n}\n\ninterface DoHAnswer {\n name: string;\n type: number;\n TTL: number;\n data: string;\n}\n\ninterface DoHResponse {\n Status: number;\n Answer?: DoHAnswer[];\n}\n\nconst DOH_RECORD_TYPE = { MX: 15, TXT: 16 } as const;\n\nexport class DoHResolver implements DNSResolver {\n private readonly endpoint: string;\n private readonly timeoutMs: number;\n private readonly fetchFn: typeof fetch;\n\n constructor(options: DoHResolverOptions = {}) {\n this.endpoint = options.endpoint ?? 'https://cloudflare-dns.com/dns-query';\n this.timeoutMs = options.timeoutMs ?? 5000;\n this.fetchFn = options.fetch ?? globalThis.fetch;\n }\n\n async resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>> {\n const records = await this.query(domain, DOH_RECORD_TYPE.MX);\n if (!records) return [];\n return records\n .map((answer) => {\n // MX answer data: \"<priority> <exchange>\" (with optional trailing dot).\n const match = answer.data.match(/^(\\d+)\\s+(.+?)\\.?$/);\n if (!match) return null;\n return { priority: Number(match[1]), exchange: match[2] as string };\n })\n .filter((r): r is { exchange: string; priority: number } => r !== null)\n .sort((a, b) => a.priority - b.priority);\n }\n\n async resolveTxt(domain: string): Promise<string[]> {\n const records = await this.query(domain, DOH_RECORD_TYPE.TXT);\n if (!records) return [];\n // TXT answers come back as quoted strings — strip the surrounding quotes.\n return records.map((answer) => answer.data.replace(/^\"(.*)\"$/, '$1'));\n }\n\n private async query(domain: string, type: number): Promise<DoHAnswer[] | null> {\n const url = `${this.endpoint}?name=${encodeURIComponent(domain)}&type=${type}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const response = await this.fetchFn(url, {\n headers: { Accept: 'application/dns-json' },\n signal: controller.signal,\n });\n if (!response.ok) return null;\n const json = (await response.json()) as DoHResponse;\n // Status 0 = NOERROR. Anything else (NXDOMAIN, SERVFAIL, etc.) → no answers.\n if (json.Status !== 0) return [];\n return json.Answer ?? [];\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n/**\n * Suggest a corrected domain. Returns the canonical for a known typo,\n * otherwise the closest match within the threshold, otherwise null.\n */\nexport function suggestDomain(domain: string, options?: DomainSuggesterOptions): string | null {\n const lower = domain.toLowerCase();\n\n // Hand-curated typo map first — beats similarity for common cases.\n const known = TYPO_LOOKUP.get(lower);\n if (known) return known;\n\n const domains = options?.customDomains ?? COMMON_DOMAINS;\n if (domains.includes(lower)) return null;\n\n const threshold = options?.threshold ?? 2;\n let minDistance = Infinity;\n let suggestion: string | null = null;\n\n for (const candidate of domains) {\n const candidateLower = candidate.toLowerCase();\n if (lower === candidateLower) return null;\n const similarity = stringSimilarity(lower, candidateLower);\n const distance = Math.round((1 - similarity) * Math.max(domain.length, candidate.length));\n if (distance > 0 && distance <= threshold && distance < minDistance) {\n minDistance = distance;\n suggestion = candidate;\n }\n }\n return suggestion;\n}\n\n/**\n * Validate one email — syntax / typo / disposable / free / MX (if a resolver\n * is supplied). Each step is independently flag-gated so callers pay only for\n * what they use.\n */\nexport async function validateEmailCore(\n email: string,\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult> {\n const normalized = email.toLowerCase().trim();\n\n if (!options?.skipCache) {\n const cached = validationCache.get(normalized);\n if (cached) return cached;\n }\n\n const result: EmailValidationResult = { valid: false, email: normalized, validators: {} };\n\n if (options?.validateSyntax !== false) {\n const syntaxValid = VALID_EMAIL_REGEX.test(normalized);\n result.validators.syntax = { valid: syntaxValid };\n if (!syntaxValid) {\n validationCache.set(normalized, result);\n return result;\n }\n }\n\n const [local, domain] = normalized.split('@');\n result.local = local;\n result.domain = domain;\n\n if (options?.validateTypo !== false) {\n const suggestion = suggestDomain(domain, options?.domainSuggesterOptions);\n result.validators.typo = { valid: !suggestion, suggestion: suggestion ?? undefined };\n }\n\n if (options?.validateDisposable !== false) {\n result.validators.disposable = { valid: !disposableProviders.includes(domain) };\n }\n\n if (options?.validateFree !== false) {\n result.validators.free = { valid: !freeProviders.includes(domain) };\n }\n\n if (options?.validateMx && options.dnsResolver) {\n try {\n const records = await options.dnsResolver.resolveMx(domain);\n const hasMx = records.length > 0;\n result.validators.mx = {\n valid: hasMx,\n records: hasMx ? records.map((r) => r.exchange) : undefined,\n };\n } catch (error) {\n result.validators.mx = {\n valid: false,\n error: error instanceof Error ? error.message : 'MX validation failed',\n };\n }\n }\n\n // Free-provider detection is informational; only the hard validators gate validity.\n result.valid = (['syntax', 'typo', 'disposable', 'mx'] as const).every((key) => {\n const validator = result.validators[key];\n return !validator || validator.valid !== false;\n });\n\n if (!options?.skipCache) validationCache.set(normalized, result);\n return result;\n}\n\nexport async function validateEmailBatch(\n emails: string[],\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult[]> {\n const chunkSize = options?.batchSize ?? 10;\n const results: EmailValidationResult[] = [];\n for (let i = 0; i < emails.length; i += chunkSize) {\n const chunk = emails.slice(i, i + chunkSize);\n const chunkResults = await Promise.all(chunk.map((email) => validateEmailCore(email, options)));\n results.push(...chunkResults);\n }\n return results;\n}\n\nexport function clearCache(): void {\n validationCache.clear();\n mxCache.clear();\n}\n\nexport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n","import type { EmailValidationResult } from '../../types';\nimport { validateEmailBatch, validateEmailCore } from '../verifier';\nimport type { ValidationDispatch } from './validation';\n\n/**\n * Execute a classified request against the core validator. Single-email\n * requests yield one result; batch requests yield an array.\n */\nexport async function executeValidation(\n dispatch: ValidationDispatch\n): Promise<EmailValidationResult | EmailValidationResult[]> {\n if (dispatch.kind === 'single') {\n return validateEmailCore(dispatch.email, dispatch.options);\n }\n return validateEmailBatch(dispatch.emails, dispatch.options);\n}\n","import type { ValidateEmailOptions } from '../../types';\n\n/** Hard limit on batch size enforced by every adapter. */\nexport const MAX_BATCH_SIZE = 100;\n\n/** Shape of POST bodies and Lambda invocations across all serverless adapters. */\nexport interface ValidationRequestBody {\n email?: string;\n emails?: string[];\n options?: ValidateEmailOptions;\n}\n\nexport type ValidationDispatch =\n | { kind: 'single'; email: string; options?: ValidateEmailOptions }\n | { kind: 'batch'; emails: string[]; options?: ValidateEmailOptions };\n\nexport interface ValidationFailure {\n kind: 'invalid';\n status: 400;\n message: string;\n}\n\n/**\n * Validation for endpoints that accept ONLY a batch (`emails`). Returns\n * a 400 failure if emails is missing/empty/oversized, or null when valid.\n * Routed `/validate/batch` paths use this so error messages stay batch-specific.\n */\nexport type BatchValidation = { ok: true; emails: string[] } | { ok: false; status: 400; message: string };\n\nexport function validateBatchEmailsField(emails: unknown): BatchValidation {\n if (!Array.isArray(emails) || emails.length === 0) {\n return { ok: false, status: 400, message: 'Emails array is required' };\n }\n if (emails.length > MAX_BATCH_SIZE) {\n return { ok: false, status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { ok: true, emails: emails as string[] };\n}\n\n/**\n * Apply the rules every serverless adapter shares:\n * 1. body must request either `email` or `emails`\n * 2. `emails` must be a non-empty array of ≤ MAX_BATCH_SIZE entries\n *\n * Centralising this means a future rule change (say, raising the cap) lands\n * in one place instead of three.\n */\nexport function classifyRequest(\n body: ValidationRequestBody | null | undefined\n): ValidationDispatch | ValidationFailure {\n if (!body || (!body.email && !body.emails)) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n if (body.emails) {\n if (!Array.isArray(body.emails) || body.emails.length === 0) {\n return { kind: 'invalid', status: 400, message: 'Emails array is required' };\n }\n if (body.emails.length > MAX_BATCH_SIZE) {\n return { kind: 'invalid', status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { kind: 'batch', emails: body.emails, options: body.options };\n }\n // body.email must be set per the first guard (which checks both fields).\n if (!body.email) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n return { kind: 'single', email: body.email, options: body.options };\n}\n","/**\n * AWS Lambda adapter — three handler shapes for three deploy modes:\n *\n * - `handler` — routed (recommended) — `/health`, `/validate`,\n * `/validate/batch`. Wire to API Gateway with\n * `{proxy+}` so all three paths land on one Lambda.\n * - `apiGatewayHandler` — single-route — accepts API Gateway proxy events\n * but never inspects `event.path`. Pick this when\n * you want one Lambda per URL.\n * - `lambdaHandler` — direct invocation — no API Gateway envelope.\n * Pick this when calling from another AWS service\n * (Step Functions, EventBridge, …).\n *\n * Shared validation rules + CORS headers come from `../_shared/` so all three\n * agree on what's accepted.\n */\nimport type { ValidateEmailOptions } from '../../types';\nimport { corsHeaders, jsonHeaders } from '../_shared/cors';\nimport { executeValidation } from '../_shared/dispatch';\nimport { classifyRequest, type ValidationRequestBody, validateBatchEmailsField } from '../_shared/validation';\nimport { clearCache, validateEmailCore } from '../verifier';\n\n/**\n * Loose API-Gateway event/result/context shapes — `headers` and similar maps\n * intentionally widen to `string | undefined` so they line up with the\n * official `@types/aws-lambda` definitions used by callers/tests.\n */\nexport interface APIGatewayProxyEvent {\n body: string | null;\n headers: { [key: string]: string | undefined };\n httpMethod: string;\n path: string;\n queryStringParameters: { [key: string]: string | undefined } | null;\n pathParameters: { [key: string]: string | undefined } | null;\n isBase64Encoded?: boolean;\n}\n\nexport interface APIGatewayProxyResult {\n statusCode: number;\n headers?: { [key: string]: string };\n body: string;\n}\n\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n awsRequestId: string;\n remainingTimeInMillis: number;\n}\n\ninterface ValidateResponse {\n success: boolean;\n data?: unknown;\n error?: string;\n}\n\nconst POST_HEADERS = jsonHeaders(corsHeaders('POST, OPTIONS'));\nconst ROUTED_HEADERS = jsonHeaders(corsHeaders());\n\nfunction jsonResponse(statusCode: number, body: unknown, headers: Record<string, string>): APIGatewayProxyResult {\n return { statusCode, headers, body: JSON.stringify(body) };\n}\n\n// Single-route API Gateway handler — accepts proxy events but doesn't inspect `event.path`.\nexport async function apiGatewayHandler(\n event: APIGatewayProxyEvent,\n _context: LambdaContext\n): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 200, headers: corsHeaders('POST, OPTIONS'), body: '' };\n }\n\n try {\n const request: ValidationRequestBody = event.body ? JSON.parse(event.body) : {};\n const classified = classifyRequest(request);\n if (classified.kind === 'invalid') {\n return jsonResponse(classified.status, { success: false, error: classified.message }, POST_HEADERS);\n }\n const data = await executeValidation(classified);\n return jsonResponse(200, { success: true, data }, POST_HEADERS);\n } catch (error) {\n console.error('Lambda error:', error);\n const message = error instanceof Error ? error.message : 'Internal server error';\n return jsonResponse(500, { success: false, error: message }, POST_HEADERS);\n }\n}\n\n// Direct Lambda handler (no API Gateway envelope).\nexport async function lambdaHandler(event: ValidationRequestBody, _context: LambdaContext): Promise<ValidateResponse> {\n try {\n const classified = classifyRequest(event);\n if (classified.kind === 'invalid') {\n return { success: false, error: classified.message };\n }\n return { success: true, data: await executeValidation(classified) };\n } catch (error) {\n console.error('Lambda error:', error);\n return { success: false, error: error instanceof Error ? error.message : 'Internal server error' };\n }\n}\n\n// Cache management handler.\nexport async function cacheHandler(\n event: { action: 'clear' | 'stats' },\n _context: LambdaContext\n): Promise<{ success: boolean; message?: string; stats?: unknown }> {\n switch (event.action) {\n case 'clear':\n clearCache();\n return { success: true, message: 'Cache cleared' };\n case 'stats':\n return { success: true, message: 'Cache stats not implemented' };\n default:\n return { success: false, message: 'Invalid action' };\n }\n}\n\n/** Decode the API Gateway body, supporting base64-encoded payloads. */\nfunction decodeBody(event: APIGatewayProxyEvent): unknown {\n if (!event.body) return {};\n const raw = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString('utf-8') : event.body;\n return JSON.parse(raw);\n}\n\n// Routed handler — supports /health, /validate, /validate/batch. The context\n// argument is intentionally `unknown` so callers can pass either our minimal\n// LambdaContext or the official `aws-lambda#Context` without a cast.\nexport async function handler(event: APIGatewayProxyEvent, _context?: unknown): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 204, headers: corsHeaders(), body: '' };\n }\n\n if (event.path === '/health' && event.httpMethod === 'GET') {\n return jsonResponse(200, { status: 'healthy', timestamp: new Date().toISOString() }, ROUTED_HEADERS);\n }\n\n const isValidatePath = event.path === '/validate' || event.path === '/validate/batch';\n if (isValidatePath && event.httpMethod !== 'POST') {\n return jsonResponse(405, { error: 'Method not allowed' }, ROUTED_HEADERS);\n }\n\n if (event.path === '/validate' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as { email?: string };\n if (!body.email) return jsonResponse(400, { error: 'Email is required' }, ROUTED_HEADERS);\n\n const options = parseValidateOptions(event.queryStringParameters);\n const result = await validateEmailCore(body.email, options);\n return jsonResponse(200, result, ROUTED_HEADERS);\n } catch (error) {\n if (error instanceof SyntaxError) {\n return jsonResponse(400, { error: 'Invalid request body' }, ROUTED_HEADERS);\n }\n console.error('Validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n if (event.path === '/validate/batch' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as ValidationRequestBody;\n const validated = validateBatchEmailsField(body.emails);\n if (!validated.ok) return jsonResponse(validated.status, { error: validated.message }, ROUTED_HEADERS);\n const results = await executeValidation({ kind: 'batch', emails: validated.emails });\n return jsonResponse(200, { results }, ROUTED_HEADERS);\n } catch (error) {\n console.error('Batch validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n return jsonResponse(404, { error: 'Not found' }, ROUTED_HEADERS);\n}\n\nfunction parseValidateOptions(query: { [key: string]: string | undefined } | null): Partial<ValidateEmailOptions> {\n if (!query) return {};\n const options: Partial<ValidateEmailOptions> = {};\n if (query.skipCache === 'true') options.skipCache = true;\n if (query.validateTypo === 'false') options.validateTypo = false;\n return options;\n}\n\nexport default {\n apiGatewayHandler,\n lambdaHandler,\n cacheHandler,\n handler,\n};\n"],"names":["stringSimilarity","__async"],"mappings":";;;;;;;;;;;;;;;;;;;;AAIO,SAAS,WAAA,CAAY,UAAkB,oBAAA,EAA8C;AAC1F,EAAA,OAAO;AAAA,IACL,6BAAA,EAA+B,GAAA;AAAA,IAC/B,8BAAA,EAAgC,OAAA;AAAA,IAChC,8BAAA,EAAgC;AAAA,GAClC;AACF;AAEO,SAAS,YAAY,KAAA,EAAwD;AAClF,EAAA,OAAO,cAAA,CAAA,EAAE,gBAAgB,kBAAA,EAAA,EAAuB,KAAA,CAAA;AAClD;;;;;;;;;;ECbA,MAAM,CAAC,cAAc,CAAA,OAAA,EAAU,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC7D,EAAA,OAAA,CAAA,gBAAA,GAA2B,MAAM;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACA,IAAI,gBAAgB,GAAG,UAAU,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,aAAa,EAAE;MACzE,IAAI,eAAe,KAAK,MAAM,EAAE,EAAE,eAAe,GAAG,CAAC,CAAC,CAAA;MACtD,IAAI,aAAa,KAAK,MAAM,EAAE,EAAE,aAAa,GAAG,KAAK,CAAC,CAAA;MACtD,IAAI,CAAC,aAAa,EAAE;AACxB,UAAQ,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;AACjC,UAAQ,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;AACjC,MAAA;MACI,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe;AACtE,UAAQ,OAAO,CAAC;AAChB,MAAI,IAAI,GAAG,GAAG,IAAI,GAAG,EAAE;AACvB,MAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;UAC1D,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC;UAC7C,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACrE,MAAA;MACI,IAAI,KAAK,GAAG,CAAC;AACjB,MAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;UAC1D,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC;AACrD,UAAQ,IAAI,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;AAC3D,UAAQ,IAAI,KAAK,GAAG,CAAC,EAAE;cACX,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC;AACvC,cAAY,KAAK,EAAE;AACnB,UAAA;AACA,MAAA;MACI,OAAO,CAAC,KAAK,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,eAAe,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;EAClF,CAAC;AACD,EAAA,OAAA,CAAA,gBAAA,GAA2B,gBAAgB;EAC3C,OAAA,CAAA,OAAA,GAAkB,OAAO,CAAC,gBAAgB;AAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBO,MAAM,SAAA,CAAa;AAAA,EAGxB,WAAA,CACmB,OAAA,GAAU,GAAA,EACV,GAAA,GAAM,IAAA,EACvB;AAFiB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AAJnB,IAAA,IAAA,CAAiB,KAAA,uBAAY,GAAA,EAA2C;AAAA,EAKrE;AAAA,EAEH,IAAI,GAAA,EAA4B;AAC9B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC/B,IAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,IAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,OAAA,EAAS;AAC7B,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AACrB,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAgB;AAC/B,IAAA,IAAI,KAAK,KAAA,CAAM,IAAA,IAAQ,IAAA,CAAK,OAAA,OAAc,KAAA,EAAM;AAChD,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK,EAAE,KAAA,EAAO,OAAA,EAAS,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,EAC/D;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,IAAA,GAAe;AACb,IAAA,OAAO,KAAK,KAAA,CAAM,IAAA;AAAA,EACpB;AAAA,EAEQ,KAAA,GAAc;AAGpB,IAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,IAAA,CAAK,OAAA,GAAU,GAAG,CAAC,CAAA;AACvD,IAAA,IAAI,CAAA,GAAI,CAAA;AACR,IAAA,KAAA,MAAW,GAAA,IAAO,IAAA,CAAK,KAAA,CAAM,IAAA,EAAK,EAAG;AACnC,MAAA,IAAI,OAAO,IAAA,EAAM;AACjB,MAAA,IAAA,CAAK,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IACvB;AAAA,EACF;AACF;AAIO,MAAM,eAAA,GAAkB,IAAI,SAAA,CAAiC,GAAI,CAAA;AACjE,MAAM,OAAA,GAAU,IAAI,SAAA,CAAoB,GAAG,CAAA;AAGlD,MAAM,iBAAA,GACJ,2IAAA;AAMK,MAAM,cAAA,GAAoC,sBAAA;AAEjD,MAAM,aAAA,GAAgB,gBAAA;AAEtB,MAAM,WAAA,uBAAkB,GAAA,EAAoB;AAC5C,KAAA,MAAW,CAAC,SAAA,EAAW,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,aAAa,CAAA,EAAG;AAC9D,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,EAAO,WAAA,CAAY,GAAA,CAAI,MAAM,SAAS,CAAA;AAC3D;AA8GO,SAAS,aAAA,CAAc,QAAgB,OAAA,EAAiD;AAhM/F,EAAA,IAAA,EAAA,EAAA,EAAA;AAiME,EAAA,MAAM,KAAA,GAAQ,OAAO,WAAA,EAAY;AAGjC,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,GAAA,CAAI,KAAK,CAAA;AACnC,EAAA,IAAI,OAAO,OAAO,KAAA;AAElB,EAAA,MAAM,OAAA,GAAA,CAAU,EAAA,GAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,aAAA,KAAT,IAAA,GAAA,EAAA,GAA0B,cAAA;AAC1C,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,IAAA;AAEpC,EAAA,MAAM,SAAA,GAAA,CAAY,EAAA,GAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,SAAA,KAAT,IAAA,GAAA,EAAA,GAAsB,CAAA;AACxC,EAAA,IAAI,WAAA,GAAc,QAAA;AAClB,EAAA,IAAI,UAAA,GAA4B,IAAA;AAEhC,EAAA,KAAA,MAAW,aAAa,OAAA,EAAS;AAC/B,IAAA,MAAM,cAAA,GAAiB,UAAU,WAAA,EAAY;AAC7C,IAAA,IAAI,KAAA,KAAU,gBAAgB,OAAO,IAAA;AACrC,IAAA,MAAM,UAAA,GAAaA,wCAAA,CAAiB,KAAA,EAAO,cAAc,CAAA;AACzD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAA,CAAO,CAAA,GAAI,UAAA,IAAc,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,MAAA,EAAQ,SAAA,CAAU,MAAM,CAAC,CAAA;AACxF,IAAA,IAAI,QAAA,GAAW,CAAA,IAAK,QAAA,IAAY,SAAA,IAAa,WAAW,WAAA,EAAa;AACnE,MAAA,WAAA,GAAc,QAAA;AACd,MAAA,UAAA,GAAa,SAAA;AAAA,IACf;AAAA,EACF;AACA,EAAA,OAAO,UAAA;AACT;AAOA,SAAsB,iBAAA,CACpB,OACA,OAAA,EACgC;AAAA,EAAA,OAAAC,SAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAChC,IAAA,MAAM,UAAA,GAAa,KAAA,CAAM,WAAA,EAAY,CAAE,IAAA,EAAK;AAE5C,IAAA,IAAI,EAAC,mCAAS,SAAA,CAAA,EAAW;AACvB,MAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAC7C,MAAA,IAAI,QAAQ,OAAO,MAAA;AAAA,IACrB;AAEA,IAAA,MAAM,MAAA,GAAgC,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,UAAA,EAAY,UAAA,EAAY,EAAC,EAAE;AAExF,IAAA,IAAA,CAAI,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,oBAAmB,KAAA,EAAO;AACrC,MAAA,MAAM,WAAA,GAAc,iBAAA,CAAkB,IAAA,CAAK,UAAU,CAAA;AACrD,MAAA,MAAA,CAAO,UAAA,CAAW,MAAA,GAAS,EAAE,KAAA,EAAO,WAAA,EAAY;AAChD,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,eAAA,CAAgB,GAAA,CAAI,YAAY,MAAM,CAAA;AACtC,QAAA,OAAO,MAAA;AAAA,MACT;AAAA,IACF;AAEA,IAAA,MAAM,CAAC,KAAA,EAAO,MAAM,CAAA,GAAI,UAAA,CAAW,MAAM,GAAG,CAAA;AAC5C,IAAA,MAAA,CAAO,KAAA,GAAQ,KAAA;AACf,IAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAEhB,IAAA,IAAA,CAAI,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,kBAAiB,KAAA,EAAO;AACnC,MAAA,MAAM,UAAA,GAAa,aAAA,CAAc,MAAA,EAAQ,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,sBAAsB,CAAA;AACxE,MAAA,MAAA,CAAO,UAAA,CAAW,OAAO,EAAE,KAAA,EAAO,CAAC,UAAA,EAAY,UAAA,EAAY,kCAAc,MAAA,EAAU;AAAA,IACrF;AAEA,IAAA,IAAA,CAAI,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,wBAAuB,KAAA,EAAO;AACzC,MAAA,MAAA,CAAO,UAAA,CAAW,aAAa,EAAE,KAAA,EAAO,CAAC,mBAAA,CAAoB,QAAA,CAAS,MAAM,CAAA,EAAE;AAAA,IAChF;AAEA,IAAA,IAAA,CAAI,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,kBAAiB,KAAA,EAAO;AACnC,MAAA,MAAA,CAAO,UAAA,CAAW,OAAO,EAAE,KAAA,EAAO,CAAC,aAAA,CAAc,QAAA,CAAS,MAAM,CAAA,EAAE;AAAA,IACpE;AAEA,IAAA,IAAA,CAAI,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,UAAA,KAAc,OAAA,CAAQ,WAAA,EAAa;AAC9C,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,WAAA,CAAY,UAAU,MAAM,CAAA;AAC1D,QAAA,MAAM,KAAA,GAAQ,QAAQ,MAAA,GAAS,CAAA;AAC/B,QAAA,MAAA,CAAO,WAAW,EAAA,GAAK;AAAA,UACrB,KAAA,EAAO,KAAA;AAAA,UACP,OAAA,EAAS,QAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,CAAA,GAAI,KAAA;AAAA,SACpD;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,MAAA,CAAO,WAAW,EAAA,GAAK;AAAA,UACrB,KAAA,EAAO,KAAA;AAAA,UACP,KAAA,EAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,SAClD;AAAA,MACF;AAAA,IACF;AAGA,IAAA,MAAA,CAAO,KAAA,GAAS,CAAC,QAAA,EAAU,MAAA,EAAQ,cAAc,IAAI,CAAA,CAAY,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC9E,MAAA,MAAM,SAAA,GAAY,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA;AACvC,MAAA,OAAO,CAAC,SAAA,IAAa,SAAA,CAAU,KAAA,KAAU,KAAA;AAAA,IAC3C,CAAC,CAAA;AAED,IAAA,IAAI,EAAC,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,SAAA,CAAA,EAAW,eAAA,CAAgB,GAAA,CAAI,YAAY,MAAM,CAAA;AAC/D,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA;AAAA;AAEA,SAAsB,kBAAA,CACpB,QACA,OAAA,EACkC;AAAA,EAAA,OAAAA,SAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AApSpC,IAAA,IAAA,EAAA;AAqSE,IAAA,MAAM,SAAA,GAAA,CAAY,EAAA,GAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,SAAA,KAAT,IAAA,GAAA,EAAA,GAAsB,EAAA;AACxC,IAAA,MAAM,UAAmC,EAAC;AAC1C,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,SAAA,EAAW;AACjD,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,IAAI,SAAS,CAAA;AAC3C,MAAA,MAAM,YAAA,GAAe,MAAM,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,KAAA,KAAU,iBAAA,CAAkB,KAAA,EAAO,OAAO,CAAC,CAAC,CAAA;AAC9F,MAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,YAAY,CAAA;AAAA,IAC9B;AACA,IAAA,OAAO,OAAA;AAAA,EACT,CAAA,CAAA;AAAA;AAEO,SAAS,UAAA,GAAmB;AACjC,EAAA,eAAA,CAAgB,KAAA,EAAM;AACtB,EAAA,OAAA,CAAQ,KAAA,EAAM;AAChB;;;;;;;;;;;;;;;;;;;;;;AC1SA,SAAsB,kBACpB,QAAA,EAC0D;AAAA,EAAA,OAAAA,SAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC1D,IAAA,IAAI,QAAA,CAAS,SAAS,QAAA,EAAU;AAC9B,MAAA,OAAO,iBAAA,CAAkB,QAAA,CAAS,KAAA,EAAO,QAAA,CAAS,OAAO,CAAA;AAAA,IAC3D;AACA,IAAA,OAAO,kBAAA,CAAmB,QAAA,CAAS,MAAA,EAAQ,QAAA,CAAS,OAAO,CAAA;AAAA,EAC7D,CAAA,CAAA;AAAA;;ACZO,MAAM,cAAA,GAAiB,GAAA;AA0BvB,SAAS,yBAAyB,MAAA,EAAkC;AACzE,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AACjD,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,SAAS,0BAAA,EAA2B;AAAA,EACvE;AACA,EAAA,IAAI,MAAA,CAAO,SAAS,cAAA,EAAgB;AAClC,IAAA,OAAO,EAAE,IAAI,KAAA,EAAO,MAAA,EAAQ,KAAK,OAAA,EAAS,CAAA,QAAA,EAAW,cAAc,CAAA,yBAAA,CAAA,EAA4B;AAAA,EACjG;AACA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,MAAA,EAA2B;AAChD;AAUO,SAAS,gBACd,IAAA,EACwC;AACxC,EAAA,IAAI,CAAC,IAAA,IAAS,CAAC,KAAK,KAAA,IAAS,CAAC,KAAK,MAAA,EAAS;AAC1C,IAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,GAAA,EAAK,SAAS,mCAAA,EAAoC;AAAA,EACtF;AACA,EAAA,IAAI,KAAK,MAAA,EAAQ;AACf,IAAA,IAAI,CAAC,MAAM,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,IAAK,IAAA,CAAK,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG;AAC3D,MAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,GAAA,EAAK,SAAS,0BAAA,EAA2B;AAAA,IAC7E;AACA,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,MAAA,GAAS,cAAA,EAAgB;AACvC,MAAA,OAAO,EAAE,MAAM,SAAA,EAAW,MAAA,EAAQ,KAAK,OAAA,EAAS,CAAA,QAAA,EAAW,cAAc,CAAA,yBAAA,CAAA,EAA4B;AAAA,IACvG;AACA,IAAA,OAAO,EAAE,MAAM,OAAA,EAAS,MAAA,EAAQ,KAAK,MAAA,EAAQ,OAAA,EAAS,KAAK,OAAA,EAAQ;AAAA,EACrE;AAEA,EAAA,IAAI,CAAC,KAAK,KAAA,EAAO;AACf,IAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,GAAA,EAAK,SAAS,mCAAA,EAAoC;AAAA,EACtF;AACA,EAAA,OAAO,EAAE,MAAM,QAAA,EAAU,KAAA,EAAO,KAAK,KAAA,EAAO,OAAA,EAAS,KAAK,OAAA,EAAQ;AACpE;;;;;;;;;;;;;;;;;;;;;;ACXA,MAAM,YAAA,GAAe,WAAA,CAAY,WAAA,CAAY,eAAe,CAAC,CAAA;AAC7D,MAAM,cAAA,GAAiB,WAAA,CAAY,WAAA,EAAa,CAAA;AAEhD,SAAS,YAAA,CAAa,UAAA,EAAoB,IAAA,EAAe,OAAA,EAAwD;AAC/G,EAAA,OAAO,EAAE,UAAA,EAAY,OAAA,EAAS,MAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAE;AAC3D;AAGA,SAAsB,iBAAA,CACpB,OACA,QAAA,EACgC;AAAA,EAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAChC,IAAA,IAAI,KAAA,CAAM,eAAe,SAAA,EAAW;AAClC,MAAA,OAAO,EAAE,YAAY,GAAA,EAAK,OAAA,EAAS,YAAY,eAAe,CAAA,EAAG,MAAM,EAAA,EAAG;AAAA,IAC5E;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAiC,MAAM,IAAA,GAAO,IAAA,CAAK,MAAM,KAAA,CAAM,IAAI,IAAI,EAAC;AAC9E,MAAA,MAAM,UAAA,GAAa,gBAAgB,OAAO,CAAA;AAC1C,MAAA,IAAI,UAAA,CAAW,SAAS,SAAA,EAAW;AACjC,QAAA,OAAO,YAAA,CAAa,UAAA,CAAW,MAAA,EAAQ,EAAE,OAAA,EAAS,OAAO,KAAA,EAAO,UAAA,CAAW,OAAA,EAAQ,EAAG,YAAY,CAAA;AAAA,MACpG;AACA,MAAA,MAAM,IAAA,GAAO,MAAM,iBAAA,CAAkB,UAAU,CAAA;AAC/C,MAAA,OAAO,aAAa,GAAA,EAAK,EAAE,SAAS,IAAA,EAAM,IAAA,IAAQ,YAAY,CAAA;AAAA,IAChE,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,iBAAiB,KAAK,CAAA;AACpC,MAAA,MAAM,OAAA,GAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,uBAAA;AACzD,MAAA,OAAO,YAAA,CAAa,KAAK,EAAE,OAAA,EAAS,OAAO,KAAA,EAAO,OAAA,IAAW,YAAY,CAAA;AAAA,IAC3E;AAAA,EACF,CAAA,CAAA;AAAA;AAGA,SAAsB,aAAA,CAAc,OAA8B,QAAA,EAAoD;AAAA,EAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AACpH,IAAA,IAAI;AACF,MAAA,MAAM,UAAA,GAAa,gBAAgB,KAAK,CAAA;AACxC,MAAA,IAAI,UAAA,CAAW,SAAS,SAAA,EAAW;AACjC,QAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,WAAW,OAAA,EAAQ;AAAA,MACrD;AACA,MAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,MAAM,MAAM,iBAAA,CAAkB,UAAU,CAAA,EAAE;AAAA,IACpE,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,iBAAiB,KAAK,CAAA;AACpC,MAAA,OAAO,EAAE,SAAS,KAAA,EAAO,KAAA,EAAO,iBAAiB,KAAA,GAAQ,KAAA,CAAM,UAAU,uBAAA,EAAwB;AAAA,IACnG;AAAA,EACF,CAAA,CAAA;AAAA;AAGA,SAAsB,YAAA,CACpB,OACA,QAAA,EACkE;AAAA,EAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAClE,IAAA,QAAQ,MAAM,MAAA;AAAQ,MACpB,KAAK,OAAA;AACH,QAAA,UAAA,EAAW;AACX,QAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,eAAA,EAAgB;AAAA,MACnD,KAAK,OAAA;AACH,QAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,6BAAA,EAA8B;AAAA,MACjE;AACE,QAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,gBAAA,EAAiB;AAAA;AACvD,EACF,CAAA,CAAA;AAAA;AAGA,SAAS,WAAW,KAAA,EAAsC;AACxD,EAAA,IAAI,CAAC,KAAA,CAAM,IAAA,EAAM,OAAO,EAAC;AACzB,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,eAAA,GAAkB,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,IAAA,EAAM,QAAQ,CAAA,CAAE,QAAA,CAAS,OAAO,CAAA,GAAI,KAAA,CAAM,IAAA;AAChG,EAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AACvB;AAKA,SAAsB,OAAA,CAAQ,OAA6B,QAAA,EAAoD;AAAA,EAAA,OAAA,OAAA,CAAA,IAAA,EAAA,IAAA,EAAA,aAAA;AAC7G,IAAA,IAAI,KAAA,CAAM,eAAe,SAAA,EAAW;AAClC,MAAA,OAAO,EAAE,UAAA,EAAY,GAAA,EAAK,SAAS,WAAA,EAAY,EAAG,MAAM,EAAA,EAAG;AAAA,IAC7D;AAEA,IAAA,IAAI,KAAA,CAAM,IAAA,KAAS,SAAA,IAAa,KAAA,CAAM,eAAe,KAAA,EAAO;AAC1D,MAAA,OAAO,YAAA,CAAa,GAAA,EAAK,EAAE,MAAA,EAAQ,SAAA,EAAW,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAE,EAAG,cAAc,CAAA;AAAA,IACrG;AAEA,IAAA,MAAM,cAAA,GAAiB,KAAA,CAAM,IAAA,KAAS,WAAA,IAAe,MAAM,IAAA,KAAS,iBAAA;AACpE,IAAA,IAAI,cAAA,IAAkB,KAAA,CAAM,UAAA,KAAe,MAAA,EAAQ;AACjD,MAAA,OAAO,aAAa,GAAA,EAAK,EAAE,KAAA,EAAO,oBAAA,IAAwB,cAAc,CAAA;AAAA,IAC1E;AAEA,IAAA,IAAI,KAAA,CAAM,IAAA,KAAS,WAAA,IAAe,KAAA,CAAM,eAAe,MAAA,EAAQ;AAC7D,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,WAAW,KAAK,CAAA;AAC7B,QAAA,IAAI,CAAC,IAAA,CAAK,KAAA,EAAO,OAAO,YAAA,CAAa,KAAK,EAAE,KAAA,EAAO,mBAAA,EAAoB,EAAG,cAAc,CAAA;AAExF,QAAA,MAAM,OAAA,GAAU,oBAAA,CAAqB,KAAA,CAAM,qBAAqB,CAAA;AAChE,QAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,IAAA,CAAK,OAAO,OAAO,CAAA;AAC1D,QAAA,OAAO,YAAA,CAAa,GAAA,EAAK,MAAA,EAAQ,cAAc,CAAA;AAAA,MACjD,SAAS,KAAA,EAAO;AACd,QAAA,IAAI,iBAAiB,WAAA,EAAa;AAChC,UAAA,OAAO,aAAa,GAAA,EAAK,EAAE,KAAA,EAAO,sBAAA,IAA0B,cAAc,CAAA;AAAA,QAC5E;AACA,QAAA,OAAA,CAAQ,KAAA,CAAM,qBAAqB,KAAK,CAAA;AACxC,QAAA,OAAO,aAAa,GAAA,EAAK,EAAE,KAAA,EAAO,uBAAA,IAA2B,cAAc,CAAA;AAAA,MAC7E;AAAA,IACF;AAEA,IAAA,IAAI,KAAA,CAAM,IAAA,KAAS,iBAAA,IAAqB,KAAA,CAAM,eAAe,MAAA,EAAQ;AACnE,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,WAAW,KAAK,CAAA;AAC7B,QAAA,MAAM,SAAA,GAAY,wBAAA,CAAyB,IAAA,CAAK,MAAM,CAAA;AACtD,QAAA,IAAI,CAAC,SAAA,CAAU,EAAA,EAAI,OAAO,YAAA,CAAa,SAAA,CAAU,MAAA,EAAQ,EAAE,KAAA,EAAO,SAAA,CAAU,OAAA,EAAQ,EAAG,cAAc,CAAA;AACrG,QAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,EAAE,MAAM,OAAA,EAAS,MAAA,EAAQ,SAAA,CAAU,MAAA,EAAQ,CAAA;AACnF,QAAA,OAAO,YAAA,CAAa,GAAA,EAAK,EAAE,OAAA,IAAW,cAAc,CAAA;AAAA,MACtD,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,2BAA2B,KAAK,CAAA;AAC9C,QAAA,OAAO,aAAa,GAAA,EAAK,EAAE,KAAA,EAAO,uBAAA,IAA2B,cAAc,CAAA;AAAA,MAC7E;AAAA,IACF;AAEA,IAAA,OAAO,aAAa,GAAA,EAAK,EAAE,KAAA,EAAO,WAAA,IAAe,cAAc,CAAA;AAAA,EACjE,CAAA,CAAA;AAAA;AAEA,SAAS,qBAAqB,KAAA,EAAoF;AAChH,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AACpB,EAAA,MAAM,UAAyC,EAAC;AAChD,EAAA,IAAI,KAAA,CAAM,SAAA,KAAc,MAAA,EAAQ,OAAA,CAAQ,SAAA,GAAY,IAAA;AACpD,EAAA,IAAI,KAAA,CAAM,YAAA,KAAiB,OAAA,EAAS,OAAA,CAAQ,YAAA,GAAe,KAAA;AAC3D,EAAA,OAAO,OAAA;AACT;AAEA,gBAAe;AAAA,EACb,iBAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA;;;;;;;;","x_google_ignoreList":[1]}
|
|
@@ -32,9 +32,9 @@ var hasRequiredStringSimilarity;
|
|
|
32
32
|
function requireStringSimilarity () {
|
|
33
33
|
if (hasRequiredStringSimilarity) return stringSimilarity;
|
|
34
34
|
hasRequiredStringSimilarity = 1;
|
|
35
|
-
(function (exports
|
|
36
|
-
Object.defineProperty(exports
|
|
37
|
-
exports
|
|
35
|
+
(function (exports) {
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.stringSimilarity = void 0;
|
|
38
38
|
/* global exports, Map */
|
|
39
39
|
/**
|
|
40
40
|
* Calculate similarity between two strings
|
|
@@ -69,8 +69,8 @@ function requireStringSimilarity () {
|
|
|
69
69
|
}
|
|
70
70
|
return (match * 2) / (str1.length + str2.length - ((substringLength - 1) * 2));
|
|
71
71
|
};
|
|
72
|
-
exports
|
|
73
|
-
exports
|
|
72
|
+
exports.stringSimilarity = stringSimilarity;
|
|
73
|
+
exports.default = exports.stringSimilarity;
|
|
74
74
|
|
|
75
75
|
} (stringSimilarity));
|
|
76
76
|
return stringSimilarity;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws-lambda.esm.js","sources":["../../../src/serverless/_shared/cors.ts","../../../node_modules/string-similarity-js/dist/string-similarity.js","../../../src/serverless/verifier.ts","../../../src/serverless/_shared/dispatch.ts","../../../src/serverless/_shared/validation.ts","../../../src/serverless/adapters/aws-lambda.ts"],"sourcesContent":["/**\n * Standard CORS header set used by every adapter. `methods` lets each platform\n * advertise the verbs it actually supports without re-declaring the rest.\n */\nexport function corsHeaders(methods: string = 'GET, POST, OPTIONS'): Record<string, string> {\n return {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': methods,\n 'Access-Control-Allow-Headers': 'Content-Type',\n };\n}\n\nexport function jsonHeaders(extra?: Record<string, string>): Record<string, string> {\n return { 'Content-Type': 'application/json', ...extra };\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.stringSimilarity = void 0;\n/* global exports, Map */\n/**\n * Calculate similarity between two strings\n * @param {string} str1 First string to match\n * @param {string} str2 Second string to match\n * @param {number} [substringLength=2] Optional. Length of substring to be used in calculating similarity. Default 2.\n * @param {boolean} [caseSensitive=false] Optional. Whether you want to consider case in string matching. Default false;\n * @returns Number between 0 and 1, with 0 being a low match score.\n */\nvar stringSimilarity = function (str1, str2, substringLength, caseSensitive) {\n if (substringLength === void 0) { substringLength = 2; }\n if (caseSensitive === void 0) { caseSensitive = false; }\n if (!caseSensitive) {\n str1 = str1.toLowerCase();\n str2 = str2.toLowerCase();\n }\n if (str1.length < substringLength || str2.length < substringLength)\n return 0;\n var map = new Map();\n for (var i = 0; i < str1.length - (substringLength - 1); i++) {\n var substr1 = str1.substr(i, substringLength);\n map.set(substr1, map.has(substr1) ? map.get(substr1) + 1 : 1);\n }\n var match = 0;\n for (var j = 0; j < str2.length - (substringLength - 1); j++) {\n var substr2 = str2.substr(j, substringLength);\n var count = map.has(substr2) ? map.get(substr2) : 0;\n if (count > 0) {\n map.set(substr2, count - 1);\n match++;\n }\n }\n return (match * 2) / (str1.length + str2.length - ((substringLength - 1) * 2));\n};\nexports.stringSimilarity = stringSimilarity;\nexports.default = exports.stringSimilarity;\n//# sourceMappingURL=string-similarity.js.map","/**\n * Edge-runtime / serverless email validator.\n *\n * No Node.js APIs (no `node:net`, no `node:dns`) — DNS is delegated to a\n * caller-supplied `DNSResolver`, so the same code runs on Cloudflare Workers,\n * Vercel Edge, Lambda@Edge, and Deno Deploy.\n *\n * Shares data with the main validator: `commonEmailDomains` and the typo map\n * are imported from `src/data/`, so we never drift between the two surfaces.\n */\n\nimport { stringSimilarity } from 'string-similarity-js';\nimport commonEmailDomainsJson from '../data/common-email-domains.json';\nimport typoPatternsJson from '../data/typo-patterns.json';\nimport disposableProviders from '../disposable-email-providers.json';\nimport freeProviders from '../free-email-providers.json';\nimport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n\n/** Compact LRU/TTL cache. One Map, expiry stamp per entry, batched eviction. */\nexport class EdgeCache<T> {\n private readonly cache = new Map<string, { value: T; expires: number }>();\n\n constructor(\n private readonly maxSize = 1000,\n private readonly ttl = 3_600_000\n ) {}\n\n get(key: string): T | undefined {\n const item = this.cache.get(key);\n if (!item) return undefined;\n if (Date.now() > item.expires) {\n this.cache.delete(key);\n return undefined;\n }\n return item.value;\n }\n\n set(key: string, value: T): void {\n if (this.cache.size >= this.maxSize) this.evict();\n this.cache.set(key, { value, expires: Date.now() + this.ttl });\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n size(): number {\n return this.cache.size;\n }\n\n private evict(): void {\n // Drop the oldest 10% in one pass — Map preserves insertion order so\n // `keys()` walks oldest-first.\n const drop = Math.max(1, Math.floor(this.maxSize * 0.1));\n let n = 0;\n for (const key of this.cache.keys()) {\n if (n++ >= drop) break;\n this.cache.delete(key);\n }\n }\n}\n\n// Module-level per-isolate caches. Edge runtimes get cold-start fresh; warm\n// invocations benefit from the in-memory hits.\nexport const validationCache = new EdgeCache<EmailValidationResult>(1000);\nexport const mxCache = new EdgeCache<string[]>(500);\n\n/** Same regex the main validator uses — kept inline because edge runtimes don't auto-resolve psl. */\nconst VALID_EMAIL_REGEX =\n /^(([a-zA-Z0-9_+'-]+(\\.[a-zA-Z0-9_+'-]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}))$/;\n\n/**\n * Common email domains — re-exported so callers (Vercel Edge, etc.) can pass a\n * custom subset via `DomainSuggesterOptions.customDomains`.\n */\nexport const COMMON_DOMAINS: readonly string[] = commonEmailDomainsJson as string[];\n\nconst TYPO_PATTERNS = typoPatternsJson as Record<string, string[]>;\n/** Reverse index for O(1) typo → canonical lookup. */\nconst TYPO_LOOKUP = new Map<string, string>();\nfor (const [canonical, typos] of Object.entries(TYPO_PATTERNS)) {\n for (const typo of typos) TYPO_LOOKUP.set(typo, canonical);\n}\n\n/** DNS resolver contract — caller-supplied so we don't import `node:dns`. */\nexport interface DNSResolver {\n resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>>;\n resolveTxt(domain: string): Promise<string[]>;\n}\n\n/** No-op resolver for environments where DNS isn't available. */\nexport class StubDNSResolver implements DNSResolver {\n async resolveMx(): Promise<Array<{ exchange: string; priority: number }>> {\n return [];\n }\n async resolveTxt(): Promise<string[]> {\n return [];\n }\n}\n\n/**\n * DNS-over-HTTPS resolver — works in any runtime with `fetch` (Cloudflare\n * Workers, Vercel Edge, Deno, browsers, Node 18+). Defaults to Cloudflare's\n * 1.1.1.1 endpoint; pass `endpoint` to use Google (8.8.8.8), NextDNS, or\n * a self-hosted resolver.\n *\n * Compatible with [`cf-doh`](https://www.npmjs.com/package/cf-doh) — if you\n * already use that, drop it in directly. This built-in keeps the package\n * zero-dep so the same code works on every edge runtime without an extra\n * install step.\n */\nexport interface DoHResolverOptions {\n /** DoH endpoint URL. Default: https://cloudflare-dns.com/dns-query */\n endpoint?: string;\n /** Per-query request timeout, ms. Default: 5000 */\n timeoutMs?: number;\n /** Custom fetch (e.g. to add headers / proxy). Default: globalThis.fetch */\n fetch?: typeof fetch;\n}\n\ninterface DoHAnswer {\n name: string;\n type: number;\n TTL: number;\n data: string;\n}\n\ninterface DoHResponse {\n Status: number;\n Answer?: DoHAnswer[];\n}\n\nconst DOH_RECORD_TYPE = { MX: 15, TXT: 16 } as const;\n\nexport class DoHResolver implements DNSResolver {\n private readonly endpoint: string;\n private readonly timeoutMs: number;\n private readonly fetchFn: typeof fetch;\n\n constructor(options: DoHResolverOptions = {}) {\n this.endpoint = options.endpoint ?? 'https://cloudflare-dns.com/dns-query';\n this.timeoutMs = options.timeoutMs ?? 5000;\n this.fetchFn = options.fetch ?? globalThis.fetch;\n }\n\n async resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>> {\n const records = await this.query(domain, DOH_RECORD_TYPE.MX);\n if (!records) return [];\n return records\n .map((answer) => {\n // MX answer data: \"<priority> <exchange>\" (with optional trailing dot).\n const match = answer.data.match(/^(\\d+)\\s+(.+?)\\.?$/);\n if (!match) return null;\n return { priority: Number(match[1]), exchange: match[2] as string };\n })\n .filter((r): r is { exchange: string; priority: number } => r !== null)\n .sort((a, b) => a.priority - b.priority);\n }\n\n async resolveTxt(domain: string): Promise<string[]> {\n const records = await this.query(domain, DOH_RECORD_TYPE.TXT);\n if (!records) return [];\n // TXT answers come back as quoted strings — strip the surrounding quotes.\n return records.map((answer) => answer.data.replace(/^\"(.*)\"$/, '$1'));\n }\n\n private async query(domain: string, type: number): Promise<DoHAnswer[] | null> {\n const url = `${this.endpoint}?name=${encodeURIComponent(domain)}&type=${type}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const response = await this.fetchFn(url, {\n headers: { Accept: 'application/dns-json' },\n signal: controller.signal,\n });\n if (!response.ok) return null;\n const json = (await response.json()) as DoHResponse;\n // Status 0 = NOERROR. Anything else (NXDOMAIN, SERVFAIL, etc.) → no answers.\n if (json.Status !== 0) return [];\n return json.Answer ?? [];\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n/**\n * Suggest a corrected domain. Returns the canonical for a known typo,\n * otherwise the closest match within the threshold, otherwise null.\n */\nexport function suggestDomain(domain: string, options?: DomainSuggesterOptions): string | null {\n const lower = domain.toLowerCase();\n\n // Hand-curated typo map first — beats similarity for common cases.\n const known = TYPO_LOOKUP.get(lower);\n if (known) return known;\n\n const domains = options?.customDomains ?? COMMON_DOMAINS;\n if (domains.includes(lower)) return null;\n\n const threshold = options?.threshold ?? 2;\n let minDistance = Infinity;\n let suggestion: string | null = null;\n\n for (const candidate of domains) {\n const candidateLower = candidate.toLowerCase();\n if (lower === candidateLower) return null;\n const similarity = stringSimilarity(lower, candidateLower);\n const distance = Math.round((1 - similarity) * Math.max(domain.length, candidate.length));\n if (distance > 0 && distance <= threshold && distance < minDistance) {\n minDistance = distance;\n suggestion = candidate;\n }\n }\n return suggestion;\n}\n\n/**\n * Validate one email — syntax / typo / disposable / free / MX (if a resolver\n * is supplied). Each step is independently flag-gated so callers pay only for\n * what they use.\n */\nexport async function validateEmailCore(\n email: string,\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult> {\n const normalized = email.toLowerCase().trim();\n\n if (!options?.skipCache) {\n const cached = validationCache.get(normalized);\n if (cached) return cached;\n }\n\n const result: EmailValidationResult = { valid: false, email: normalized, validators: {} };\n\n if (options?.validateSyntax !== false) {\n const syntaxValid = VALID_EMAIL_REGEX.test(normalized);\n result.validators.syntax = { valid: syntaxValid };\n if (!syntaxValid) {\n validationCache.set(normalized, result);\n return result;\n }\n }\n\n const [local, domain] = normalized.split('@');\n result.local = local;\n result.domain = domain;\n\n if (options?.validateTypo !== false) {\n const suggestion = suggestDomain(domain, options?.domainSuggesterOptions);\n result.validators.typo = { valid: !suggestion, suggestion: suggestion ?? undefined };\n }\n\n if (options?.validateDisposable !== false) {\n result.validators.disposable = { valid: !disposableProviders.includes(domain) };\n }\n\n if (options?.validateFree !== false) {\n result.validators.free = { valid: !freeProviders.includes(domain) };\n }\n\n if (options?.validateMx && options.dnsResolver) {\n try {\n const records = await options.dnsResolver.resolveMx(domain);\n const hasMx = records.length > 0;\n result.validators.mx = {\n valid: hasMx,\n records: hasMx ? records.map((r) => r.exchange) : undefined,\n };\n } catch (error) {\n result.validators.mx = {\n valid: false,\n error: error instanceof Error ? error.message : 'MX validation failed',\n };\n }\n }\n\n // Free-provider detection is informational; only the hard validators gate validity.\n result.valid = (['syntax', 'typo', 'disposable', 'mx'] as const).every((key) => {\n const validator = result.validators[key];\n return !validator || validator.valid !== false;\n });\n\n if (!options?.skipCache) validationCache.set(normalized, result);\n return result;\n}\n\nexport async function validateEmailBatch(\n emails: string[],\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult[]> {\n const chunkSize = options?.batchSize ?? 10;\n const results: EmailValidationResult[] = [];\n for (let i = 0; i < emails.length; i += chunkSize) {\n const chunk = emails.slice(i, i + chunkSize);\n const chunkResults = await Promise.all(chunk.map((email) => validateEmailCore(email, options)));\n results.push(...chunkResults);\n }\n return results;\n}\n\nexport function clearCache(): void {\n validationCache.clear();\n mxCache.clear();\n}\n\nexport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n","import type { EmailValidationResult } from '../../types';\nimport { validateEmailBatch, validateEmailCore } from '../verifier';\nimport type { ValidationDispatch } from './validation';\n\n/**\n * Execute a classified request against the core validator. Single-email\n * requests yield one result; batch requests yield an array.\n */\nexport async function executeValidation(\n dispatch: ValidationDispatch\n): Promise<EmailValidationResult | EmailValidationResult[]> {\n if (dispatch.kind === 'single') {\n return validateEmailCore(dispatch.email, dispatch.options);\n }\n return validateEmailBatch(dispatch.emails, dispatch.options);\n}\n","import type { ValidateEmailOptions } from '../../types';\n\n/** Hard limit on batch size enforced by every adapter. */\nexport const MAX_BATCH_SIZE = 100;\n\n/** Shape of POST bodies and Lambda invocations across all serverless adapters. */\nexport interface ValidationRequestBody {\n email?: string;\n emails?: string[];\n options?: ValidateEmailOptions;\n}\n\nexport type ValidationDispatch =\n | { kind: 'single'; email: string; options?: ValidateEmailOptions }\n | { kind: 'batch'; emails: string[]; options?: ValidateEmailOptions };\n\nexport interface ValidationFailure {\n kind: 'invalid';\n status: 400;\n message: string;\n}\n\n/**\n * Validation for endpoints that accept ONLY a batch (`emails`). Returns\n * a 400 failure if emails is missing/empty/oversized, or null when valid.\n * Routed `/validate/batch` paths use this so error messages stay batch-specific.\n */\nexport type BatchValidation = { ok: true; emails: string[] } | { ok: false; status: 400; message: string };\n\nexport function validateBatchEmailsField(emails: unknown): BatchValidation {\n if (!Array.isArray(emails) || emails.length === 0) {\n return { ok: false, status: 400, message: 'Emails array is required' };\n }\n if (emails.length > MAX_BATCH_SIZE) {\n return { ok: false, status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { ok: true, emails: emails as string[] };\n}\n\n/**\n * Apply the rules every serverless adapter shares:\n * 1. body must request either `email` or `emails`\n * 2. `emails` must be a non-empty array of ≤ MAX_BATCH_SIZE entries\n *\n * Centralising this means a future rule change (say, raising the cap) lands\n * in one place instead of three.\n */\nexport function classifyRequest(\n body: ValidationRequestBody | null | undefined\n): ValidationDispatch | ValidationFailure {\n if (!body || (!body.email && !body.emails)) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n if (body.emails) {\n if (!Array.isArray(body.emails) || body.emails.length === 0) {\n return { kind: 'invalid', status: 400, message: 'Emails array is required' };\n }\n if (body.emails.length > MAX_BATCH_SIZE) {\n return { kind: 'invalid', status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { kind: 'batch', emails: body.emails, options: body.options };\n }\n // body.email must be set per the first guard (which checks both fields).\n if (!body.email) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n return { kind: 'single', email: body.email, options: body.options };\n}\n","/**\n * AWS Lambda adapter — three handler shapes for three deploy modes:\n *\n * - `handler` — routed (recommended) — `/health`, `/validate`,\n * `/validate/batch`. Wire to API Gateway with\n * `{proxy+}` so all three paths land on one Lambda.\n * - `apiGatewayHandler` — single-route — accepts API Gateway proxy events\n * but never inspects `event.path`. Pick this when\n * you want one Lambda per URL.\n * - `lambdaHandler` — direct invocation — no API Gateway envelope.\n * Pick this when calling from another AWS service\n * (Step Functions, EventBridge, …).\n *\n * Shared validation rules + CORS headers come from `../_shared/` so all three\n * agree on what's accepted.\n */\nimport type { ValidateEmailOptions } from '../../types';\nimport { corsHeaders, jsonHeaders } from '../_shared/cors';\nimport { executeValidation } from '../_shared/dispatch';\nimport { classifyRequest, type ValidationRequestBody, validateBatchEmailsField } from '../_shared/validation';\nimport { clearCache, validateEmailCore } from '../verifier';\n\n/**\n * Loose API-Gateway event/result/context shapes — `headers` and similar maps\n * intentionally widen to `string | undefined` so they line up with the\n * official `@types/aws-lambda` definitions used by callers/tests.\n */\nexport interface APIGatewayProxyEvent {\n body: string | null;\n headers: { [key: string]: string | undefined };\n httpMethod: string;\n path: string;\n queryStringParameters: { [key: string]: string | undefined } | null;\n pathParameters: { [key: string]: string | undefined } | null;\n isBase64Encoded?: boolean;\n}\n\nexport interface APIGatewayProxyResult {\n statusCode: number;\n headers?: { [key: string]: string };\n body: string;\n}\n\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n awsRequestId: string;\n remainingTimeInMillis: number;\n}\n\ninterface ValidateResponse {\n success: boolean;\n data?: unknown;\n error?: string;\n}\n\nconst POST_HEADERS = jsonHeaders(corsHeaders('POST, OPTIONS'));\nconst ROUTED_HEADERS = jsonHeaders(corsHeaders());\n\nfunction jsonResponse(statusCode: number, body: unknown, headers: Record<string, string>): APIGatewayProxyResult {\n return { statusCode, headers, body: JSON.stringify(body) };\n}\n\n// Single-route API Gateway handler — accepts proxy events but doesn't inspect `event.path`.\nexport async function apiGatewayHandler(\n event: APIGatewayProxyEvent,\n _context: LambdaContext\n): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 200, headers: corsHeaders('POST, OPTIONS'), body: '' };\n }\n\n try {\n const request: ValidationRequestBody = event.body ? JSON.parse(event.body) : {};\n const classified = classifyRequest(request);\n if (classified.kind === 'invalid') {\n return jsonResponse(classified.status, { success: false, error: classified.message }, POST_HEADERS);\n }\n const data = await executeValidation(classified);\n return jsonResponse(200, { success: true, data }, POST_HEADERS);\n } catch (error) {\n console.error('Lambda error:', error);\n const message = error instanceof Error ? error.message : 'Internal server error';\n return jsonResponse(500, { success: false, error: message }, POST_HEADERS);\n }\n}\n\n// Direct Lambda handler (no API Gateway envelope).\nexport async function lambdaHandler(event: ValidationRequestBody, _context: LambdaContext): Promise<ValidateResponse> {\n try {\n const classified = classifyRequest(event);\n if (classified.kind === 'invalid') {\n return { success: false, error: classified.message };\n }\n return { success: true, data: await executeValidation(classified) };\n } catch (error) {\n console.error('Lambda error:', error);\n return { success: false, error: error instanceof Error ? error.message : 'Internal server error' };\n }\n}\n\n// Cache management handler.\nexport async function cacheHandler(\n event: { action: 'clear' | 'stats' },\n _context: LambdaContext\n): Promise<{ success: boolean; message?: string; stats?: unknown }> {\n switch (event.action) {\n case 'clear':\n clearCache();\n return { success: true, message: 'Cache cleared' };\n case 'stats':\n return { success: true, message: 'Cache stats not implemented' };\n default:\n return { success: false, message: 'Invalid action' };\n }\n}\n\n/** Decode the API Gateway body, supporting base64-encoded payloads. */\nfunction decodeBody(event: APIGatewayProxyEvent): unknown {\n if (!event.body) return {};\n const raw = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString('utf-8') : event.body;\n return JSON.parse(raw);\n}\n\n// Routed handler — supports /health, /validate, /validate/batch. The context\n// argument is intentionally `unknown` so callers can pass either our minimal\n// LambdaContext or the official `aws-lambda#Context` without a cast.\nexport async function handler(event: APIGatewayProxyEvent, _context?: unknown): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 204, headers: corsHeaders(), body: '' };\n }\n\n if (event.path === '/health' && event.httpMethod === 'GET') {\n return jsonResponse(200, { status: 'healthy', timestamp: new Date().toISOString() }, ROUTED_HEADERS);\n }\n\n const isValidatePath = event.path === '/validate' || event.path === '/validate/batch';\n if (isValidatePath && event.httpMethod !== 'POST') {\n return jsonResponse(405, { error: 'Method not allowed' }, ROUTED_HEADERS);\n }\n\n if (event.path === '/validate' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as { email?: string };\n if (!body.email) return jsonResponse(400, { error: 'Email is required' }, ROUTED_HEADERS);\n\n const options = parseValidateOptions(event.queryStringParameters);\n const result = await validateEmailCore(body.email, options);\n return jsonResponse(200, result, ROUTED_HEADERS);\n } catch (error) {\n if (error instanceof SyntaxError) {\n return jsonResponse(400, { error: 'Invalid request body' }, ROUTED_HEADERS);\n }\n console.error('Validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n if (event.path === '/validate/batch' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as ValidationRequestBody;\n const validated = validateBatchEmailsField(body.emails);\n if (!validated.ok) return jsonResponse(validated.status, { error: validated.message }, ROUTED_HEADERS);\n const results = await executeValidation({ kind: 'batch', emails: validated.emails });\n return jsonResponse(200, { results }, ROUTED_HEADERS);\n } catch (error) {\n console.error('Batch validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n return jsonResponse(404, { error: 'Not found' }, ROUTED_HEADERS);\n}\n\nfunction parseValidateOptions(query: { [key: string]: string | undefined } | null): Partial<ValidateEmailOptions> {\n if (!query) return {};\n const options: Partial<ValidateEmailOptions> = {};\n if (query.skipCache === 'true') options.skipCache = true;\n if (query.validateTypo === 'false') options.validateTypo = false;\n return options;\n}\n\nexport default {\n apiGatewayHandler,\n lambdaHandler,\n cacheHandler,\n handler,\n};\n"],"names":["exports","stringSimilarity","__async"],"mappings":"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","x_google_ignoreList":[1]}
|
|
1
|
+
{"version":3,"file":"aws-lambda.esm.js","sources":["../../../src/serverless/_shared/cors.ts","../../../node_modules/string-similarity-js/dist/string-similarity.js","../../../src/serverless/verifier.ts","../../../src/serverless/_shared/dispatch.ts","../../../src/serverless/_shared/validation.ts","../../../src/serverless/adapters/aws-lambda.ts"],"sourcesContent":["/**\n * Standard CORS header set used by every adapter. `methods` lets each platform\n * advertise the verbs it actually supports without re-declaring the rest.\n */\nexport function corsHeaders(methods: string = 'GET, POST, OPTIONS'): Record<string, string> {\n return {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': methods,\n 'Access-Control-Allow-Headers': 'Content-Type',\n };\n}\n\nexport function jsonHeaders(extra?: Record<string, string>): Record<string, string> {\n return { 'Content-Type': 'application/json', ...extra };\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.stringSimilarity = void 0;\n/* global exports, Map */\n/**\n * Calculate similarity between two strings\n * @param {string} str1 First string to match\n * @param {string} str2 Second string to match\n * @param {number} [substringLength=2] Optional. Length of substring to be used in calculating similarity. Default 2.\n * @param {boolean} [caseSensitive=false] Optional. Whether you want to consider case in string matching. Default false;\n * @returns Number between 0 and 1, with 0 being a low match score.\n */\nvar stringSimilarity = function (str1, str2, substringLength, caseSensitive) {\n if (substringLength === void 0) { substringLength = 2; }\n if (caseSensitive === void 0) { caseSensitive = false; }\n if (!caseSensitive) {\n str1 = str1.toLowerCase();\n str2 = str2.toLowerCase();\n }\n if (str1.length < substringLength || str2.length < substringLength)\n return 0;\n var map = new Map();\n for (var i = 0; i < str1.length - (substringLength - 1); i++) {\n var substr1 = str1.substr(i, substringLength);\n map.set(substr1, map.has(substr1) ? map.get(substr1) + 1 : 1);\n }\n var match = 0;\n for (var j = 0; j < str2.length - (substringLength - 1); j++) {\n var substr2 = str2.substr(j, substringLength);\n var count = map.has(substr2) ? map.get(substr2) : 0;\n if (count > 0) {\n map.set(substr2, count - 1);\n match++;\n }\n }\n return (match * 2) / (str1.length + str2.length - ((substringLength - 1) * 2));\n};\nexports.stringSimilarity = stringSimilarity;\nexports.default = exports.stringSimilarity;\n//# sourceMappingURL=string-similarity.js.map","/**\n * Edge-runtime / serverless email validator.\n *\n * No Node.js APIs (no `node:net`, no `node:dns`) — DNS is delegated to a\n * caller-supplied `DNSResolver`, so the same code runs on Cloudflare Workers,\n * Vercel Edge, Lambda@Edge, and Deno Deploy.\n *\n * Shares data with the main validator: `commonEmailDomains` and the typo map\n * are imported from `src/data/`, so we never drift between the two surfaces.\n */\n\nimport { stringSimilarity } from 'string-similarity-js';\nimport commonEmailDomainsJson from '../data/common-email-domains.json';\nimport typoPatternsJson from '../data/typo-patterns.json';\nimport disposableProviders from '../disposable-email-providers.json';\nimport freeProviders from '../free-email-providers.json';\nimport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n\n/** Compact LRU/TTL cache. One Map, expiry stamp per entry, batched eviction. */\nexport class EdgeCache<T> {\n private readonly cache = new Map<string, { value: T; expires: number }>();\n\n constructor(\n private readonly maxSize = 1000,\n private readonly ttl = 3_600_000\n ) {}\n\n get(key: string): T | undefined {\n const item = this.cache.get(key);\n if (!item) return undefined;\n if (Date.now() > item.expires) {\n this.cache.delete(key);\n return undefined;\n }\n return item.value;\n }\n\n set(key: string, value: T): void {\n if (this.cache.size >= this.maxSize) this.evict();\n this.cache.set(key, { value, expires: Date.now() + this.ttl });\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n size(): number {\n return this.cache.size;\n }\n\n private evict(): void {\n // Drop the oldest 10% in one pass — Map preserves insertion order so\n // `keys()` walks oldest-first.\n const drop = Math.max(1, Math.floor(this.maxSize * 0.1));\n let n = 0;\n for (const key of this.cache.keys()) {\n if (n++ >= drop) break;\n this.cache.delete(key);\n }\n }\n}\n\n// Module-level per-isolate caches. Edge runtimes get cold-start fresh; warm\n// invocations benefit from the in-memory hits.\nexport const validationCache = new EdgeCache<EmailValidationResult>(1000);\nexport const mxCache = new EdgeCache<string[]>(500);\n\n/** Same regex the main validator uses — kept inline because edge runtimes don't auto-resolve psl. */\nconst VALID_EMAIL_REGEX =\n /^(([a-zA-Z0-9_+'-]+(\\.[a-zA-Z0-9_+'-]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}))$/;\n\n/**\n * Common email domains — re-exported so callers (Vercel Edge, etc.) can pass a\n * custom subset via `DomainSuggesterOptions.customDomains`.\n */\nexport const COMMON_DOMAINS: readonly string[] = commonEmailDomainsJson as string[];\n\nconst TYPO_PATTERNS = typoPatternsJson as Record<string, string[]>;\n/** Reverse index for O(1) typo → canonical lookup. */\nconst TYPO_LOOKUP = new Map<string, string>();\nfor (const [canonical, typos] of Object.entries(TYPO_PATTERNS)) {\n for (const typo of typos) TYPO_LOOKUP.set(typo, canonical);\n}\n\n/** DNS resolver contract — caller-supplied so we don't import `node:dns`. */\nexport interface DNSResolver {\n resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>>;\n resolveTxt(domain: string): Promise<string[]>;\n}\n\n/** No-op resolver for environments where DNS isn't available. */\nexport class StubDNSResolver implements DNSResolver {\n async resolveMx(): Promise<Array<{ exchange: string; priority: number }>> {\n return [];\n }\n async resolveTxt(): Promise<string[]> {\n return [];\n }\n}\n\n/**\n * DNS-over-HTTPS resolver — works in any runtime with `fetch` (Cloudflare\n * Workers, Vercel Edge, Deno, browsers, Node 18+). Defaults to Cloudflare's\n * 1.1.1.1 endpoint; pass `endpoint` to use Google (8.8.8.8), NextDNS, or\n * a self-hosted resolver.\n *\n * Compatible with [`cf-doh`](https://www.npmjs.com/package/cf-doh) — if you\n * already use that, drop it in directly. This built-in keeps the package\n * zero-dep so the same code works on every edge runtime without an extra\n * install step.\n */\nexport interface DoHResolverOptions {\n /** DoH endpoint URL. Default: https://cloudflare-dns.com/dns-query */\n endpoint?: string;\n /** Per-query request timeout, ms. Default: 5000 */\n timeoutMs?: number;\n /** Custom fetch (e.g. to add headers / proxy). Default: globalThis.fetch */\n fetch?: typeof fetch;\n}\n\ninterface DoHAnswer {\n name: string;\n type: number;\n TTL: number;\n data: string;\n}\n\ninterface DoHResponse {\n Status: number;\n Answer?: DoHAnswer[];\n}\n\nconst DOH_RECORD_TYPE = { MX: 15, TXT: 16 } as const;\n\nexport class DoHResolver implements DNSResolver {\n private readonly endpoint: string;\n private readonly timeoutMs: number;\n private readonly fetchFn: typeof fetch;\n\n constructor(options: DoHResolverOptions = {}) {\n this.endpoint = options.endpoint ?? 'https://cloudflare-dns.com/dns-query';\n this.timeoutMs = options.timeoutMs ?? 5000;\n this.fetchFn = options.fetch ?? globalThis.fetch;\n }\n\n async resolveMx(domain: string): Promise<Array<{ exchange: string; priority: number }>> {\n const records = await this.query(domain, DOH_RECORD_TYPE.MX);\n if (!records) return [];\n return records\n .map((answer) => {\n // MX answer data: \"<priority> <exchange>\" (with optional trailing dot).\n const match = answer.data.match(/^(\\d+)\\s+(.+?)\\.?$/);\n if (!match) return null;\n return { priority: Number(match[1]), exchange: match[2] as string };\n })\n .filter((r): r is { exchange: string; priority: number } => r !== null)\n .sort((a, b) => a.priority - b.priority);\n }\n\n async resolveTxt(domain: string): Promise<string[]> {\n const records = await this.query(domain, DOH_RECORD_TYPE.TXT);\n if (!records) return [];\n // TXT answers come back as quoted strings — strip the surrounding quotes.\n return records.map((answer) => answer.data.replace(/^\"(.*)\"$/, '$1'));\n }\n\n private async query(domain: string, type: number): Promise<DoHAnswer[] | null> {\n const url = `${this.endpoint}?name=${encodeURIComponent(domain)}&type=${type}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const response = await this.fetchFn(url, {\n headers: { Accept: 'application/dns-json' },\n signal: controller.signal,\n });\n if (!response.ok) return null;\n const json = (await response.json()) as DoHResponse;\n // Status 0 = NOERROR. Anything else (NXDOMAIN, SERVFAIL, etc.) → no answers.\n if (json.Status !== 0) return [];\n return json.Answer ?? [];\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n/**\n * Suggest a corrected domain. Returns the canonical for a known typo,\n * otherwise the closest match within the threshold, otherwise null.\n */\nexport function suggestDomain(domain: string, options?: DomainSuggesterOptions): string | null {\n const lower = domain.toLowerCase();\n\n // Hand-curated typo map first — beats similarity for common cases.\n const known = TYPO_LOOKUP.get(lower);\n if (known) return known;\n\n const domains = options?.customDomains ?? COMMON_DOMAINS;\n if (domains.includes(lower)) return null;\n\n const threshold = options?.threshold ?? 2;\n let minDistance = Infinity;\n let suggestion: string | null = null;\n\n for (const candidate of domains) {\n const candidateLower = candidate.toLowerCase();\n if (lower === candidateLower) return null;\n const similarity = stringSimilarity(lower, candidateLower);\n const distance = Math.round((1 - similarity) * Math.max(domain.length, candidate.length));\n if (distance > 0 && distance <= threshold && distance < minDistance) {\n minDistance = distance;\n suggestion = candidate;\n }\n }\n return suggestion;\n}\n\n/**\n * Validate one email — syntax / typo / disposable / free / MX (if a resolver\n * is supplied). Each step is independently flag-gated so callers pay only for\n * what they use.\n */\nexport async function validateEmailCore(\n email: string,\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult> {\n const normalized = email.toLowerCase().trim();\n\n if (!options?.skipCache) {\n const cached = validationCache.get(normalized);\n if (cached) return cached;\n }\n\n const result: EmailValidationResult = { valid: false, email: normalized, validators: {} };\n\n if (options?.validateSyntax !== false) {\n const syntaxValid = VALID_EMAIL_REGEX.test(normalized);\n result.validators.syntax = { valid: syntaxValid };\n if (!syntaxValid) {\n validationCache.set(normalized, result);\n return result;\n }\n }\n\n const [local, domain] = normalized.split('@');\n result.local = local;\n result.domain = domain;\n\n if (options?.validateTypo !== false) {\n const suggestion = suggestDomain(domain, options?.domainSuggesterOptions);\n result.validators.typo = { valid: !suggestion, suggestion: suggestion ?? undefined };\n }\n\n if (options?.validateDisposable !== false) {\n result.validators.disposable = { valid: !disposableProviders.includes(domain) };\n }\n\n if (options?.validateFree !== false) {\n result.validators.free = { valid: !freeProviders.includes(domain) };\n }\n\n if (options?.validateMx && options.dnsResolver) {\n try {\n const records = await options.dnsResolver.resolveMx(domain);\n const hasMx = records.length > 0;\n result.validators.mx = {\n valid: hasMx,\n records: hasMx ? records.map((r) => r.exchange) : undefined,\n };\n } catch (error) {\n result.validators.mx = {\n valid: false,\n error: error instanceof Error ? error.message : 'MX validation failed',\n };\n }\n }\n\n // Free-provider detection is informational; only the hard validators gate validity.\n result.valid = (['syntax', 'typo', 'disposable', 'mx'] as const).every((key) => {\n const validator = result.validators[key];\n return !validator || validator.valid !== false;\n });\n\n if (!options?.skipCache) validationCache.set(normalized, result);\n return result;\n}\n\nexport async function validateEmailBatch(\n emails: string[],\n options?: ValidateEmailOptions & { dnsResolver?: DNSResolver }\n): Promise<EmailValidationResult[]> {\n const chunkSize = options?.batchSize ?? 10;\n const results: EmailValidationResult[] = [];\n for (let i = 0; i < emails.length; i += chunkSize) {\n const chunk = emails.slice(i, i + chunkSize);\n const chunkResults = await Promise.all(chunk.map((email) => validateEmailCore(email, options)));\n results.push(...chunkResults);\n }\n return results;\n}\n\nexport function clearCache(): void {\n validationCache.clear();\n mxCache.clear();\n}\n\nexport type { DomainSuggesterOptions, EmailValidationResult, ValidateEmailOptions } from '../types';\n","import type { EmailValidationResult } from '../../types';\nimport { validateEmailBatch, validateEmailCore } from '../verifier';\nimport type { ValidationDispatch } from './validation';\n\n/**\n * Execute a classified request against the core validator. Single-email\n * requests yield one result; batch requests yield an array.\n */\nexport async function executeValidation(\n dispatch: ValidationDispatch\n): Promise<EmailValidationResult | EmailValidationResult[]> {\n if (dispatch.kind === 'single') {\n return validateEmailCore(dispatch.email, dispatch.options);\n }\n return validateEmailBatch(dispatch.emails, dispatch.options);\n}\n","import type { ValidateEmailOptions } from '../../types';\n\n/** Hard limit on batch size enforced by every adapter. */\nexport const MAX_BATCH_SIZE = 100;\n\n/** Shape of POST bodies and Lambda invocations across all serverless adapters. */\nexport interface ValidationRequestBody {\n email?: string;\n emails?: string[];\n options?: ValidateEmailOptions;\n}\n\nexport type ValidationDispatch =\n | { kind: 'single'; email: string; options?: ValidateEmailOptions }\n | { kind: 'batch'; emails: string[]; options?: ValidateEmailOptions };\n\nexport interface ValidationFailure {\n kind: 'invalid';\n status: 400;\n message: string;\n}\n\n/**\n * Validation for endpoints that accept ONLY a batch (`emails`). Returns\n * a 400 failure if emails is missing/empty/oversized, or null when valid.\n * Routed `/validate/batch` paths use this so error messages stay batch-specific.\n */\nexport type BatchValidation = { ok: true; emails: string[] } | { ok: false; status: 400; message: string };\n\nexport function validateBatchEmailsField(emails: unknown): BatchValidation {\n if (!Array.isArray(emails) || emails.length === 0) {\n return { ok: false, status: 400, message: 'Emails array is required' };\n }\n if (emails.length > MAX_BATCH_SIZE) {\n return { ok: false, status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { ok: true, emails: emails as string[] };\n}\n\n/**\n * Apply the rules every serverless adapter shares:\n * 1. body must request either `email` or `emails`\n * 2. `emails` must be a non-empty array of ≤ MAX_BATCH_SIZE entries\n *\n * Centralising this means a future rule change (say, raising the cap) lands\n * in one place instead of three.\n */\nexport function classifyRequest(\n body: ValidationRequestBody | null | undefined\n): ValidationDispatch | ValidationFailure {\n if (!body || (!body.email && !body.emails)) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n if (body.emails) {\n if (!Array.isArray(body.emails) || body.emails.length === 0) {\n return { kind: 'invalid', status: 400, message: 'Emails array is required' };\n }\n if (body.emails.length > MAX_BATCH_SIZE) {\n return { kind: 'invalid', status: 400, message: `Maximum ${MAX_BATCH_SIZE} emails allowed per batch` };\n }\n return { kind: 'batch', emails: body.emails, options: body.options };\n }\n // body.email must be set per the first guard (which checks both fields).\n if (!body.email) {\n return { kind: 'invalid', status: 400, message: 'Email or emails array is required' };\n }\n return { kind: 'single', email: body.email, options: body.options };\n}\n","/**\n * AWS Lambda adapter — three handler shapes for three deploy modes:\n *\n * - `handler` — routed (recommended) — `/health`, `/validate`,\n * `/validate/batch`. Wire to API Gateway with\n * `{proxy+}` so all three paths land on one Lambda.\n * - `apiGatewayHandler` — single-route — accepts API Gateway proxy events\n * but never inspects `event.path`. Pick this when\n * you want one Lambda per URL.\n * - `lambdaHandler` — direct invocation — no API Gateway envelope.\n * Pick this when calling from another AWS service\n * (Step Functions, EventBridge, …).\n *\n * Shared validation rules + CORS headers come from `../_shared/` so all three\n * agree on what's accepted.\n */\nimport type { ValidateEmailOptions } from '../../types';\nimport { corsHeaders, jsonHeaders } from '../_shared/cors';\nimport { executeValidation } from '../_shared/dispatch';\nimport { classifyRequest, type ValidationRequestBody, validateBatchEmailsField } from '../_shared/validation';\nimport { clearCache, validateEmailCore } from '../verifier';\n\n/**\n * Loose API-Gateway event/result/context shapes — `headers` and similar maps\n * intentionally widen to `string | undefined` so they line up with the\n * official `@types/aws-lambda` definitions used by callers/tests.\n */\nexport interface APIGatewayProxyEvent {\n body: string | null;\n headers: { [key: string]: string | undefined };\n httpMethod: string;\n path: string;\n queryStringParameters: { [key: string]: string | undefined } | null;\n pathParameters: { [key: string]: string | undefined } | null;\n isBase64Encoded?: boolean;\n}\n\nexport interface APIGatewayProxyResult {\n statusCode: number;\n headers?: { [key: string]: string };\n body: string;\n}\n\nexport interface LambdaContext {\n functionName: string;\n functionVersion: string;\n awsRequestId: string;\n remainingTimeInMillis: number;\n}\n\ninterface ValidateResponse {\n success: boolean;\n data?: unknown;\n error?: string;\n}\n\nconst POST_HEADERS = jsonHeaders(corsHeaders('POST, OPTIONS'));\nconst ROUTED_HEADERS = jsonHeaders(corsHeaders());\n\nfunction jsonResponse(statusCode: number, body: unknown, headers: Record<string, string>): APIGatewayProxyResult {\n return { statusCode, headers, body: JSON.stringify(body) };\n}\n\n// Single-route API Gateway handler — accepts proxy events but doesn't inspect `event.path`.\nexport async function apiGatewayHandler(\n event: APIGatewayProxyEvent,\n _context: LambdaContext\n): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 200, headers: corsHeaders('POST, OPTIONS'), body: '' };\n }\n\n try {\n const request: ValidationRequestBody = event.body ? JSON.parse(event.body) : {};\n const classified = classifyRequest(request);\n if (classified.kind === 'invalid') {\n return jsonResponse(classified.status, { success: false, error: classified.message }, POST_HEADERS);\n }\n const data = await executeValidation(classified);\n return jsonResponse(200, { success: true, data }, POST_HEADERS);\n } catch (error) {\n console.error('Lambda error:', error);\n const message = error instanceof Error ? error.message : 'Internal server error';\n return jsonResponse(500, { success: false, error: message }, POST_HEADERS);\n }\n}\n\n// Direct Lambda handler (no API Gateway envelope).\nexport async function lambdaHandler(event: ValidationRequestBody, _context: LambdaContext): Promise<ValidateResponse> {\n try {\n const classified = classifyRequest(event);\n if (classified.kind === 'invalid') {\n return { success: false, error: classified.message };\n }\n return { success: true, data: await executeValidation(classified) };\n } catch (error) {\n console.error('Lambda error:', error);\n return { success: false, error: error instanceof Error ? error.message : 'Internal server error' };\n }\n}\n\n// Cache management handler.\nexport async function cacheHandler(\n event: { action: 'clear' | 'stats' },\n _context: LambdaContext\n): Promise<{ success: boolean; message?: string; stats?: unknown }> {\n switch (event.action) {\n case 'clear':\n clearCache();\n return { success: true, message: 'Cache cleared' };\n case 'stats':\n return { success: true, message: 'Cache stats not implemented' };\n default:\n return { success: false, message: 'Invalid action' };\n }\n}\n\n/** Decode the API Gateway body, supporting base64-encoded payloads. */\nfunction decodeBody(event: APIGatewayProxyEvent): unknown {\n if (!event.body) return {};\n const raw = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString('utf-8') : event.body;\n return JSON.parse(raw);\n}\n\n// Routed handler — supports /health, /validate, /validate/batch. The context\n// argument is intentionally `unknown` so callers can pass either our minimal\n// LambdaContext or the official `aws-lambda#Context` without a cast.\nexport async function handler(event: APIGatewayProxyEvent, _context?: unknown): Promise<APIGatewayProxyResult> {\n if (event.httpMethod === 'OPTIONS') {\n return { statusCode: 204, headers: corsHeaders(), body: '' };\n }\n\n if (event.path === '/health' && event.httpMethod === 'GET') {\n return jsonResponse(200, { status: 'healthy', timestamp: new Date().toISOString() }, ROUTED_HEADERS);\n }\n\n const isValidatePath = event.path === '/validate' || event.path === '/validate/batch';\n if (isValidatePath && event.httpMethod !== 'POST') {\n return jsonResponse(405, { error: 'Method not allowed' }, ROUTED_HEADERS);\n }\n\n if (event.path === '/validate' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as { email?: string };\n if (!body.email) return jsonResponse(400, { error: 'Email is required' }, ROUTED_HEADERS);\n\n const options = parseValidateOptions(event.queryStringParameters);\n const result = await validateEmailCore(body.email, options);\n return jsonResponse(200, result, ROUTED_HEADERS);\n } catch (error) {\n if (error instanceof SyntaxError) {\n return jsonResponse(400, { error: 'Invalid request body' }, ROUTED_HEADERS);\n }\n console.error('Validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n if (event.path === '/validate/batch' && event.httpMethod === 'POST') {\n try {\n const body = decodeBody(event) as ValidationRequestBody;\n const validated = validateBatchEmailsField(body.emails);\n if (!validated.ok) return jsonResponse(validated.status, { error: validated.message }, ROUTED_HEADERS);\n const results = await executeValidation({ kind: 'batch', emails: validated.emails });\n return jsonResponse(200, { results }, ROUTED_HEADERS);\n } catch (error) {\n console.error('Batch validation error:', error);\n return jsonResponse(500, { error: 'Internal server error' }, ROUTED_HEADERS);\n }\n }\n\n return jsonResponse(404, { error: 'Not found' }, ROUTED_HEADERS);\n}\n\nfunction parseValidateOptions(query: { [key: string]: string | undefined } | null): Partial<ValidateEmailOptions> {\n if (!query) return {};\n const options: Partial<ValidateEmailOptions> = {};\n if (query.skipCache === 'true') options.skipCache = true;\n if (query.validateTypo === 'false') options.validateTypo = false;\n return options;\n}\n\nexport default {\n apiGatewayHandler,\n lambdaHandler,\n cacheHandler,\n handler,\n};\n"],"names":["stringSimilarity","__async"],"mappings":"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","x_google_ignoreList":[1]}
|
|
@@ -36,9 +36,9 @@ var hasRequiredStringSimilarity;
|
|
|
36
36
|
function requireStringSimilarity () {
|
|
37
37
|
if (hasRequiredStringSimilarity) return stringSimilarity;
|
|
38
38
|
hasRequiredStringSimilarity = 1;
|
|
39
|
-
(function (exports
|
|
40
|
-
Object.defineProperty(exports
|
|
41
|
-
exports
|
|
39
|
+
(function (exports) {
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.stringSimilarity = void 0;
|
|
42
42
|
/* global exports, Map */
|
|
43
43
|
/**
|
|
44
44
|
* Calculate similarity between two strings
|
|
@@ -73,8 +73,8 @@ function requireStringSimilarity () {
|
|
|
73
73
|
}
|
|
74
74
|
return (match * 2) / (str1.length + str2.length - ((substringLength - 1) * 2));
|
|
75
75
|
};
|
|
76
|
-
exports
|
|
77
|
-
exports
|
|
76
|
+
exports.stringSimilarity = stringSimilarity;
|
|
77
|
+
exports.default = exports.stringSimilarity;
|
|
78
78
|
|
|
79
79
|
} (stringSimilarity));
|
|
80
80
|
return stringSimilarity;
|