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

mapbase

v1.0.2

Published

Typed HTTP client for the Mapbase Engine API.

Downloads

1,194

Readme

mapbase

npm version

Typed HTTP client for the Mapbase Engine API.

Mapbase · API reference · SDK guide · Dashboard

Table of contents

Install

npm install mapbase
# or
bun add mapbase

Types are generated from the engine's OpenAPI 3.1 spec — they stay in sync with the published API contract.

Quickstart

Every method returns { data, error, rateLimit }. Check error before using data.

import { Mapbase } from "mapbase"

const mapbase = new Mapbase(process.env.MAPBASE_API_KEY!)

const { data, error } = await mapbase.autocomplete.search({
  q: "lis",
  layers: ["locations"],
  country: "PT",
  limit: 5,
})

if (error) {
  console.error(error.code, error.message)
} else {
  for (const suggestion of data.results) {
    console.log(suggestion.id, suggestion.name)
  }
}

Try the live playground before wiring the SDK into your app.

Get an API key

All /v1 routes require an API key. The SDK sends it as x-api-key on every request.

  1. Create an account — sign up at dashboard.mapbase.dev/login (free tier available).
  2. Mint a key — open dashboard.mapbase.dev/api-keys and create a key. Live keys use the mb_live_ prefix.
  3. Pass it to the client — the first constructor argument:
const mapbase = new Mapbase(process.env.MAPBASE_API_KEY!)

Notes

  • You only see the full secret once at creation; keys are SHA-256 hashed at rest.
  • Optionally restrict each key to a list of allowed domains in the dashboard.
  • Do not ship live keys in browser bundles. Call Mapbase from your server, or inject keys server-side (for example via a Next.js server action or API route).
  • mapbase.layers.list() does not require auth; every other /v1 route does.

Documentation

| Resource | URL | | -------- | --- | | Website & playground | mapbase.dev | | SDK guide (walkthroughs) | mapbase.dev/sdk | | Interactive API reference (Scalar) | mapbase.dev/api-reference | | OpenAPI 3.1 spec | mapbase.dev/openapi.json | | LLM docs index (llms.txt) | mapbase.dev/llms.txt | | API reference (Markdown) | mapbase.dev/api-reference.md | | Engine base URL | api.mapbase.dev |

The SDK is codegen'd from the same OpenAPI contract that powers Scalar, so request/response types cannot drift from the live API. For step-by-step examples (autocomplete, point resolve, rate limits), see the SDK guide.

Use /locations to list and filter locations. Use /locations/{identifier} to fetch one location. Use /locations/{identifier}/relations to navigate the hierarchy. Use /locations/{identifier}/boundary when you need polygons. Use /locations/{identifier}/zones when you need custom zones attached to that location. Use /autocomplete for search-as-you-type across all layers.

API surface

Each namespace maps to a tag in the engine's OpenAPI spec. Override the default base URL with { baseUrl: "https://api.mapbase.dev" } if needed.

| Namespace | Methods | Notes | | --------- | ------- | ----- | | locations | list, listAll, get, relations, boundary, zones | Administrative locations | | postcodes | list, listAll, get, byPoint, byCode | Postal codes | | lau | list, listAll, get, boundary, postcodes, postcodesAll | EU LAU regions | | zones | list, listAll, get, boundary | Read-only; writes via zoneSubmissions | | zoneSubmissions | create, list, get, update, submit, delete | User-scoped via API key; two keys for the same user share submissions | | boundaries | list | Bulk boundary fetch with spatial and registry filters | | points | resolve | Point-in-polygon resolve | | autocomplete | search | Unified search across every layer | | seo | page, tree, sitemap | SEO page bundles, directory trees, sitemap entries | | layers | list | Registry layers with live row counts; no API key required | | providers.google | autocomplete, place, geocode, reverseGeocode | Live passthroughs; pass your Google key via googleApiKey in request options; responses typed as unknown | | providers.geoapify | autocomplete, boundaries | Live passthroughs; pass your Geoapify key via geoapifyApiKey in request options |

React hooks (mapbase/react)

Hooks live under the mapbase/react subpath. Peer dependencies: @tanstack/react-query (required, >=5) and react (>=18, optional).

Exports: MapbaseProvider, useMapbase, useMapbaseClient, useOptionalMapbase, usePlaceSource, useAutocomplete, useBoundary, usePointResolve, useLayerCatalog.

import { useAutocomplete } from "mapbase/react"

function Search() {
  const { query, setQuery, hits, loading } = useAutocomplete({ country: "PT" })

  return (
    <div>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      {loading ? (
        <span>…</span>
      ) : (
        hits.map((h) => <div key={h.id}>{h.label}</div>)
      )}
    </div>
  )
}

Wrap your tree in MapbaseProvider once (server-side key injection recommended):

import { MapbaseProvider } from "mapbase/react"

function App() {
  return (
    <MapbaseProvider apiKey={process.env.MAPBASE_API_KEY!}>
      <Search />
    </MapbaseProvider>
  )
}

| Hook | Purpose | | ---- | ------- | | useAutocomplete | Debounced typeahead via react-query; returns { query, setQuery, hits, loading, error, ... } | | useBoundary | Fetch a boundary polygon by place id | | usePointResolve | Resolve a coordinate or suggestion to taxonomy | | useLayerCatalog | Public layer catalog with availability and count helpers |

Place sources

Use createPlaceSource(client, name) to build a PlaceSource for "mapbase" | "google" | "geoapify". Named factories: createMapbaseSource, createGoogleSource, createGeoapifySource. Google and Geoapify sources require the customer's provider key (googleApiKey / geoapifyApiKey).

import { Mapbase, createPlaceSource } from "mapbase"

const client = new Mapbase("mb_live_...")
const source = createPlaceSource(client, "mapbase")
const { hits } = await source.autocomplete("Lisb", { country: "PT" })

Geometry helpers

Polyline and bbox helpers (coordinates are [lng, lat], GeoJSON order):

  • decodeGooglePolyline(encoded) — decode a precision-5 Google polyline to [lng, lat] pairs.
  • polygonFeaturesFromEncodedPolylines(encoded[]) — assemble GeoJSON Feature polygons from encoded rings.
  • polylinesToGeoJson(encoded[]) — first feature geometry, or null.
  • bboxToPolygonCoordinates([minLng, minLat, maxLng, maxLat]) — closed ring.

Responses

Every method returns a Result:

type Result<T> =
  | { data: T; error: null; rateLimit: RateLimitInfo }
  | { data: null; error: MapbaseError; rateLimit: RateLimitInfo }

The SDK never throws on HTTP errors. Network failures and timeouts are surfaced as MapbaseError with code: "network_error".

Retry

Retry is off by default (attempts: 0). Opt in at client construction or per request:

const mapbase = new Mapbase("mb_live_...", {
  retry: { attempts: 3, respectRetryAfter: true },
})

// Per-request override — disable despite client default
await mapbase.locations.get("0-EU-ES", {}, { retry: false })

await mapbase.autocomplete.search(
  { q: "lis", layers: ["locations"] },
  { retry: { attempts: 2 } },
)

By default only GET requests are retried (429, 502, 503, 504, and transport failures). POST, PATCH, and DELETE require retry: { idempotent: true } — do not set that on zoneSubmissions writes unless the engine guarantees idempotency.

timeoutMs applies to each attempt. Optional retry.budgetMs caps total wall time across attempts and backoff sleeps.

Cursor pagination (listAll)

List namespaces expose async iterators that walk every page via meta.next_cursor. Top-level collections use listAll; id-scoped related lists use {relation}All (for example lau.postcodesAll).

for await (const postcode of mapbase.postcodes.listAll({ country: "PT" })) {
  console.log(postcode.code)
}

Unlike single-page list() methods, iterators throw MapbaseError when a page request fails. Pass signal to cancel between pages; an aborted signal ends the generator without throwing.

*All param types omit cursor and offset (cursor-only iteration). Use the existing list() methods for offset-based random access.

Optional caps on ListAllOptions:

  • maxPages — stop after this many HTTP page fetches (first page counts as 1).
  • maxItems — stop after yielding this many rows (may end mid-page).

Per-request retry passes through to each page fetch. For bulk exports, consider retry: { attempts: 2–5, respectRetryAfter: true }.

zoneSubmissions has no listAll in v1.

Errors

Handle failures by switching on error.code:

import { MapbaseError, type MapbaseErrorCode } from "mapbase"

const { error } = await mapbase.locations.get("0-EU-ES")
if (error) {
  switch (error.code) {
    case "rate_limited":
      console.log("Try again in", error.rateLimit?.retryAfter, "s")
      break
    case "unauthorized":
      console.log("Check your API key")
      break
    case "invalid_request":
      console.log("Fix the request parameters")
      break
    case "not_found":
      console.log("No such location")
      break
    default:
      console.error(error)
  }
}

Versioning

[email protected] targets the engine's stable /v1 contract today. Additive engine changes ship as SDK minor versions. When a breaking engine API ships under /v2, the SDK major version will track that prefix. Backwards- incompatible changes within /v1 would violate the engine contract.

License

MIT