/** * @copyright Sister Software * @license AGPL-3.0 * @author Teffen Ellis, et al. * * Download the Administration du cadastre et de la topographie's BD-Adresses CSV for the * `bd-adresses` adapter. * * The acquisition belongs under a `tools/` root. `@mailwoman/corpus` is one of the * `TOOLING_PACKAGES` in `dependency-cruiser.config.mjs`, which keep their tooling under `lib/`, so * this module sits beside `#fi/tools/fetch/ryhti` rather than in an `sdk/` root the workspace does * not declare. * * `data.public.lu` states `cc-zero` for this dataset, which the address-source register elects as * `CC0-1.0` under `lu-property-building-1`. CC0 asks for no attribution, and crediting the ACT * remains good practice, so the manifest records the publisher beside the license. * * Four measured properties decide what this module does: * * 1. **The download URL carries the edition's own timestamp.** The dataset is republished weekly * and the CSV resource's `url` reads * `https://download.data.public.lu/resources/adresses-georeferencees-bd-adresses/20260928-023119/addresses.csv`, * where the path segment is the publication time. A hardcoded URL therefore pins one edition and * 404s on the next. The module reads {@linkcode LU_BD_ADRESSES_DATASET_URL} and takes the `url` * of the resource whose `format` is `csv`. The resource's own `latest`, * `https://data.public.lu/fr/datasets/r/`, answers http 302 to the same dated path, * and the dated path is the one downloaded, so the bytes and the checksum recorded beside them * belong to one edition. * 2. **The publisher states an md5 for the file.** The resource carries * `checksum: {type: "md5", value: "…"}` and a `filesize`, measured as * `c2df2f3c18b846144bb5d5dc57fc14ca` and 28,186,970 on the 2026-09-28 edition. The transfer is * checked against both, so a truncated body is a reported failure rather than a short CSV that * parses. A publisher that one day states a digest of another type is reported rather than * skipped silently. * 3. **The file opens with a UTF-8 byte-order mark**, `EF BB BF`. The portal's `filesize` counts it, * which is why a reader that discards the mark reports three bytes fewer than the portal does. * The module writes the body to disk unaltered and checks the digest over the bytes as delivered. * 4. **The re-run check is the stated checksum against the manifest.** The dataset API answer is * roughly 15 KB, so comparing it costs one small request instead of 28 MB. * * The CSV is the only one of the three bulk files this reads. The GeoJSON is 80,836,067 bytes and * the shapefile 19,681,289 for the same records, and `#lu/adapters/bd-adresses/adapter` hands * `opts.inputPath` to `CSVSpliterator.fromAsync`. */ import { APIClient } from "@mailwoman/core/api"; import { PathBuilder, type PathBuilderLike } from "path-ts"; import type { BaseFetchOptions, FetchSummary, SourceManifest } from "#tools/fetch/download"; /** * The dataset record that states the current edition of each bulk file. */ export declare const LU_BD_ADRESSES_DATASET_URL = "https://data.public.lu/api/1/datasets/adresses-georeferencees-bd-adresses/"; /** * The file the adapter reads. * * It is the publisher's own name for the resource. */ export declare const LU_BD_ADRESSES_CSV_FILENAME = "addresses.csv"; /** * The publisher the manifest credits. */ export declare const LU_BD_ADRESSES_ATTRIBUTION = "Administration du cadastre et de la topographie"; /** * The semicolon the publisher delimits with. */ export declare const LU_BD_ADRESSES_DELIMITER = ";"; /** * One bulk file as the dataset record describes it. */ export interface BDAdressesResource { /** * The dated download URL, which names one edition. */ url: string; /** * The publisher's stated byte count, `null` when the record omits it. */ filesize: number | null; /** * The publisher's stated md5, `null` when the record states a digest of another type or none. */ md5: string | null; /** * The resource's own last-modified time, as the record states it. */ lastModified: string | null; } /** * The manifest this module writes beside the CSV. */ export interface BDAdressesManifest extends SourceManifest { license: string; attribution: string; dataset_url: string; /** * The md5 the dataset record stated, which the downloaded bytes were checked against. */ publisher_md5: string | null; /** * The byte count the dataset record stated, beside the `bytes` that arrived. */ publisher_filesize: number | null; last_modified: string | null; columns: readonly string[]; } /** * The shape the dataset API answers with, narrowed to the fields this module reads. */ interface DatasetRecord { resources?: readonly { format?: string; url?: string; filesize?: number; checksum?: { type?: string; value?: string; }; last_modified?: string; }[]; } /** * The CSV resource of a dataset record. * * @throws When the record carries no `csv` resource with a URL, because the publisher * having moved the file is a reported failure rather than an empty transfer. */ export declare function readBDAdressesResource(record: DatasetRecord): BDAdressesResource; export interface DownloadBDAdressesOptions { outputDir: PathBuilderLike; /** * Download although the manifest already records this edition's checksum. */ force?: boolean; retries?: number; retryDelayMs?: number; signal?: AbortSignal; report?: (line: string) => void; } /** * Download the current edition of `addresses.csv` into `options.outputDir`. * * `client` is the caller's, so a test supplies its own and {@linkcode fetchBDAdresses} * decides the retry policy. */ export declare function downloadBDAdresses(client: Pick, options: DownloadBDAdressesOptions): Promise; export interface FetchBDAdressesOptions extends BaseFetchOptions { force?: boolean; retries?: number; signal?: AbortSignal; } /** * Download BD-Adresses into `/bd-adresses/`. * * The registry entry point. * `#lu/adapters/bd-adresses/adapter` is pointed at {@linkcode bdAdressesInputPath}, * the `addresses.csv` inside that directory, rather than at the directory itself. */ export declare function fetchBDAdresses(options: FetchBDAdressesOptions, report?: (line: string) => void): Promise; /** * The file `#lu/adapters/bd-adresses/adapter` reads, under a fetch run's `outRoot`. */ export declare function bdAdressesInputPath(outRoot: PathBuilder): PathBuilder; export {}; //# sourceMappingURL=bd-adresses.d.ts.map