/** * @copyright Sister Software * @license AGPL-3.0 * @author Teffen Ellis, et al. * * The `mailwoman corpus fetch ` family — reproducible bulk-download recovery modules for * the open-data sources the corpus build pipeline consumes. Each module writes the raw download * files **plus** a sibling `MANIFEST.json` capturing the origin URL, fetch timestamp, byte count, * and sha256 so downstream adapters can verify provenance. * * The corpus build pipeline itself does NOT call these modules — the existing convention is for * operators to pre-download into an out-root and point adapters at the resulting files. These * modules exist for **reproducibility** (disk-loss recovery, weekly refresh, fresh-environment * bootstrap). * * ## Usage * * ```sh * # Default: writes under ./data/corpus/sources/ relative to the working directory * mailwoman corpus fetch state-sources * mailwoman corpus fetch hrsa * * # Or point at the standard mailwoman data root * mailwoman corpus fetch state-sources --out-root /data/corpus/sources * ``` * * Each adapter under `corpus/src/adapters//README.md` documents the specific URL its * input was pulled from; these modules mirror those URLs in a single executable place. * * ## Coverage * * - `ban` — French BAN (Base Adresse Nationale), all départements incl. DOM/TOM. Tier B (Licence * Ouverte 2.0). * - `nad` — US DOT National Address Database (~97M address points, ArcGIS FeatureServer). Tier A * (US PD). * - `geonames-postal` — GeoNames per-country postal exports (~80 countries). Tier B (CC-BY-4.0, * attribute "GeoNames"). The only source in this family carrying `(postcode, locality, region)` * with the names INLINE, which is why it exists: the `parent_id` join route covers exactly five * countries and the nearest-centroid fallback measured under 50% agreement on four of those five. * GeoNames does not publish every country — Venezuela 404s. * - `hrsa` — HRSA Health Center Service Delivery Sites (federal). Tier A (US PD). * - `imls-pls` — IMLS Public Libraries Survey, outlet-level (~17K library branches, FY 2023). * Tier A (US PD). * - `nppes` — NPPES NPI registry, full monthly dissemination (~7M provider venue+address rows). * Tier A (US PD). * - `openaddresses` — OpenAddresses country collections (default: Canada / `ca`). Tier B/C mixed * — per-row filter. * - `ourairports` — OurAirports global airport CSVs (~83K airports + the country/region/runway * joins). Tier A (public domain). The VENUE half of the sub-venue arc (#35); it carries no * interior structure, which comes from `@mailwoman/osm/sdk`'s `extractOSMSubVenues`. * - `wikidata-subvenue` — the multilingual sub-venue DESIGNATOR vocabulary, pulled as the labels * and aliases of eight Wikidata concepts (terminal, gate, concourse, campus, …) plus the * airport-terminal instance labels as attested usage. Tier A (CC0). The only module in this * family built on `APIClient` — see its docstring for why. * - `state-sources` — NY/TX/DE/OR notaries, IA contractors, WA health providers, HI lobbyists. * Tier A (state PD-equivalent). * - `state-hi-schools` — Hawaii DOE school directory (original XLSX; HIDOE + PCS sheets). Tier A * (state PD-equivalent). * - `tiger-full` — US Census TIGER 2024 ADDRFEAT, all US counties. Tier A (US PD). * - `juso-kr` — the Korean road-name address register (주소DB, plus the English road-name DB) from * business.juso.go.kr, the LABEL source for Korean. Tier B ("이용허락범위 제한 없음", attribution). * - `localdata-kr` — Korea's local-government permit registry, one CSV per category, each row carrying * the lot-number AND road-name address of one premises plus a coordinate. The NOISY source for * Korean. Tier B (same label as `juso-kr`). * - `gcis-tw` — Taiwan's company and business registers from the economic ministry's open-data * platform, 148 files by region and industry. The NOISY source for Taiwanese. Tier B (Open * Government Data License v1.0 — the prescribed attribution is a condition of the grant). * - `acra-sg` — Singapore's ACRA corporate-entity register, 27 CSVs with the address FIELDED. The * NOISY source for Singapore. Tier B (Singapore Open Data Licence 1.0). * - `houjin-jp` — the National Tax Agency's corporate-number register, the nationwide Unicode CSV. * The NOISY source for Japanese. Tier A-equivalent (free use, no attribution condition stated). * * License tiers per `docs/licensing-strategy.md` (or the playpen knowledge base mirror at * `docs/docs/projects/mailwoman/licensing-strategy.md`). `openaddresses` is a **Tier-mixed** * source: the downloaded collection includes CC0, CC-BY, OGL, and ODbL/CC-BY-SA rows. The per-row * `LICENSE` filter in the `openaddresses` adapter is essential — Tier-C (ODbL, CC-BY-SA) rows are * dropped at ingest by default to protect proprietary-weights training. * * ### OpenAddresses authentication (as of 2026-05-18) * * `batch.openaddresses.io` now requires a free registered account for bulk downloads (auth check * prevents CDN abuse; data remains openly licensed). `fetchOpenAddresses` reads `OA_BATCH_TOKEN` * from the environment: * * ```sh * # One-time: register at https://batch.openaddresses.io/register * # Log in → Profile → "Create Token" → copy token * export OA_BATCH_TOKEN= * * # Download Canada (~2 GiB compressed, ~7 GiB uncompressed) * mailwoman corpus fetch openaddresses --country ca \ * --out-root $MAILWOMAN_DATA_ROOT/corpus/sources * * # Or any other OA country code * mailwoman corpus fetch openaddresses --country fr * ``` * * Without a token the command prints setup instructions and reports the failure. * * ## Adding a new source * * 1. Pick the right module (or create a sibling one if the source is from a meaningfully * different family). * 2. Append to the `SOURCES` array: `{ slug, filename, url }`. * 3. Confirm the destination URL via `curl -sI -L | head` before committing — state * open-data portals occasionally rotate Socrata view IDs. * 4. Run the command against a scratch `--out-root` to verify the download succeeds + the * MANIFEST is well-formed. * 5. Add the source's adapter (or extend an existing one) under `corpus/src/adapters/`. */ import { fetchBan } from "#fr/tools/fetch/ban" import { fetchHoujinJP } from "#jp/tools/fetch/houjin" import { fetchJusoKR } from "#kr/tools/fetch/juso" import { fetchLocaldataKR } from "#kr/tools/fetch/localdata" import { fetchACRASG } from "#sg/tools/fetch/acra" import { fetchGeonamesDumps } from "#tools/fetch/geonames/dump" import { fetchGeonamesPostal } from "#tools/fetch/geonames/postal" import { fetchOpenAddresses } from "#tools/fetch/openaddresses" import { fetchOurAirports } from "#tools/fetch/ourairports" import { fetchWikidataSubVenue } from "#tools/fetch/wikidata-subvenue" import { fetchGCISTW } from "#tw/tools/fetch/gcis" import { fetchHRSA } from "#us/tools/fetch/hrsa" import { fetchIMLSPLS } from "#us/tools/fetch/imls-pls" import { fetchNAD } from "#us/tools/fetch/nad" import { fetchNPPES } from "#us/tools/fetch/nppes" import { fetchStateHISchools } from "#us/tools/fetch/state/hi-schools" import { fetchStateSources } from "#us/tools/fetch/state/sources" import { fetchTigerFull } from "#us/tools/fetch/tiger-full" export * from "#sg/tools/fetch/acra" export * from "#fr/tools/fetch/ban" export * from "#tw/tools/fetch/gcis" export * from "#tools/fetch/geonames/dump" export * from "#tools/fetch/geonames/postal" export * from "#jp/tools/fetch/houjin" export * from "#us/tools/fetch/hrsa" export * from "#us/tools/fetch/imls-pls" export * from "#kr/tools/fetch/juso" export * from "#kr/tools/fetch/localdata" export * from "#us/tools/fetch/nad" export * from "#us/tools/fetch/nppes" export * from "#tools/fetch/openaddresses" export * from "#tools/fetch/ourairports" export * from "#us/tools/fetch/state/hi-schools" export * from "#us/tools/fetch/state/sources" export * from "#us/tools/fetch/tiger-full" export * from "#tools/fetch/wikidata-subvenue" /** * The fetch-source registry: id → module entry point. Each entry point takes its own options interface. */ export const FETCH_SOURCES = { "acra-sg": fetchACRASG, ban: fetchBan, "gcis-tw": fetchGCISTW, "houjin-jp": fetchHoujinJP, "juso-kr": fetchJusoKR, "localdata-kr": fetchLocaldataKR, nad: fetchNAD, "geonames-dump": fetchGeonamesDumps, "geonames-postal": fetchGeonamesPostal, hrsa: fetchHRSA, "imls-pls": fetchIMLSPLS, nppes: fetchNPPES, openaddresses: fetchOpenAddresses, ourairports: fetchOurAirports, "state-sources": fetchStateSources, "state-hi-schools": fetchStateHISchools, "tiger-full": fetchTigerFull, "wikidata-subvenue": fetchWikidataSubVenue, } as const export type FetchSourceID = keyof typeof FETCH_SOURCES