Skip to content

Latest commit

Β 

History

20 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Topolab TypeScript SDK

npm version TypeScript types CI License: MIT Documentation

@topolab/sdk

The official TypeScript client for the Topolab dataset and geospatial API.
Lightweight, GeoJSON-first, runs in Node and the browser.


πŸ“– Docs: topolab-bv.github.io/topolab-js Β· full platform docs at docs.topolab.nl

Install

npm install @topolab/sdk

Pre-release: until the first version is published to npm, install from Git: npm install github:topolab-bv/topolab-js

Ships ES modules + CommonJS and TypeScript types. Uses the platform fetch, so Node 18+ or any modern browser / edge runtime works with no polyfill.

Quickstart

// Page Domino's locations within an Amsterdam bounding box
import { Client } from "@topolab/sdk";

const tl = new Client({ apiKey: "tlb_prod_..." });
const fc = await tl.dataset("nl-domino-poi").items({ limit: 100, bbox: [4.7, 52.2, 5.1, 52.5] });
console.log(`${fc.features.length} locations`);

Your API key carries your scope and add-ons β€” spatial queries need GIS_ACCESS, downloads need API_ACCESS, and data routes require an organization-scoped key. Pass apiKey or set TOPOLAB_API_KEY (avoid embedding keys in client bundles):

const tl = new Client({ apiKey: process.env.TOPOLAB_API_KEY });

Staging vs production

The client targets production (https://api.topolab.nl) by default. Point it at staging with the environment option:

const tl = new Client({ apiKey: "tlb_staging_...", environment: "staging" }); // https://api-staging.topolab.nl

Or set TOPOLAB_ENV=staging. An explicit baseUrl always wins (self-hosting / tests). Precedence: baseUrl β†’ environment β†’ TOPOLAB_BASE_URL β†’ TOPOLAB_ENV β†’ production.

Pull everything you own

The loop this SDK is built for β€” discover what your organization licences, then pull each dataset's newest snapshot. No hard-coded slugs:

import { Client } from "@topolab/sdk";
import { downloadArchive } from "@topolab/sdk/node";

const tl = new Client();

for await (const ds of tl.datasets.iterOwned()) {
  await downloadArchive(tl.dataset(ds.table), `${ds.table}.zip`, { month: "latest", format: "geojson" });
}

iterOwned() is filtered by the same licence check the download routes enforce, so everything it yields is downloadable.

What you can do

Browse the catalog

const page = await tl.datasets.list({ country: "NL", limit: 10 });

Query features in an area (spatial, paged)

const fc = await tl.dataset("nl-domino-poi").items({ limit: 100, bbox: [4.7, 52.2, 5.1, 52.5] });

// or stream every feature, paging transparently:
for await (const feature of tl.dataset("nl-domino-poi").iterItems({ pageSize: 500 })) {
  // ...
}

The async iterator cancels the in-flight request if you break early.

Pull a whole dataset (bulk)

const fc = await tl.dataset("nl-domino-poi").toGeoJSON();   // FeatureCollection

Stream a dataset to disk (Node only)

import { Client } from "@topolab/sdk";
import { download } from "@topolab/sdk/node";

const tl = new Client();
await download(tl.dataset("nl-domino-poi"), "dominos-nl.geojson", { format: "geojson" });

download lives in the @topolab/sdk/node subpath because it writes to the filesystem β€” the core entry point stays browser-safe. downloadArchive lives there for the same reason.

List what you licence

const page = await tl.datasets.owned({ limit: 50 });   // page.total = all licensed datasets
for await (const ds of tl.datasets.iterOwned()) { /* every one, paged for you */ }

Monthly archives

const ds = tl.dataset("business_professional_services_autocrew");
const months = await ds.archives();                    // newest first; free, no credits

import { downloadArchive } from "@topolab/sdk/node";
await downloadArchive(ds, "autocrew.zip", { month: "2026-07", format: "geojson" });

month is "latest", "YYYY-MM" or "YYYY-MM-DD", validated as a real calendar value before the request goes out. Team plans see a trailing 12 months; Enterprise sees everything.

Coordinates with attributes

const page = await ds.coordinates({ limit: 1000 });
page.total;             // from X-Total-Count β€” the whole dataset, regardless of paging
page.rows[0].latitude;  // "51.49638600" β€” a decimal string, kept as one

SQL across the datasets you licence (Enterprise)

const res = await tl.sql("SELECT city, count(*) AS n FROM autocrew GROUP BY 1", { maxRows: 100 });

One read-only SELECT, restricted to datasets you hold an active licence for. Requires the sql-access entitlement, part of the Enterprise plan.

Errors

Every failure throws a subclass of TopolabError, so you never parse raw JSON:

Error When
AuthenticationError missing or invalid API key (401)
AddonRequiredError key lacks the add-on β€” .addon names it (403)
AccessDeniedError dataset not accessible to your organization (403)
InsufficientCreditsError not enough credits β€” .required / .available (402)
NotFoundError unknown dataset, or no archive available for that month (404)
QueryTimeoutError a SQL query exceeded the server statement timeout (408)
RateLimitError rate limited β€” .retryAfter, retried automatically (429)
import { Client, AddonRequiredError } from "@topolab/sdk";

try {
  await tl.dataset("nl-domino-poi").toGeoJSON();
} catch (e) {
  if (e instanceof AddonRequiredError) console.log("Your key needs:", e.addon);
}

Documentation

Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md. Run npm test, type-check with npm run typecheck, build with npm run build.

License

MIT Β© Topolab B.V.

About

Official TypeScript client for the Topolab dataset and geospatial API.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages