/** * @copyright Sister Software * @license AGPL-3.0 * @author Teffen Ellis, et al. * * Harvests Poland's INSPIRE Addresses (AD) theme into the GML file that * `#pl/adapters/emuia/adapter` reads. * * Główny Urząd Geodezji i Kartografii publishes the Państwowy Rejestr Granic through MapServer at * {@linkcode PL_EMUIA_WFS}. Its dataset record states one condition of use in `otherConstraints`, * `Brak warunków dostępu i użytkowania` — no conditions for access and use — which the * address-source register elected. No license instrument is named, so the publisher's own words are * the label, and that statement grants the reproduction a paged harvest performs. * * `#tools/fetch/wfs-harvest` owns the page read, the appending, the manifest and the resumption. * What is particular to Poland is five measurements, taken on 2026-10-02: * * 1. `ms:AD.Address` is the only feature type the service publishes, and the payload is the Polish * register's own schema with every address value inline, so the harvest takes that one type and * resolves no reference. * 2. The service serves GML and no JSON. Its `GetFeature` `outputFormat` parameter advertises four * values — `application/gml+xml; version=3.2`, `text/xml; subtype=gml/3.2.1`, `text/xml; * subtype=gml/3.1.1` and `text/xml; subtype=gml/2.1.2` — and answers with * `text/xml; subtype="gml/3.2.1"`. * 3. A page holds at most 1,000 features whatever `count` asks for. `count=5000` answers * `numberReturned="1000"`, and the capabilities document states `CountDefault` as 1000. The page * size is therefore the service's cap rather than a choice, and a full harvest is one request per * thousand features. * 4. The service states no count of its own. `resultType=hits` answers `numberMatched="1000"` both * bare and at `startIndex=1`, which is that same cap, and a feature page answers * `numberMatched="unknown"`. `readCheckedWFSFeatureCount` proves a reported count against a page * of the type, and a count equal to the page cap passes that check because no page can exceed the * cap — a 10-feature probe agrees with 1000. `statedFeatureCount` refuses a count equal to the * advertised `CountDefault` for that reason, so this service is harvested with no count and the * harvest ends on the first page that returns no features. The size is read from the service when * a caller asks for it, by `countWFSFeaturesByPaging`, and no count is written into this file. * 5. The service honors a sort. `ImplementsSorting` is `TRUE`, `sortBy=ms:id` answers HTTP 200 and * `sortBy=ms:id D` returns the register's last rows first, which proves the parameter is applied. * `PagingIsTransactionSafe` is `FALSE`, which is the service stating that a paged sequence may * shift under edits made while it is being read. The sort bounds that shift to the rows whose * `ms:id` changed rather than leaving the whole sequence unordered. * * A measurement by paging rests on monotone presence: that an index holding a feature implies every * smaller index holds one. A WFS offers no such guarantee, and a bisection over a service where it * fails reports the first gap rather than the extent. The figure is therefore reported with the date * it was taken, never stored as a constant: the register recorded 8,625,921 on 2026-10-01, and on * 2026-10-02 `startIndex=8626950` returned one feature while `startIndex=8626951` returned none, so * the service then held 8,626,951. That is 1,030 more than the day before, which is ordinary * business for a municipal address register. * * At 1,000 features per page and 1,607,180 bytes per page, a full harvest at that size is 8,627 * requests and about 13.9 GB. * * The harvest assembles one GML document rather than one file per page, because the adapter opens * `opts.inputPath` as a single markup stream. The first page's root tag opens the file with its * namespace declarations kept and its per-page `numberReturned`, `numberMatched` and `timeStamp` * dropped, since those describe one page and the manifest records them per page. The closing tag is * written when the harvest reaches the end of the type, so a partial harvest is an unclosed document * — which the adapter's scanner still reads member by member, and which a resumed run appends to * after truncating back to the last page boundary. */ import { type APIClient } from "@mailwoman/core/api"; import type { PathBuilderLike } from "path-ts"; import type { BaseFetchOptions, FetchSummary } from "#tools/fetch/download"; import { type WFSCapabilities } from "#tools/fetch/inspire-addresses"; import { type FeatureCountStatement, type WFSHarvestManifest } from "#tools/fetch/wfs-harvest"; /** * The service this module harvests. */ export declare const PL_EMUIA_WFS = "https://mapy.geoportal.gov.pl/wss/service/INSPIRE/Addresses"; /** * The one feature type the service publishes, spelled as its capabilities document spells it. */ export declare const PL_EMUIA_TYPE_NAME = "ms:AD.Address"; /** * The output format the harvest asks for, which is the first the service advertises. */ export declare const PL_EMUIA_OUTPUT_FORMAT = "application/gml+xml; version=3.2"; /** * The property the pages are ordered by. */ export declare const PL_EMUIA_SORT_BY = "ms:id"; /** * Features per page. * * The service's own cap rather than a choice: `count=5000` answers with 1,000 features, * and the capabilities document states `CountDefault` as 1000. */ export declare const PL_EMUIA_PAGE_SIZE = 1000; /** * The file the adapter's `inputPath` points at, inside the harvest directory. */ export declare const PL_EMUIA_HARVEST_FILE = "address.gml"; export interface HarvestEMUiAOptions { /** * Where the harvest is written. * * The adapter reads {@linkcode PL_EMUIA_HARVEST_FILE} inside it. */ outputDir: PathBuilderLike; /** * Features per page, capped at {@linkcode PL_EMUIA_PAGE_SIZE} because the service caps it there. */ pageSize?: number; /** * Stop once the manifest holds this many pages, for a probe rather than a full harvest. */ maxPages?: number; /** * Measure the service's extent by paging before the harvest starts. * * Off by default. * The measurement costs about 2·log2(n) requests — 51 for a register of this size — and the * harvest does not need it: paging to the first empty page reads the type whole either way. * * It buys a denominator for the progress lines and a figure for the manifest, * and it rests on the monotone-presence assumption this module's header states. */ measureCount?: boolean; signal?: AbortSignal; report?: (line: string) => void; } /** * The count the service states, with how it was obtained. * * The service states none that can be used, so this reports why rather than * carrying its page cap forward as a count. * A caller that asked for {@linkcode HarvestEMUiAOptions.measureCount} gets the * paged measurement instead, with the requests it cost. */ export declare function readEMUiAFeatureCount(client: Pick, options: { measureCount?: boolean; pageCap: number | null; }): Promise; /** * What the service states about itself, with the three claims this harvest depends on checked. * * The type name and the output format are read from the document rather than taken * from this file's constants, so a service that stops publishing either raises here * instead of producing a harvest of something else. * * @throws When the service publishes no Addresses type, does not advertise the GML * format the adapter reads, or does not advertise result paging. */ export declare function readEMUiACapabilities(client: Pick): Promise; /** * Harvests the service into `options.outputDir` and writes the manifest beside the data file. * * @returns The manifest as written. */ export declare function harvestEMUiAPL(client: Pick, options: HarvestEMUiAOptions): Promise; export type FetchEMUiAPLOptions = BaseFetchOptions & Pick & { /** * An injected client, for a test that supplies its own transport. */ client?: Pick; }; /** * Harvests Poland's addresses under `/emuia/`, for `mailwoman corpus fetch emuia-pl`. * * Re-runnable: a complete harvest whose file still hashes to the manifest's digest makes * no request, and an interrupted one resumes at the page after the last that reached disk. */ export declare function fetchEMUiAPL(options: FetchEMUiAPLOptions, report?: (line: string) => void): Promise; //# sourceMappingURL=emuia.d.ts.map