@molecule/api-geolocation-photon
Provider bond · geolocation · API (Node) · v1.1.1 · Apache-2.0
Photon (OpenStreetMap) geolocation provider for molecule.dev — point it at your own instance
npm install @molecule/api-geolocation-photonnpm · Source on GitHub · Implements @molecule/api-geolocation
How it works
@molecule/api-geolocation-photon is a provider bond on the API (Node) side: it implements the geolocation core interface (@molecule/api-geolocation) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setProvider } from '@molecule/api-geolocation'
import { provider } from '@molecule/api-geolocation-photon'
setProvider(provider)Works with: @molecule/api-geolocation
Reference
Photon (OpenStreetMap) geolocation provider for molecule.dev.
Implements the GeolocationProvider interface using a Photon instance for
geocoding, reverse geocoding, and search-as-you-type (autocomplete).
Distance calculations use the Haversine formula. Timezone lookups are not
supported.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { setProvider } from '@molecule/api-geolocation'
import { provider } from '@molecule/api-geolocation-photon'
setProvider(provider)
Type
provider
Installation
npm install @molecule/api-geolocation-photon @molecule/api-geolocation
API
Interfaces
PhotonGeolocationConfig
Configuration options for the Photon geolocation provider.
interface PhotonGeolocationConfig {
/**
* Base URL of the Photon instance.
* Defaults to the public instance `'https://photon.komoot.io'`.
* Point this at a self-hosted Photon for production volume — the public
* instance serves reasonable low-volume use only and throttles or bans
* heavy callers.
*/
baseUrl?: string
/**
* Photon result language (`en`, `de`, `fr`, `nl`, `it`, …). Languages the
* instance has no data for fall back to the default. Defaults to the
* instance default (`en`) when omitted.
*/
language?: string
/** Request timeout in milliseconds. Defaults to `10000`. */
timeout?: number
/** Maximum number of results to return from search queries. Defaults to `10`. */
limit?: number
/**
* ISO 3166-1 alpha-2 country codes to keep (e.g. `['LI', 'CH']`). Photon's
* API has no country-restriction parameter, so results are filtered AFTER
* the query — a restriction combined with a small `limit` can return fewer
* (even zero) results that the upstream actually had.
*/
countryCodes?: string[]
}
Functions
createProvider(config)
Creates a Photon geolocation provider.
function createProvider(config?: PhotonGeolocationConfig): GeolocationProvider
config— Provider configuration (base URL, language, bounds).
Returns: A GeolocationProvider backed by the Photon API.
Constants
provider
The provider implementation, lazily initialized from env: PHOTON_BASE_URL
(self-hosted or alternate instance) and PHOTON_LANG (result language).
const provider: GeolocationProvider
Core Interface
Implements @molecule/api-geolocation interface.
Bond Wiring
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-geolocation'
import { provider } from '@molecule/api-geolocation-photon'
export function setupGeolocationPhoton(): void {
setProvider(provider)
}
Injection Notes
Requirements
Peer dependencies:
@molecule/api-geolocation^1.0.2
Runtime Dependencies
-
@molecule/api-geolocation -
Defaults to the public instance
https://photon.komoot.io, which serves reasonable low-volume use only — heavy usage is throttled or banned, with no availability guarantees. For production volume, run your own Photon (Apache-2.0, an OpenSearch-embedded Java 21 app with an OSM extract) and pointPHOTON_BASE_URL(orconfig.baseUrl) at it. -
Attribution is required by the data, not optional: Photon serves OpenStreetMap data under ODbL — display "© OpenStreetMap contributors" wherever results appear.
-
Coverage is the loaded extract: a self-hosted Photon answers only for the region its index was built from; queries outside it return
[], not an error. Build the index from the region your app actually geocodes. -
No server-side country filter:
countryCodesfilters results AFTER the query, so a restriction combined with a small limit can return fewer results than matched. -
Results are as-typed-as-Photon-parsed them: OSM data is community edited — treat a geocode result as a suggestion to confirm, never as a verified postal address (the same caution applies to every OSM geocoder).
-
getTimezoneis not implemented (optional core capability) — feature- detect per the core's remarks, or use@molecule/api-geolocation-google.
E2E Tests
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
- A known input resolves to plausibly-correct results: a real address
passed to
geocode()returns coordinates in roughly the right place (a famous landmark lands inside its own city, not the middle of the ocean), and a known lat/lng passed toreverseGeocode()names the right city — never an empty array,null,0,0, or a hardcoded placeholder. - The app actually CONSUMES the result downstream, verified on screen:
the map recenters on the geocoded point, a "near me" list is sorted or
filtered by
distance()(closest first), or the address form marks a real address valid and a bogus one invalid — a coordinate that comes back but changes nothing in the UI is a broken integration, not a pass. - If the app relies on the BROWSER geolocation permission, denying it (or letting it time out) falls back gracefully to manual entry — type or autocomplete an address — never a blank map, a spinner that never resolves, or a crash.
- An unresolvable input (gibberish address, empty
geocode()/reverseGeocode()result) surfaces a clear "location not found" message, not a crash, a silent blank screen, or a default location shown as if real. - PRIVACY: a user's precise coordinates are not exposed to other users or written to logs beyond what the feature needs (persist/show only the granularity required — e.g. city, not raw lat/lng), and the geocoding provider key stays SERVER-SIDE (app screens call YOUR API, never the geocoding service directly).