"""Nevada — SilverFlume SOS portal automation. Name search implemented via the public business entity search. LLC/Corp filing selectors pending live portal verification. """ from __future__ import annotations from scripts.formation.base import ( StatePortal, NameSearchResult, FormationOrder, FilingResult, FilingStatus, ) from .config import CONFIG class NVPortal(StatePortal): STATE_CODE = "NV" STATE_NAME = "Nevada" PORTAL_NAME = "SilverFlume" PORTAL_URL = CONFIG["portal_url"] NWRA_ADDRESS = CONFIG["nwra_address"] NWRA_CITY = CONFIG["nwra_city"] NWRA_STATE = CONFIG["nwra_state"] NWRA_ZIP = CONFIG["nwra_zip"] async def search_name(self, name: str) -> NameSearchResult: """Nevada business name availability. Nevada's entity search (esos.nv.gov / SilverFlume) sits behind Imperva Incapsula bot protection, which blocks automated/headless access (and the residential proxy IPs are flagged too), and Nevada publishes no public open-data API or bulk dataset we can query. So we cannot reliably automate NV name availability the way we do TX (open-data API). Rather than scrape a blocked portal and risk a false "available"/"taken", we attempt one lightweight portal hit and, if we get the Incapsula challenge or anything that is not clearly a result page, we return available=None ("could not determine") with a note so the order flow flags it for a manual admin check on SilverFlume. available=None is NEVER treated as "taken", so it never wrongly blocks an order. """ try: page = await self.start_browser() await page.goto(CONFIG["name_search_url"], wait_until="domcontentloaded", timeout=45000) await self.human_delay(2.0, 4.0) content = await page.content() await self.screenshot(page, f"nv_name_search_{name[:20]}") blocked = ( "_incapsula_resource" in content.lower() or "incapsula" in content.lower() or len(content) < 2000 # challenge stub, not a real page ) if blocked: return NameSearchResult( available=None, state_code="NV", searched_name=name, raw_response=( "NV portal behind Incapsula bot protection - automated " "name check unavailable. Verify manually on SilverFlume " "(esos.nv.gov) before filing." ), ) return NameSearchResult( available=None, state_code="NV", searched_name=name, raw_response="NV name check inconclusive - verify manually on SilverFlume.", ) except Exception as exc: return NameSearchResult( available=None, state_code="NV", searched_name=name, raw_response=f"Error: {exc}", ) async def file_llc(self, order: FormationOrder) -> FilingResult: """File an LLC in Nevada. Selectors pending live portal verification.""" return FilingResult( success=False, status=FilingStatus.PENDING, state_code="NV", entity_name=order.entity_name, error_message=( "NV filing adapter selectors pending verification. " f"Admin: file manually at {CONFIG['portal_url']} — LLC formation." ), ) async def file_corporation(self, order: FormationOrder) -> FilingResult: """File a corporation in Nevada. Selectors pending live portal verification.""" return FilingResult( success=False, status=FilingStatus.PENDING, state_code="NV", entity_name=order.entity_name, error_message=( "NV filing adapter selectors pending verification. " f"Admin: file manually at {CONFIG['portal_url']} — Corp formation." ), ) def adapter() -> NVPortal: return NVPortal()