@mostajs/geo
v0.1.0
Published
Geolocation module for @mostajs — GPS, geocoding, distance, geofencing, multi-provider maps (Google Maps, OpenStreetMap/MapLibre, Mapbox), demo mode
Maintainers
Readme
@mostajs/geo
Géolocalisation pour @mostajs — géocodage, distance, geofencing et cartes multi-fournisseurs (OpenStreetMap/MapLibre par défaut, Google, Mapbox). Mode démo sans clé, DB-agnostique, pensé RGPD + Maghreb. Zéro lock-in.
Auteur : Dr Hamid MADANI [email protected] · Licence : AGPL-3.0-or-later
⚠ v0.1 — cœur. Géocodage (OSM/démo), distance, geofencing, position navigateur, carte MapLibre. Routing, providers Google/Mapbox, Plus Codes et persistance arrivent ensuite (cf.
docs/PLAN-DEV-GEO.md). Les décisions d'architecture sont dansdocs/DECISIONS-GEO-04062026.md.
Install
npm install @mostajs/geo
# carte (optionnel) :
npm install react maplibre-glUsage
Distance & proximité (cœur pur, sans réseau)
import { distance, nearest, isWithin } from '@mostajs/geo'
const Alger = { lat: 36.7538, lon: 3.0588 }
const Oran = { lat: 35.6969, lon: -0.6331 }
distance(Alger, Oran, 'km') // ≈ 351
nearest(Alger, [Oran, { lat: 36.36, lon: 6.61 }]) // le plus proche d'Alger
// Geofence : cercle OU polygone
isWithin(Alger, { id: 'z1', center: Alger, radiusM: 500 }) // true
isWithin(Alger, { id: 'z2', polygon: [/* ≥3 sommets LatLng */] }) // ray-castingGéocodage (OpenStreetMap par défaut, gratuit, sans clé)
import { geocode, reverseGeocode } from '@mostajs/geo'
const r = await geocode('Place des Martyrs, Alger', { provider: 'osm' })
r.results[0] // { lat, lon, label, city, country, ... }
r.isRealData // true
await reverseGeocode({ lat: 36.7538, lon: 3.0588 }, { provider: 'osm' })Mode démo (sans clé, sans réseau)
const r = await geocode('Alger') // provider 'osm' par défaut → réseau
const d = await geocode('Alger', { provider: 'demo' })
d.isRealData // false (données factices)
mapboxsansapiKeybasculent silencieusement en mode démo (isRealData: false) — comme@mostajs/weather.
Position du navigateur (côté client)
import { getCurrentPosition, watch } from '@mostajs/geo'
const here = await getCurrentPosition({ highAccuracy: true, minAccuracyM: 50 })
const stop = watch((p) => console.log(p.lat, p.lon), { minAccuracyM: 30 })
// ... stop() pour arrêter le suiviCarte React (MapLibre — peer-deps optionnelles)
import { MapView } from '@mostajs/geo/react'
<MapView
center={{ lat: 36.7538, lon: 3.0588 }}
markers={[{ lat: 36.7538, lon: 3.0588, label: 'Alger' }]}
onClick={(p) => console.log('clic', p)}
/>Sans clé : fond OpenStreetMap libre. Avec
config.apiKey: style vectoriel MapTiler.
Geohash (proximité)
import { geohashEncode, geohashDecode } from '@mostajs/geo'
geohashEncode({ lat: 36.7538, lon: 3.0588 }, 7) // 'snz...' (préfixe partagé = proximité)Référence API (v0.1)
| Export | Rôle |
|---|---|
| distance(a, b, unit?) | distance Haversine ('m'|'km'|'mi') |
| bearing(a, b) | cap en degrés [0, 360) |
| nearest(from, points) | point le plus proche (ou null) |
| isWithin(point, fence) | geofence cercle (center+radiusM) ou polygone |
| boundingBox(points) | boîte englobante |
| geohashEncode/Decode | encodage proximité |
| geocode/reverseGeocode/suggest | géocodage (osm/demo ; google/mapbox en v0.2) |
| getCurrentPosition/watch | position navigateur (+ seuil minAccuracyM) |
| toGeoJsonPosition/... | conversions GeoJSON (⚠ [lon, lat]) |
| MapView (/react) | carte MapLibre |
| geoModuleRegistration | métadonnées @mostajs/socle |
Pièges
- Interne
{lat, lon}mais GeoJSON =[lon, lat](RFC 7946) — convertir explicitement. provider: 'osm'(Nominatim) : respecter la usage policy (User-Agent, 1 req/s) ; auto-héberger à l'échelle.- La position est une donnée personnelle (RGPD + loi 18-07) : recueillir le consentement.
Composition (DEVRULES §10)
Config via @mostajs/config, persistance/index via @mostajs/data-plug (orm/net), temps réel via @mostajs/net, audit via @mostajs/audit. @mostajs/geo ne ship pas de base et ne réimplémente aucune de ces capacités.
Licence AGPL-3.0-or-later — Dr Hamid MADANI [email protected]
