@smarthivelabs-devs/geocore-node
v1.6.5
Published
Geocore Node.js server SDK — mapping and geocoding for backend services
Readme
@smarthivelabs-devs/geocore-node
Node.js / server-side SDK for Geocore. Lightweight HTTP client — no browser dependencies. Covers all 14 geo-operations, weather, the SmartHive Pricing Engine, and two new Location Intelligence operations built for delivery and logistics apps.
Installation
npm install @smarthivelabs-devs/geocore-node
# or
pnpm add @smarthivelabs-devs/geocore-nodeRequires Node.js 18+ (uses native fetch and AbortSignal.timeout).
Setup
import { GeocoreNodeClient } from '@smarthivelabs-devs/geocore-node';
const geocore = new GeocoreNodeClient({
apiKey: process.env.GEOCORE_API_KEY!,
// baseUrl — optional, defaults to https://geocore.smarthivelabs.dev/api
// timeout — optional, default 8000 ms
});GeocoreNodeClientConfig
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| apiKey | string | Yes | Your Geocore project API key (x-api-key header) |
| baseUrl | string | No | Override backend URL — defaults to production |
| timeout | number | No | Request timeout in ms — default 8000 |
Geocoding
// Address → coordinates
const result = await geocore.geocode('Kaneshie Market, Accra');
console.log(result.coordinates); // { lat: 5.5558, lng: -0.2318 }
console.log(result.provider); // 'mapbox'
// Coordinates → address
const rev = await geocore.reverse(5.5558, -0.2318);
console.log(rev.formattedAddress);Location Intelligence ✨
Two new operations designed for logistics and delivery apps — where a wrong-city geocode costs money.
geocodeMulti — all-provider fan-out
Returns every unique candidate from all configured providers simultaneously, deduplicated by 200 m proximity. Use this when you need a diverse result set to score or rank downstream.
const result = await geocore.geocodeMulti('Calabash Restaurant', { limit: 12 });
// result.results — GeocodingResult[] from Mapbox, Google, LocationIQ, HERE, …
// result.provider — 'multi'
// result.status — 'ok' | 'zero_results'
for (const candidate of result.results) {
console.log(`${candidate.provider}: ${candidate.formattedAddress}`);
// mapbox: Calabash Restaurant, Kumasi, Ghana
// google: Calabash, Accra, Ghana
// locationiq: Calabash Cafe, Takoradi, Ghana
}resolveLocation — delivery-grade smart resolution
Accepts a structured LocationIntent and returns scored, ranked candidates with a deterministic resolution state. Prevents silent wrong-city dispatches common in logistics apps — e.g. "Calabash near St. Teresa's in Kumasi" should never silently resolve to "Kalabash Cyber Cafe, Accra".
7-step algorithm:
- Generate up to 8 query variants (name, +city, +area, +type, multi-city fan-out, near landmark)
- Fan-out geocode across all providers → collect raw candidates
- Geocode landmarks and build a geospatial cluster (centroid + radius)
- Score each candidate on 7 dimensions (see weights below)
- Apply mismatch penalties
- Determine resolution state:
exact/probable/approximate/unresolved - Detect multi-city ambiguity for disambiguation UI
Score weights: name similarity 30% · landmark consistency 25% · city/area match 15% · place type 10% · provider confidence 10% · user proximity 5% · place memory 5%
Mismatch penalties: city mismatch −0.40 · landmark >50 km −0.35 · weak name −0.25 · area mismatch −0.20 · wrong type −0.10
import type { LocationIntent, ResolveLocationOptions } from '@smarthivelabs-devs/geocore-node';
const intent: LocationIntent = {
main_place_name: 'Calabash',
landmarks: ["St. Teresa's Hostel"],
city: 'Kumasi',
place_type: 'restaurant',
normalized_queries: ['Calabash Restaurant Kumasi'],
};
const options: ResolveLocationOptions = {
proximity: { lat: 6.6884, lng: -1.6244 }, // user's current location
};
const result = await geocore.resolveLocation(intent, options);
console.log(result.state); // 'exact'
console.log(result.requires_confirmation); // false
console.log(result.explanation);
// "Found Calabash Restaurant, Kumasi, consistent with nearby St. Teresa's Hostel."
const best = result.selected_candidate!;
console.log(best.lat, best.lng); // 6.688..., -1.624...
console.log(best.score); // 0.91
console.log(best.mismatchFlags); // []
// When state is 'approximate' or 'unresolved', show ranked_candidates in UI
for (const c of result.ranked_candidates) {
console.log(`${c.score.toFixed(2)} — ${c.formatted} [${c.city}]`);
}
// Multi-city disambiguation (show "Which Calabash?" UI)
if (result.multi_city_disambiguation) {
const cities = [...new Set(result.ranked_candidates.map(c => c.city))];
console.log('Ambiguous cities:', cities); // ['Kumasi', 'Accra', 'Takoradi']
}Resolution states
| State | Meaning | requires_confirmation |
|---|---|:---:|
| exact | High confidence, no severe flags | false |
| probable | Good score, no severe flags — show for user confirmation | true |
| approximate | Low score but landmark cluster exists — show options | true |
| unresolved | Could not resolve — show map pin / manual entry | true |
Handling place memory bias
Pass userPlaceHistory to boost candidates near places the user has previously confirmed. This is the only app-specific dimension — omit it if you don't have history.
const result = await geocore.resolveLocation(intent, {
proximity: { lat: 6.69, lng: -1.62 },
userPlaceHistory: [
{ label: 'Office', lat: 6.6884, lng: -1.6244, useCount: 12 },
{ label: 'Gym', lat: 6.6720, lng: -1.5980, useCount: 3 },
],
});Directions & Routing
// Turn-by-turn directions
// mode: 'driving' | 'walking' | 'cycling' | 'transit'
const route = await geocore.directions(
{ lat: 5.5558, lng: -0.2318 },
{ lat: 5.6037, lng: -0.1870 },
{ mode: 'driving' }
);
console.log(route.distance); // metres
console.log(route.duration); // seconds
console.log(route.steps); // turn-by-turn instructions
// Optimise waypoint order (Travelling Salesman)
const optimised = await geocore.routeOptimize(
['Accra Mall', 'Airport City, Accra', 'Tema, Ghana'],
{ mode: 'driving' }
);
console.log(optimised.waypoints); // reordered array
// Snap GPS trace to road network
const snapped = await geocore.snapToRoad([
{ lat: 5.556, lng: -0.232 },
{ lat: 5.558, lng: -0.231 },
]);
console.log(snapped.snappedPoints);Places & Search
// Text search — radius in metres (optional)
const places = await geocore.places('pharmacy', { lat: 5.556, lng: -0.232 }, { radius: 500 });
console.log(places.places); // [{ name, coordinates, address, rating, types }]
// Category search around a point
const nearby = await geocore.nearbySearch('hospital', { lat: 5.556, lng: -0.232 });
console.log(nearby.places);
// Autocomplete predictions
const suggest = await geocore.autocomplete('Accra Mall');
console.log(suggest.predictions); // [{ mainText, secondaryText, placeId }]Spatial Analysis
// Elevation
const elev = await geocore.elevation(6.6884, -1.6244);
console.log(elev.elevation); // metres
// Isochrone (reachability polygon)
const iso = await geocore.isochrone(6.6884, -1.6244, [10, 20], { mode: 'driving' });
console.log(iso.polygons); // array of GeoJSON polygons per time band
// Distance matrix
const matrix = await geocore.distanceMatrix(
['Accra, Ghana', 'Kumasi, Ghana'],
['Tema, Ghana', 'Cape Coast, Ghana'],
);
console.log(matrix.matrix); // [[{distance, duration}, …], …]
// Timezone
const tz = await geocore.timezone(6.6884, -1.6244);
console.log(tz.timezone); // 'Africa/Accra'
// Traffic conditions
const traffic = await geocore.traffic(5.556, -0.232);
console.log(traffic.condition); // 'free' | 'slow' | 'heavy' | 'blocked'
// Static map image URL
const map = await geocore.staticMap(5.556, -0.232, { zoom: 14, width: 800, height: 600 });
console.log(map.url);Weather
// Current conditions
const now = await geocore.weather(6.6884, -1.6244);
console.log(now.temperature); // °C
console.log(now.weatherCode); // WMO code (map to your condition enum)
console.log(now.description); // 'Partly cloudy'
console.log(now.humidity); // %
console.log(now.windSpeed); // km/h
// Forecast (1–14 days, default 7)
const forecast = await geocore.forecast(6.6884, -1.6244, 5);
for (const day of forecast.days ?? []) {
console.log(`${day.date}: ${day.tempMin}–${day.tempMax}°C — ${day.description}`);
}SmartHive Pricing Engine
Convert a base price to any user's local currency based on their location or country code. Exchange rates are refreshed by the Geocore backend on the 1st and 15th of each month.
// Auto-detect user's country from lat/lng
const price = await geocore.localizePrice(100, 'GHS', {
lat: 6.5244, // user in Lagos, Nigeria
lng: 3.3792,
});
// { amount: 4500, currency: 'NGN', symbol: '₦', country: 'NG', rate: 45.0, ... }
// Manual country override
const usd = await geocore.localizePrice(100, 'GHS', { countryCode: 'US' });
// { amount: 9.99, currency: 'USD', symbol: '$', ... }
// FX rate pairs
const rate = await geocore.fxRate('USD', 'EUR');
const rates = await geocore.fxRates('USD'); // all rates for a baseProvider Registry
const providers = await geocore.getProviders();
const mapbox = await geocore.getProvider('mapbox');
const geocoders = await geocore.getProvidersForOperation('geocode');Error Handling
All methods throw Error when the request fails or all providers are exhausted.
try {
const result = await geocore.geocode('Unknown XYZ');
} catch (err) {
if (err instanceof Error) {
console.error(err.message);
// 'API error 404: Not Found'
// 'All providers failed for geocode. mapbox: ...'
}
}Requests automatically abort after timeout ms (default 8000).
TypeScript
All methods and responses are fully typed. Import the types you need:
import type {
// Standard geo
GeocodingResult, ReverseGeocodingResult,
DirectionsResult, RouteOptimizeResult, SnapToRoadResult,
PlacesResult, NearbySearchResult, AutocompleteResult,
ElevationResult, IsochroneResult, TimezoneResult,
DistanceMatrixResult, TrafficResult, StaticMapResult,
// Weather
WeatherCurrentResult, WeatherForecastResult,
// Pricing
PricingResult, FxRateResult, FxRatesResult,
// Location intelligence
LocationIntent, ResolveLocationOptions,
LocationResolutionResult, LocationResolutionState,
LocationMismatchFlag, RankedLocationCandidate,
ValidatedLandmark, LandmarkClusterSummary,
PlaceMemoryRecord, GeocodingMultiResult,
} from '@smarthivelabs-devs/geocore-node';License
MIT — SmartHive Labs
