npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

duara-geo

v2.0.0

Published

Client and map widget for a self-hosted duara-geo deployment: routing, distance matrices, isochrones, multi-drop, geocoding, places, road attributes, elevation, time zones, tiles and static maps over OpenStreetMap.

Readme

duara-geo

The JavaScript client and map widget for a duara-geo deployment: routing, distance matrices, isochrones, multi-drop sequencing, geocoding, places, road attributes, map matching, elevation, time zones, tiles and static maps — over OpenStreetMap, from a server you run.

It talks to your deployment. There is no hosted service behind this package and no account to create; baseUrl is where you put the container.

npm install duara-geo

No dependencies. About 20 KB. Works in Node 18+, in any bundler, and from a plain <script> tag with no build step at all.

Using it

import DuaraGeo from 'duara-geo';

const geo = new DuaraGeo({ baseUrl: 'https://geo.example.com', key: 'dgk_live_…' });

const trip = await geo.route({
  locations: [
    { latitude: 0.3476, longitude: 32.5825 },
    { latitude: 0.3556, longitude: 32.6136 },
  ],
});

console.log(trip.distance_km, 'km,', Math.round(trip.seconds / 60), 'min');

CommonJS works the same way:

const DuaraGeo = require('duara-geo');

baseUrl is optional in a browser, where it defaults to the page's own origin — right when the service sits behind the same proxy. Off a page there is no origin to inherit, so the constructor throws rather than letting the first request fail somewhere inside fetch.

A map, without a mapping library

The package ships a small raster map widget: tiles, markers, lines, polygons, circles and popups, in about twenty kilobytes with no dependencies. It is browser-only and is not loaded until you construct it.

const map = geo.map('map', { center: [32.5825, 0.3476], zoom: 13 });

map.addMarker([32.5825, 0.3476], { label: 'A', draggable: true });
map.addPolyline(trip.shape, { precision: trip.shape_precision });
map.on('click', (e) => console.log(e.lngLat));

Coordinates in the widget are [longitude, latitude], the order GeoJSON uses. Coordinates in the API are { latitude, longitude } objects. That is deliberate: the two conventions exist, and a single silent [a, b] at the boundary is how a delivery ends up in the wrong hemisphere.

For a vector basemap, 3D or clustering, point MapLibre GL at your deployment's /v1/style.json instead. The two coexist and the rest of this client keeps working next to it.

From a <script> tag

Your own deployment serves the same file, so an air-gapped page needs no CDN:

<script src="https://geo.example.com/sdk/duara-geo.js"></script>

Or from a CDN, if you would rather:

<script src="https://cdn.jsdelivr.net/npm/duara-geo@2/duara-geo.js"></script>

Both define window.DuaraGeo and window.DuaraMap.

What is actually in the box

const caps = await geo.capabilities();   // cached after the first call
if (geo.can('places_nearby')) { /* show the "what's near me" button */ }

Every service except routing is optional, because every one of them needs a backend or a dataset somebody chose to run. capabilities() reports what this deployment can answer and, for the rest, why it is off in terms of the configuration that would turn it on. Building a UI from it is the difference between hiding a feature and shipping one that 501s.

| | | |---|---| | routing | route matrix isochrone tour | | roads | mapMatch nearestRoads speedLimits | | places | geocode reverseGeocode autocomplete searchPlaces nearbyPlaces placeDetails validateAddress | | environment | elevation timezone | | URLs | tileUrl styleUrl staticMapUrl embedUrl | | browser | map |

Three things worth knowing before you build on it

method is not decoration. A matrix cell comes back as road or great_circle. The second is a real answer you can price from, but it is not the answer you asked for, and rendering the two identically is how a straight-line estimate reaches a customer as a road distance.

const leg = res.legs[0][0];
if (leg.method !== 'road') showEstimateBadge();

Decode shapes with the precision the response gave you. shape_precision is 6 on /v1 and 5 on the compatibility surface. Assuming 5 for a precision-6 shape puts a Kampala route in the Gulf of Guinea. A route through three or more points returns several legs joined with ; — decodePolyline splits them; a decoder that does not will draw a rectangle across a continent.

import { decodePolyline } from 'duara-geo';
const coords = decodePolyline(trip.shape, trip.shape_precision);

Absent is not zero. metres on an elevation sample and speed_limit_kph on a road edge are missing rather than 0 when unknown, because 0 m and 0 km/h are both plausible readings and both would be false. The TypeScript definitions mark them optional for exactly this reason.

Errors

import { GeoError } from 'duara-geo';

try {
  await geo.route({ locations });
} catch (err) {
  if (err instanceof GeoError) {
    err.code;        // 'unroutable', 'invalid_coordinate', 'rate_limited', …
    err.status;      // HTTP status, or 0 for a transport failure
    err.retryable;   // whether asking again could plausibly help
    err.requestId;   // quote this in a support conversation
  }
}

Branch on code, not on the status: unroutable and invalid_coordinate are both 422 and need opposite handling.

TypeScript

Types ship with the package; nothing to install. They are checked against every module resolution mode TypeScript has, so both import styles are real:

// ESM
import DuaraGeo, { type RouteResponse, type Place, GeoError } from 'duara-geo';

// CommonJS -- the export is `module.exports = DuaraGeo`, so the types come through the class
import DuaraGeo = require('duara-geo');
const trip: DuaraGeo.RouteResponse = await geo.route({ locations });

Other languages

Python · Go · PHP · or generate a client for anything else from your deployment's /openapi.json.

Releasing

OTP=123456 make sdk-js-publish        # from the repository root

The target refreshes the copy from web/sdk, runs the package tests and the drift check, and refuses to publish an UNLICENSED package or an account without a second factor. npm requires 2FA to publish; OTP is the six digits from your authenticator.

Licence

MIT. Use it, ship it, vendor it into your build — a client library for a paid service is worthless if you cannot.

The service it talks to is proprietary and separate: this package grants you nothing in respect of running your own duara-geo deployment. Talk to us about that.