@mailwoman/nominatim 4.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/out/cli.d.ts +17 -0
- package/out/cli.d.ts.map +1 -0
- package/out/cli.js +229 -0
- package/out/cli.js.map +1 -0
- package/out/index.d.ts +147 -0
- package/out/index.d.ts.map +1 -0
- package/out/index.js +159 -0
- package/out/index.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @mailwoman/nominatim
|
|
2
|
+
|
|
3
|
+
A **Nominatim-compatible HTTP geocoding API** over the [Mailwoman](https://mailwoman.sister.software) engine. Point an existing Nominatim client at it and forward + reverse geocoding work — no PostgreSQL, no `osm2pgsql` import.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @mailwoman/nominatim serve --port 8080 --data <gazetteer-or-bundle>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from geopy.geocoders import Nominatim
|
|
11
|
+
|
|
12
|
+
geo = Nominatim(domain="localhost:8080", scheme="http")
|
|
13
|
+
geo.geocode("1600 Pennsylvania Ave NW, Washington DC", addressdetails=True)
|
|
14
|
+
geo.reverse((38.8977, -77.0365))
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Endpoints
|
|
18
|
+
|
|
19
|
+
| Endpoint | Nominatim contract | Status |
|
|
20
|
+
| ---------- | -------------------------------------------------------- | ------- |
|
|
21
|
+
| `/search` | free-text `q` + structured forward geocoding | ✓ |
|
|
22
|
+
| `/reverse` | `lat`/`lon` → nearest address (`WofReverseGeocoder` PIP) | ✓ |
|
|
23
|
+
| `/status` | health + data version | ✓ |
|
|
24
|
+
| `/lookup` | resolve known place ids | planned |
|
|
25
|
+
|
|
26
|
+
## Library use
|
|
27
|
+
|
|
28
|
+
The package is engine-agnostic — embed it in your own server:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import express from "express"
|
|
32
|
+
import { createNominatimRouter, type NominatimEngine } from "@mailwoman/nominatim"
|
|
33
|
+
|
|
34
|
+
const engine: NominatimEngine = {
|
|
35
|
+
/* search, reverse, lookup, status — backed by your Mailwoman pipeline */
|
|
36
|
+
}
|
|
37
|
+
express().use(createNominatimRouter(engine)).listen(8080)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Annotations
|
|
41
|
+
|
|
42
|
+
Every result carries an OpenCage-style `annotations` block — coordinate formats (DMS, MGRS, geohash,
|
|
43
|
+
Maidenhead, Mercator), qibla bearing, sun times, country flag, calling code, and currency, plus the IANA
|
|
44
|
+
timezone, UN/LOCODE, and EU NUTS codes when their data bundles are present. Plain Nominatim returns none
|
|
45
|
+
of these.
|
|
46
|
+
|
|
47
|
+
## Status
|
|
48
|
+
|
|
49
|
+
Shipped. `/search` and `/reverse` resolve over the live engine and return the enriched block; `/lookup`
|
|
50
|
+
is not yet implemented (returns `501`). `addressdetails` goes down to the house number and road when the
|
|
51
|
+
query carries them — `1600 Pennsylvania Avenue NW, Washington, DC 20500` resolves to the rooftop
|
|
52
|
+
(`38.897, -77.037`) with `house_number`, `road`, `city`, `state`, `postcode`, and `country_code`.
|
|
53
|
+
|
|
54
|
+
For autocomplete / type-ahead, see the companion [`@mailwoman/photon`](../photon).
|
package/out/cli.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @copyright Sister Software
|
|
4
|
+
* @license AGPL-3.0
|
|
5
|
+
* @author Teffen Ellis, et al.
|
|
6
|
+
*
|
|
7
|
+
* `mailwoman-nominatim` — boot a Nominatim-compatible endpoint via the `serve` command. Usage +
|
|
8
|
+
* examples live in the package README.
|
|
9
|
+
*
|
|
10
|
+
* Wires the real engine: `/search` over `geocodeAddress` (parse → resolve), `/reverse` over
|
|
11
|
+
* `WofReverseGeocoder` (point-in-polygon over WOF admin polygons), reusing the same
|
|
12
|
+
* resolver-backend selector GeocodeRouter uses. Results carry the OpenCage-style `annotations`
|
|
13
|
+
* block — coordinate formats, flag, calling code, currency, and (when their DBs are present)
|
|
14
|
+
* timezone, UN/LOCODE, NUTS — composed from the `@mailwoman/*` annotators.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=cli.d.ts.map
|
package/out/cli.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
|
package/out/cli.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @copyright Sister Software
|
|
4
|
+
* @license AGPL-3.0
|
|
5
|
+
* @author Teffen Ellis, et al.
|
|
6
|
+
*
|
|
7
|
+
* `mailwoman-nominatim` — boot a Nominatim-compatible endpoint via the `serve` command. Usage +
|
|
8
|
+
* examples live in the package README.
|
|
9
|
+
*
|
|
10
|
+
* Wires the real engine: `/search` over `geocodeAddress` (parse → resolve), `/reverse` over
|
|
11
|
+
* `WofReverseGeocoder` (point-in-polygon over WOF admin polygons), reusing the same
|
|
12
|
+
* resolver-backend selector GeocodeRouter uses. Results carry the OpenCage-style `annotations`
|
|
13
|
+
* block — coordinate formats, flag, calling code, currency, and (when their DBs are present)
|
|
14
|
+
* timezone, UN/LOCODE, NUTS — composed from the `@mailwoman/*` annotators.
|
|
15
|
+
*/
|
|
16
|
+
import { composeAnnotators, toOpenCage } from "@mailwoman/annotations";
|
|
17
|
+
import { countryReferenceAnnotator, matchCountry } from "@mailwoman/codex/country";
|
|
18
|
+
import { NeuralAddressClassifier } from "@mailwoman/neural";
|
|
19
|
+
import { makeNutsAnnotator, NutsLookup } from "@mailwoman/nuts-lookup";
|
|
20
|
+
import { createWofResolver } from "@mailwoman/resolver";
|
|
21
|
+
import { coordinateFormatAnnotator } from "@mailwoman/spatial";
|
|
22
|
+
import { makeTimezoneAnnotator, TimezoneLookup } from "@mailwoman/timezone-lookup";
|
|
23
|
+
import { makeUnLocodeAnnotator, UnLocodeLookup } from "@mailwoman/un-locode-lookup";
|
|
24
|
+
import express from "express";
|
|
25
|
+
import { createAddressParser } from "mailwoman";
|
|
26
|
+
import { geocodeAddress, ShardProvider } from "mailwoman/geocode-core";
|
|
27
|
+
import { createResolverBackend, mailwomanDataRoot, resolveCandidateDbPath, wofShardPaths, } from "mailwoman/resolver-backend";
|
|
28
|
+
import { existsSync } from "node:fs";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
import { parseArgs } from "node:util";
|
|
31
|
+
import { createNominatimRouter, toNominatimResult, } from "./index.js";
|
|
32
|
+
/** WOF placetype → Nominatim address key. */
|
|
33
|
+
const PLACETYPE_TO_KEY = {
|
|
34
|
+
venue: "road",
|
|
35
|
+
street: "road",
|
|
36
|
+
locality: "city",
|
|
37
|
+
localadmin: "city",
|
|
38
|
+
borough: "city_district",
|
|
39
|
+
neighbourhood: "suburb",
|
|
40
|
+
county: "county",
|
|
41
|
+
region: "state",
|
|
42
|
+
macroregion: "state",
|
|
43
|
+
country: "country",
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* A real address fits comfortably; anything longer is malformed input (and would exceed the model's
|
|
47
|
+
* input window). Cap defensively so a giant query returns no results instead of faulting.
|
|
48
|
+
*/
|
|
49
|
+
const MAX_QUERY_LEN = 512;
|
|
50
|
+
function joinNonEmpty(...parts) {
|
|
51
|
+
return parts.filter(Boolean).join(", ");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The resolver returns admin labels + a coordinate (often rooftop/interpolated via the situs
|
|
55
|
+
* shards) but drops the street. Recover house_number + road from the parse so the result carries
|
|
56
|
+
* the full address — Nominatim populates both `addressdetails` and `display_name` down to the house
|
|
57
|
+
* number.
|
|
58
|
+
*/
|
|
59
|
+
async function streetParts(parser, query) {
|
|
60
|
+
const solution = (await parser.parse(query, { verbose: true })).solutions[0];
|
|
61
|
+
const matches = solution?.toJSON()?.matches ?? [];
|
|
62
|
+
return {
|
|
63
|
+
houseNumber: matches.find((m) => m.classification === "house_number")?.value,
|
|
64
|
+
road: matches.find((m) => m.classification === "street")?.value,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Map a forward geocode result (admin + coordinate) into the formatter's neutral shape. */
|
|
68
|
+
function forwardToResolved(r) {
|
|
69
|
+
const address = {};
|
|
70
|
+
if (r.locality)
|
|
71
|
+
address.city = r.locality;
|
|
72
|
+
if (r.region)
|
|
73
|
+
address.state = r.region;
|
|
74
|
+
if (r.postcode)
|
|
75
|
+
address.postcode = r.postcode;
|
|
76
|
+
for (const h of r.hierarchy) {
|
|
77
|
+
if (h.tag === "country")
|
|
78
|
+
address.country = h.value;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
lat: r.lat,
|
|
82
|
+
lon: r.lon,
|
|
83
|
+
address,
|
|
84
|
+
displayName: joinNonEmpty(address.city, address.state, address.postcode, address.country) || r.input,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async function serve() {
|
|
88
|
+
const { values } = parseArgs({
|
|
89
|
+
options: {
|
|
90
|
+
port: { type: "string", default: "8080" },
|
|
91
|
+
host: { type: "string", default: "0.0.0.0" },
|
|
92
|
+
data: { type: "string" },
|
|
93
|
+
},
|
|
94
|
+
allowPositionals: true,
|
|
95
|
+
});
|
|
96
|
+
const port = Number(values.port) || 8080;
|
|
97
|
+
const host = values.host ?? "0.0.0.0";
|
|
98
|
+
const resolverMod = await import("@mailwoman/resolver-wof-sqlite");
|
|
99
|
+
const wofPaths = wofShardPaths().filter(existsSync);
|
|
100
|
+
const adminDbPath = wofPaths[0];
|
|
101
|
+
const classifier = await NeuralAddressClassifier.loadFromWeights({ locale: "en-US" });
|
|
102
|
+
const parser = createAddressParser();
|
|
103
|
+
const backend = createResolverBackend(resolverMod, { wofPaths });
|
|
104
|
+
const resolver = createWofResolver(backend);
|
|
105
|
+
const shards = new ShardProvider(resolverMod, mailwomanDataRoot());
|
|
106
|
+
// NOT a geocode country constraint. The default-on #244 placer already routes the query's country
|
|
107
|
+
// (Berlin→DE, Boston→US) and `defaultCountry` is a HARD override that beats it (geocode-core.ts:102),
|
|
108
|
+
// so forcing "US" resolved every non-US query to its US namesake (Berlin→Berlin NH). We let the
|
|
109
|
+
// placer decide instead. This is the fallback used ONLY to annotate the flag/currency/calling-code
|
|
110
|
+
// when the resolved hierarchy omits the country tag — which on US-centric data (no candidate DB)
|
|
111
|
+
// happens for US results, where "US" is the right guess. Non-US results carry the country tag, so
|
|
112
|
+
// the fallback never mislabels them.
|
|
113
|
+
const annotationCountryFallback = resolveCandidateDbPath() ? undefined : "US";
|
|
114
|
+
const reverseGeo = adminDbPath ? new resolverMod.WofReverseGeocoder({ adminDbPath }) : undefined;
|
|
115
|
+
const annotators = [coordinateFormatAnnotator, countryReferenceAnnotator];
|
|
116
|
+
const tzDbPath = join(mailwomanDataRoot(), "timezone", "timezone.db");
|
|
117
|
+
if (existsSync(tzDbPath))
|
|
118
|
+
annotators.push(makeTimezoneAnnotator(new TimezoneLookup({ databasePath: tzDbPath })));
|
|
119
|
+
const ulDbPath = join(mailwomanDataRoot(), "un-locode", "un-locode.db");
|
|
120
|
+
if (existsSync(ulDbPath))
|
|
121
|
+
annotators.push(makeUnLocodeAnnotator(new UnLocodeLookup({ databasePath: ulDbPath })));
|
|
122
|
+
const nutsDbPath = join(mailwomanDataRoot(), "nuts", "nuts.db");
|
|
123
|
+
if (existsSync(nutsDbPath))
|
|
124
|
+
annotators.push(makeNutsAnnotator(new NutsLookup({ databasePath: nutsDbPath })));
|
|
125
|
+
const annotate = composeAnnotators(annotators);
|
|
126
|
+
const engine = {
|
|
127
|
+
async search(params) {
|
|
128
|
+
const query = (params.q ?? joinNonEmpty(params.street, params.city, params.state, params.postalcode, params.country))?.trim();
|
|
129
|
+
// Empty/whitespace → no query; absurdly long → not an address (and would blow the model's input).
|
|
130
|
+
if (!query || query.length > MAX_QUERY_LEN)
|
|
131
|
+
return [];
|
|
132
|
+
// A caller-supplied `countrycodes` is an explicit hard restriction (Nominatim semantics): honor
|
|
133
|
+
// it as the country constraint, even to the point of no result. It doubles as the manual override
|
|
134
|
+
// for the #822 placer frontier — `countrycodes=au` lands Sydney in Australia. One country is the
|
|
135
|
+
// common (geopy) case; for a list we apply the first.
|
|
136
|
+
const userCountry = params.countrycodes?.[0]?.toUpperCase();
|
|
137
|
+
const result = await geocodeAddress(query, {
|
|
138
|
+
classifier,
|
|
139
|
+
resolver,
|
|
140
|
+
shards: shards.for,
|
|
141
|
+
defaultCountry: userCountry,
|
|
142
|
+
});
|
|
143
|
+
if (result.lat == null || result.lon == null)
|
|
144
|
+
return [];
|
|
145
|
+
const resolved = forwardToResolved(result);
|
|
146
|
+
// Recover the street the resolver drops, so addressdetails + display_name carry it.
|
|
147
|
+
const { houseNumber, road } = await streetParts(parser, query);
|
|
148
|
+
if (houseNumber)
|
|
149
|
+
resolved.address.house_number = houseNumber;
|
|
150
|
+
if (road)
|
|
151
|
+
resolved.address.road = road;
|
|
152
|
+
// The country tag isn't always in the hierarchy (US admin results omit it); backfill from the
|
|
153
|
+
// US-centric-data default so the address, display_name, and flag/currency/calling-code agree.
|
|
154
|
+
const countryName = result.hierarchy.find((h) => h.tag === "country")?.value ?? annotationCountryFallback;
|
|
155
|
+
const country = matchCountry(countryName);
|
|
156
|
+
if (country) {
|
|
157
|
+
if (!resolved.address.country)
|
|
158
|
+
resolved.address.country = country.canonical;
|
|
159
|
+
resolved.address.country_code = country.iso2.toLowerCase();
|
|
160
|
+
}
|
|
161
|
+
if (houseNumber || road) {
|
|
162
|
+
resolved.displayName =
|
|
163
|
+
joinNonEmpty(houseNumber, road, resolved.address.city, resolved.address.state, resolved.address.postcode, resolved.address.country) || resolved.displayName;
|
|
164
|
+
}
|
|
165
|
+
const out = toNominatimResult(resolved, { addressdetails: params.addressdetails });
|
|
166
|
+
out.annotations = toOpenCage(await annotate({
|
|
167
|
+
lat: result.lat,
|
|
168
|
+
lon: result.lon,
|
|
169
|
+
countryCode: country?.iso2,
|
|
170
|
+
placeName: result.locality ?? undefined,
|
|
171
|
+
}));
|
|
172
|
+
return [out].slice(0, params.limit);
|
|
173
|
+
},
|
|
174
|
+
async reverse(params) {
|
|
175
|
+
if (!reverseGeo)
|
|
176
|
+
return null;
|
|
177
|
+
const { hierarchy } = await reverseGeo.reverseGeocode(params.lat, params.lon);
|
|
178
|
+
if (hierarchy.length === 0)
|
|
179
|
+
return null;
|
|
180
|
+
const address = {};
|
|
181
|
+
for (const place of hierarchy) {
|
|
182
|
+
const key = PLACETYPE_TO_KEY[place.placetype];
|
|
183
|
+
if (key && !address[key])
|
|
184
|
+
address[key] = place.name;
|
|
185
|
+
}
|
|
186
|
+
const deepest = hierarchy[0];
|
|
187
|
+
if (deepest.country)
|
|
188
|
+
address.country_code = deepest.country.toLowerCase();
|
|
189
|
+
const resolved = {
|
|
190
|
+
lat: params.lat,
|
|
191
|
+
lon: params.lon,
|
|
192
|
+
address,
|
|
193
|
+
displayName: hierarchy.map((p) => p.name).join(", "),
|
|
194
|
+
placeId: deepest.id,
|
|
195
|
+
boundingbox: deepest.bbox
|
|
196
|
+
? [
|
|
197
|
+
String(deepest.bbox.minLat),
|
|
198
|
+
String(deepest.bbox.maxLat),
|
|
199
|
+
String(deepest.bbox.minLon),
|
|
200
|
+
String(deepest.bbox.maxLon),
|
|
201
|
+
]
|
|
202
|
+
: undefined,
|
|
203
|
+
};
|
|
204
|
+
const out = toNominatimResult(resolved, { addressdetails: params.addressdetails });
|
|
205
|
+
out.annotations = toOpenCage(await annotate({ lat: params.lat, lon: params.lon, countryCode: address.country_code }));
|
|
206
|
+
return out;
|
|
207
|
+
},
|
|
208
|
+
async status() {
|
|
209
|
+
return { status: 0, message: "OK" };
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
express()
|
|
213
|
+
.use(createNominatimRouter(engine))
|
|
214
|
+
.listen(port, host, () => {
|
|
215
|
+
console.error(`[@mailwoman/nominatim] listening on http://${host}:${port}`);
|
|
216
|
+
console.error(` wof: ${adminDbPath ?? "(none found — set MAILWOMAN_WOF_DB)"}`);
|
|
217
|
+
console.error(` endpoints: GET /search GET /reverse GET /lookup GET /status`);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
const command = process.argv[2];
|
|
221
|
+
switch (command) {
|
|
222
|
+
case "serve":
|
|
223
|
+
await serve();
|
|
224
|
+
break;
|
|
225
|
+
default:
|
|
226
|
+
console.error("Usage: mailwoman-nominatim serve [--port 8080] [--host 0.0.0.0] [--data <path>]");
|
|
227
|
+
process.exit(command ? 1 : 0);
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=cli.js.map
|
package/out/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":"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"}
|
package/out/index.d.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `@mailwoman/nominatim` — a Nominatim-compatible HTTP geocoding API over the Mailwoman engine.
|
|
7
|
+
*
|
|
8
|
+
* The package is intentionally engine-agnostic: {@link createNominatimRouter} takes a
|
|
9
|
+
* {@link NominatimEngine} (the thing that actually parses + resolves) and exposes it under the
|
|
10
|
+
* endpoint shapes + response format a Nominatim client expects. The CLI (`./cli.ts`) wires the
|
|
11
|
+
* real Mailwoman engine; tests can inject a fake. This keeps the compat surface isolated from the
|
|
12
|
+
* resolver wiring.
|
|
13
|
+
*
|
|
14
|
+
* Implementation is staged across the epic (#801): #804 the result formatter, #802 `/search`, #803
|
|
15
|
+
* `/reverse`, #805 `/lookup` + `/status`. Routes whose engine method is absent answer `501`.
|
|
16
|
+
*/
|
|
17
|
+
import type { OpenCageAnnotations } from "@mailwoman/annotations";
|
|
18
|
+
import { Router } from "express";
|
|
19
|
+
/** Output serialization formats Nominatim supports. `jsonv2` is the modern default. */
|
|
20
|
+
export type NominatimFormat = "jsonv2" | "json" | "geojson";
|
|
21
|
+
/**
|
|
22
|
+
* The structured address breakdown returned under `address` when `addressdetails=1`. Keys mirror
|
|
23
|
+
* Nominatim's OSM-derived tag names; populated from Mailwoman's `ComponentTag` / resolved ancestor
|
|
24
|
+
* lineage (mapping owned by #804).
|
|
25
|
+
*/
|
|
26
|
+
export interface NominatimAddressDetails {
|
|
27
|
+
house_number?: string;
|
|
28
|
+
road?: string;
|
|
29
|
+
neighbourhood?: string;
|
|
30
|
+
suburb?: string;
|
|
31
|
+
city?: string;
|
|
32
|
+
town?: string;
|
|
33
|
+
village?: string;
|
|
34
|
+
county?: string;
|
|
35
|
+
state?: string;
|
|
36
|
+
postcode?: string;
|
|
37
|
+
country?: string;
|
|
38
|
+
country_code?: string;
|
|
39
|
+
[key: string]: string | undefined;
|
|
40
|
+
}
|
|
41
|
+
/** A single Nominatim result object (the shape geopy and friends parse). */
|
|
42
|
+
export interface NominatimResult {
|
|
43
|
+
place_id: number | string;
|
|
44
|
+
licence: string;
|
|
45
|
+
osm_type?: string;
|
|
46
|
+
osm_id?: number | string;
|
|
47
|
+
lat: string;
|
|
48
|
+
lon: string;
|
|
49
|
+
display_name: string;
|
|
50
|
+
/** `[south, north, west, east]` as strings, per Nominatim. */
|
|
51
|
+
boundingbox?: [string, string, string, string];
|
|
52
|
+
class?: string;
|
|
53
|
+
type?: string;
|
|
54
|
+
importance?: number;
|
|
55
|
+
place_rank?: number;
|
|
56
|
+
address?: NominatimAddressDetails;
|
|
57
|
+
/** Present when `format=geojson` or `polygon_geojson=1`. */
|
|
58
|
+
geojson?: unknown;
|
|
59
|
+
/** OpenCage-style enrichment block (timezone, coordinate formats, …); attached by the engine. */
|
|
60
|
+
annotations?: OpenCageAnnotations;
|
|
61
|
+
}
|
|
62
|
+
/** Parsed `/search` parameters (free-text OR structured; never both). */
|
|
63
|
+
export interface NominatimSearchParams {
|
|
64
|
+
q?: string;
|
|
65
|
+
street?: string;
|
|
66
|
+
city?: string;
|
|
67
|
+
county?: string;
|
|
68
|
+
state?: string;
|
|
69
|
+
country?: string;
|
|
70
|
+
postalcode?: string;
|
|
71
|
+
countrycodes?: string[];
|
|
72
|
+
limit: number;
|
|
73
|
+
viewbox?: [number, number, number, number];
|
|
74
|
+
bounded?: boolean;
|
|
75
|
+
addressdetails?: boolean;
|
|
76
|
+
format: NominatimFormat;
|
|
77
|
+
acceptLanguage?: string;
|
|
78
|
+
}
|
|
79
|
+
/** Parsed `/reverse` parameters. */
|
|
80
|
+
export interface NominatimReverseParams {
|
|
81
|
+
lat: number;
|
|
82
|
+
lon: number;
|
|
83
|
+
zoom?: number;
|
|
84
|
+
addressdetails?: boolean;
|
|
85
|
+
format: NominatimFormat;
|
|
86
|
+
acceptLanguage?: string;
|
|
87
|
+
}
|
|
88
|
+
/** Parsed `/lookup` parameters. */
|
|
89
|
+
export interface NominatimLookupParams {
|
|
90
|
+
osmIds: string[];
|
|
91
|
+
addressdetails?: boolean;
|
|
92
|
+
format: NominatimFormat;
|
|
93
|
+
}
|
|
94
|
+
/** Nominatim `/status` payload. */
|
|
95
|
+
export interface NominatimStatus {
|
|
96
|
+
status: number;
|
|
97
|
+
message: string;
|
|
98
|
+
data_updated?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The geocoding engine the router delegates to. Each method is optional; a route whose method is
|
|
102
|
+
* not provided answers `501 Not Implemented`. The real implementation (Mailwoman parse → resolve,
|
|
103
|
+
* plus `WofReverseGeocoder`) is wired by the CLI and fleshed out across #802–#805.
|
|
104
|
+
*/
|
|
105
|
+
export interface NominatimEngine {
|
|
106
|
+
search?(params: NominatimSearchParams): Promise<NominatimResult[]>;
|
|
107
|
+
reverse?(params: NominatimReverseParams): Promise<NominatimResult | null>;
|
|
108
|
+
lookup?(params: NominatimLookupParams): Promise<NominatimResult[]>;
|
|
109
|
+
status?(): Promise<NominatimStatus>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Build the Nominatim-compatible router around an injected {@link NominatimEngine}. Query-param
|
|
113
|
+
* parsing lives here; the result _formatting_ (jsonv2 vs geojson envelope, `address` projection) is
|
|
114
|
+
* #804 and currently passes the engine's results through verbatim.
|
|
115
|
+
*/
|
|
116
|
+
export declare function createNominatimRouter(engine: NominatimEngine): Router;
|
|
117
|
+
/**
|
|
118
|
+
* A resolved address in a neutral shape, the input to {@link toNominatimResult}. The engine maps its
|
|
119
|
+
* native geocode/reverse result into this; the formatter renders it as a Nominatim result. This is
|
|
120
|
+
* the #804 mapping seam, kept dependency-free (no `@mailwoman/*` import) so it stays
|
|
121
|
+
* unit-testable.
|
|
122
|
+
*/
|
|
123
|
+
export interface ResolvedAddress {
|
|
124
|
+
lat: number | null;
|
|
125
|
+
lon: number | null;
|
|
126
|
+
address: NominatimAddressDetails;
|
|
127
|
+
/** Pre-rendered display name; falls back to the address values joined by ", ". */
|
|
128
|
+
displayName?: string;
|
|
129
|
+
category?: string;
|
|
130
|
+
type?: string;
|
|
131
|
+
importance?: number;
|
|
132
|
+
placeRank?: number;
|
|
133
|
+
boundingbox?: [string, string, string, string];
|
|
134
|
+
/** A stable id from the resolver (WOF/GERS); a deterministic hash is used when absent. */
|
|
135
|
+
placeId?: string | number;
|
|
136
|
+
}
|
|
137
|
+
/** The attribution string emitted as `licence` (the data sources Mailwoman resolves over). */
|
|
138
|
+
export declare const MAILWOMAN_LICENCE = "Data \u00A9 Who's On First, Overture Maps, OpenAddresses, US Census TIGER";
|
|
139
|
+
/**
|
|
140
|
+
* Render a {@link ResolvedAddress} as a Nominatim result. `addressdetails` gates the `address`
|
|
141
|
+
* block, matching Nominatim. The `annotations` block is attached by the caller (empty until the
|
|
142
|
+
* annotations layer lands).
|
|
143
|
+
*/
|
|
144
|
+
export declare function toNominatimResult(r: ResolvedAddress, opts?: {
|
|
145
|
+
addressdetails?: boolean;
|
|
146
|
+
}): NominatimResult;
|
|
147
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/out/index.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `@mailwoman/nominatim` — a Nominatim-compatible HTTP geocoding API over the Mailwoman engine.
|
|
7
|
+
*
|
|
8
|
+
* The package is intentionally engine-agnostic: {@link createNominatimRouter} takes a
|
|
9
|
+
* {@link NominatimEngine} (the thing that actually parses + resolves) and exposes it under the
|
|
10
|
+
* endpoint shapes + response format a Nominatim client expects. The CLI (`./cli.ts`) wires the
|
|
11
|
+
* real Mailwoman engine; tests can inject a fake. This keeps the compat surface isolated from the
|
|
12
|
+
* resolver wiring.
|
|
13
|
+
*
|
|
14
|
+
* Implementation is staged across the epic (#801): #804 the result formatter, #802 `/search`, #803
|
|
15
|
+
* `/reverse`, #805 `/lookup` + `/status`. Routes whose engine method is absent answer `501`.
|
|
16
|
+
*/
|
|
17
|
+
import { Router } from "express";
|
|
18
|
+
const DEFAULT_LIMIT = 10;
|
|
19
|
+
function parseFormat(raw) {
|
|
20
|
+
return raw === "geojson" || raw === "json" ? raw : "jsonv2";
|
|
21
|
+
}
|
|
22
|
+
function parseBool(raw) {
|
|
23
|
+
return raw === "1" || raw === "true";
|
|
24
|
+
}
|
|
25
|
+
function asString(raw) {
|
|
26
|
+
return typeof raw === "string" && raw.length > 0 ? raw : undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the Nominatim-compatible router around an injected {@link NominatimEngine}. Query-param
|
|
30
|
+
* parsing lives here; the result _formatting_ (jsonv2 vs geojson envelope, `address` projection) is
|
|
31
|
+
* #804 and currently passes the engine's results through verbatim.
|
|
32
|
+
*/
|
|
33
|
+
export function createNominatimRouter(engine) {
|
|
34
|
+
const router = Router();
|
|
35
|
+
const search = async (req, res) => {
|
|
36
|
+
if (!engine.search) {
|
|
37
|
+
res.status(501).json({ error: "search not implemented (see #802)" });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const q = req.query;
|
|
41
|
+
const params = {
|
|
42
|
+
q: asString(q["q"]),
|
|
43
|
+
street: asString(q["street"]),
|
|
44
|
+
city: asString(q["city"]),
|
|
45
|
+
county: asString(q["county"]),
|
|
46
|
+
state: asString(q["state"]),
|
|
47
|
+
country: asString(q["country"]),
|
|
48
|
+
postalcode: asString(q["postalcode"]),
|
|
49
|
+
countrycodes: asString(q["countrycodes"])?.split(","),
|
|
50
|
+
limit: Number(q["limit"] ?? DEFAULT_LIMIT) || DEFAULT_LIMIT,
|
|
51
|
+
bounded: parseBool(q["bounded"]),
|
|
52
|
+
addressdetails: parseBool(q["addressdetails"]),
|
|
53
|
+
format: parseFormat(q["format"]),
|
|
54
|
+
acceptLanguage: asString(q["accept-language"]),
|
|
55
|
+
};
|
|
56
|
+
res.json(await engine.search(params));
|
|
57
|
+
};
|
|
58
|
+
const reverse = async (req, res) => {
|
|
59
|
+
if (!engine.reverse) {
|
|
60
|
+
res.status(501).json({ error: "reverse not implemented (see #803)" });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const q = req.query;
|
|
64
|
+
const lat = Number(q["lat"]);
|
|
65
|
+
const lon = Number(q["lon"]);
|
|
66
|
+
if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
|
|
67
|
+
res.status(400).json({ error: "lat and lon are required" });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (lat < -90 || lat > 90 || lon < -180 || lon > 180) {
|
|
71
|
+
res.status(400).json({ error: "lat must be in [-90, 90] and lon in [-180, 180]" });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const params = {
|
|
75
|
+
lat,
|
|
76
|
+
lon,
|
|
77
|
+
zoom: q["zoom"] != null ? Number(q["zoom"]) : undefined,
|
|
78
|
+
addressdetails: parseBool(q["addressdetails"]),
|
|
79
|
+
format: parseFormat(q["format"]),
|
|
80
|
+
acceptLanguage: asString(q["accept-language"]),
|
|
81
|
+
};
|
|
82
|
+
res.json(await engine.reverse(params));
|
|
83
|
+
};
|
|
84
|
+
const lookup = async (req, res) => {
|
|
85
|
+
if (!engine.lookup) {
|
|
86
|
+
res.status(501).json({ error: "lookup not implemented (see #805)" });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const params = {
|
|
90
|
+
osmIds: asString(req.query["osm_ids"])?.split(",") ?? [],
|
|
91
|
+
addressdetails: parseBool(req.query["addressdetails"]),
|
|
92
|
+
format: parseFormat(req.query["format"]),
|
|
93
|
+
};
|
|
94
|
+
res.json(await engine.lookup(params));
|
|
95
|
+
};
|
|
96
|
+
const status = async (_req, res) => {
|
|
97
|
+
if (!engine.status) {
|
|
98
|
+
res.json({ status: 0, message: "OK" });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
res.json(await engine.status());
|
|
102
|
+
};
|
|
103
|
+
// Safety net: a malformed query (whitespace-only, absurdly long, control chars) or an engine fault
|
|
104
|
+
// must never crash the process into a stack-trace 500. Wrap every handler so an unexpected throw
|
|
105
|
+
// becomes a clean JSON error.
|
|
106
|
+
const safe = (fn) => async (req, res, next) => {
|
|
107
|
+
try {
|
|
108
|
+
await fn(req, res, next);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
if (!res.headersSent)
|
|
112
|
+
res.status(500).json({ error: "internal error" });
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
router.get("/search", safe(search));
|
|
116
|
+
router.get("/reverse", safe(reverse));
|
|
117
|
+
router.get("/lookup", safe(lookup));
|
|
118
|
+
router.get("/status", safe(status));
|
|
119
|
+
return router;
|
|
120
|
+
}
|
|
121
|
+
/** The attribution string emitted as `licence` (the data sources Mailwoman resolves over). */
|
|
122
|
+
export const MAILWOMAN_LICENCE = "Data © Who's On First, Overture Maps, OpenAddresses, US Census TIGER";
|
|
123
|
+
function stableId(seed) {
|
|
124
|
+
let h = 5381;
|
|
125
|
+
for (let i = 0; i < seed.length; i++)
|
|
126
|
+
h = (h * 33) ^ seed.charCodeAt(i);
|
|
127
|
+
return h >>> 0;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Render a {@link ResolvedAddress} as a Nominatim result. `addressdetails` gates the `address`
|
|
131
|
+
* block, matching Nominatim. The `annotations` block is attached by the caller (empty until the
|
|
132
|
+
* annotations layer lands).
|
|
133
|
+
*/
|
|
134
|
+
export function toNominatimResult(r, opts = {}) {
|
|
135
|
+
const displayName = r.displayName ?? Object.values(r.address).filter(Boolean).join(", ");
|
|
136
|
+
const lat = r.lat != null ? String(r.lat) : "";
|
|
137
|
+
const lon = r.lon != null ? String(r.lon) : "";
|
|
138
|
+
const result = {
|
|
139
|
+
place_id: r.placeId ?? stableId(`${lat},${lon},${displayName}`),
|
|
140
|
+
licence: MAILWOMAN_LICENCE,
|
|
141
|
+
lat,
|
|
142
|
+
lon,
|
|
143
|
+
display_name: displayName,
|
|
144
|
+
};
|
|
145
|
+
if (r.category != null)
|
|
146
|
+
result.class = r.category;
|
|
147
|
+
if (r.type != null)
|
|
148
|
+
result.type = r.type;
|
|
149
|
+
if (r.importance != null)
|
|
150
|
+
result.importance = r.importance;
|
|
151
|
+
if (r.placeRank != null)
|
|
152
|
+
result.place_rank = r.placeRank;
|
|
153
|
+
if (r.boundingbox)
|
|
154
|
+
result.boundingbox = r.boundingbox;
|
|
155
|
+
if (opts.addressdetails)
|
|
156
|
+
result.address = r.address;
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=index.js.map
|
package/out/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mailwoman/nominatim",
|
|
3
|
+
"version": "4.15.1",
|
|
4
|
+
"description": "Nominatim drop-in — a Nominatim-compatible HTTP geocoding API (search / reverse / lookup / status) over the Mailwoman engine. Run it with `npx @mailwoman/nominatim serve`.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/sister-software/mailwoman.git",
|
|
9
|
+
"directory": "nominatim"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
".": "./out/index.js"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@mailwoman/annotations": "4.15.1",
|
|
18
|
+
"@mailwoman/codex": "4.15.0",
|
|
19
|
+
"@mailwoman/neural": "4.15.0",
|
|
20
|
+
"@mailwoman/nuts-lookup": "4.15.1",
|
|
21
|
+
"@mailwoman/resolver": "4.15.0",
|
|
22
|
+
"@mailwoman/resolver-wof-sqlite": "4.15.0",
|
|
23
|
+
"@mailwoman/spatial": "4.15.0",
|
|
24
|
+
"@mailwoman/timezone-lookup": "4.15.1",
|
|
25
|
+
"@mailwoman/un-locode-lookup": "4.15.1",
|
|
26
|
+
"express": "^5.2.1",
|
|
27
|
+
"mailwoman": "4.15.0"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"out/**/*.js",
|
|
31
|
+
"out/**/*.js.map",
|
|
32
|
+
"out/**/*.d.ts",
|
|
33
|
+
"out/**/*.d.ts.map",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"bin": "./out/cli.js",
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
}
|
|
40
|
+
}
|