local M = {}
M.OPERATIONS = { "search_companies", "find_person", "resolve_email", "verify_email" }
local OPERATION_SET = {}
for _, op in ipairs(M.OPERATIONS) do OPERATION_SET[op] = true end
local function trim(s) return (tostring(s or ""):gsub("^%s+", ""):gsub("%s+$", "")) end
local function stamp()
return os.date("!%Y-%m-%dT%H:%M:%SZ")
end
function M.bare_domain(value)
local d = trim(value):lower()
if d == "" then return nil end
d = d:gsub("^https?://", ""):gsub("^www%.", ""):gsub("/.*$", ""):gsub(":%d+$", "")
return d ~= "" and d or nil
end
function M.gate(budget)
if type(budget) ~= "table" then
error("lead_provider: a budget context is required — paid lookups are gated (NEP-0007 §8)")
end
if type(budget.approve) ~= "function" or type(budget.meter) ~= "function" then
error("lead_provider: budget context needs approve(op, cents) and meter(op, cents, meta)")
end
local gate = {}
function gate:paid(op, cents, fn)
if not OPERATION_SET[op] then
error("lead_provider: unknown operation '" .. tostring(op) .. "'")
end
if type(cents) ~= "number" or cents < 0 then
error("lead_provider: " .. op .. " needs a non-negative cost in cents")
end
local ok, reason = budget.approve(op, cents)
if not ok then
return nil, reason or "budget_declined"
end
local result = fn()
budget.meter(op, cents, { operation = op, cents = cents, at = stamp() })
return result
end
return gate
end
function M.provenance(provider, from)
return { provider = trim(provider), retrieved_from = from, retrieved_at = stamp() }
end
function M.person(provider, from, fields)
fields = fields or {}
return {
first_name = fields.first_name,
last_name = fields.last_name,
full_name = fields.full_name,
title = fields.title,
company = fields.company,
domain = fields.domain,
linkedin = fields.linkedin,
location = fields.location,
emails = fields.emails or {},
provenance = M.provenance(provider, from),
}
end
function M.company(provider, from, fields)
fields = fields or {}
return {
registry_id = fields.registry_id,
name = fields.name,
domain = fields.domain,
status = fields.status,
legal_form = fields.legal_form,
jurisdiction = fields.jurisdiction,
city = fields.city,
country = fields.country,
industry = fields.industry,
industry_code = fields.industry_code,
employees = fields.employees,
phone = fields.phone,
founded_at = fields.founded_at,
registered_at = fields.registered_at,
provenance = M.provenance(provider, from),
}
end
function M.email(provider, from, fields)
fields = fields or {}
return {
address = fields.address,
email_type = fields.email_type or "provider",
verification_status = fields.verification_status or "UNKNOWN",
confidence = fields.confidence,
provenance = M.provenance(provider, from),
}
end
return M