feat(search): Nominatim as the last-resort geocoder (#573)

Supersedes #350 by @sendmebits, ported onto the current component layout with fixes from review.

Verified before merge: format, package boundaries, unit suite, build, and the browser tracking suite; a browser harness for the change where one applies; adversarial review applied.

Co-authored-by: sendmebits <[email protected]>
This commit is contained in:
Bilawal Sidhuandsendmebits authored and GitHub committed 2026-09-14 21:22:08 -05:00
1 parent cca6442997
commit 7fa0cfbb26
15 files changed
+1077 -48

No files matched your search

+17 -2
View File
@@ -8,8 +8,8 @@ import { createPresetGeocoder } from './presetGeocoder.js';
/**
* Coordinates and bundled names first — both answer offline and with no key —
* then Google when configured, then keyless Photon. Transport stays local to
* setup.
* then Google when configured, then keyless Photon, then the local Nominatim
* route as a last resort. Transport stays local to setup.
*
* `presets` is the caller's bundled place data. It is passed in rather than
* imported so this package keeps reading no application state; with none
@@ -43,6 +43,21 @@ export function createDefaultPlaceSearch({
},
}),
createPhotonGeocoder({ fetchImpl, endpoint: endpoints.photon }),
// Last resort: the local Nominatim route, which answers with no key when
// neither of the two above did. It speaks the same result shape, so it
// rides the existing Google adapter rather than needing its own.
createGoogleGeocoder({
request(query, { bias, signal }) {
const params = new URLSearchParams({ q: query });
if (bias) params.set('bounds', bias);
return fetchImpl(
`${endpoints.nominatim || '/api/geocode'}?${params}`,
{
signal,
},
);
},
}),
],
});
return {