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

@kaistrum/geonode-node-sdk

v1.0.0

Published

Node.js SDK for GeoNode 4.x — dataset uploads and full WFS-T feature CRUD (create, read, update, delete) with geometry and attributes

Downloads

81

Readme

@kaistrum/geonode-node-sdk

A Node.js SDK for GeoNode 4.x. Create datasets by uploading data, and run full WFS-T feature CRUD (create / read / update / delete) with geometry and attributes — all behind a small, promise-based API with a consistent result envelope.

Built and verified against a live GeoNode 4.x instance (datasets API + GeoServer WFS-T).

Features

  • Auth — HTTP Basic Auth against the GeoNode v2 API.
  • Datasets — list, read, update metadata, delete (async), and create via upload (GeoJSON object or a file on disk; the import runs asynchronously and is polled for you).
  • Features (WFS-T) — insert, read (with CQL / bbox filters), update, and delete, including bulk update/delete by CQL filter.
  • Geometry — Point, LineString, Polygon (GeoJSON in, GML out).
  • Consistent responses — every call returns { success, data?, error? }.

Install

npm install @kaistrum/geonode-node-sdk

Requires Node.js >= 16.

Important: GeoNode 4.x specifics

This SDK targets GeoNode 4.x, whose API differs from older guides:

  • Datasets, not layers — the API lives at /api/v2/datasets/ (the old /layers/ is gone).
  • No "empty layer" create — you create a dataset by uploading data. createLayer() therefore takes a GeoJSON geojson object or a filePath, not just metadata.
  • GeoServer has its own credentials — feature (WFS-T) operations hit GeoServer directly, which authenticates separately from GeoNode. Set geoserverUser / geoserverPassword (default admin / geoserver; the real password is your GEOSERVER_ADMIN_PASSWORD).
  • Geometry column is geom by default (the GeoJSON importer's column name).
  • Fresh layers settle asynchronously — a just-uploaded layer can take a short while before GeoServer serves it over WFS. createLayer() waits for readiness before returning, and the SDK deliberately does not hammer WFS on 401 (rapid retries trip GeoServer's brute-force filter and make the block worse).

Quick start

const GeoNodeService = require('@kaistrum/geonode-node-sdk');

const geonode = new GeoNodeService({
  baseUrl: 'http://localhost',
  username: 'admin',
  password: 'admin',
  // GeoServer creds (for feature/WFS-T operations)
  geoserverUser: 'admin',
  geoserverPassword: 'your-geoserver-password',
  debug: true,
});

(async () => {
  await geonode.authenticate();

  // Create a dataset by uploading a GeoJSON FeatureCollection (async import).
  const created = await geonode.createLayer({
    name: 'parks',
    title: 'City Parks',
    geojson: {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          geometry: { type: 'Point', coordinates: [-74.0, 40.7] },
          properties: { name: 'Central Park', area_sqm: 843000, kind: 'park' },
        },
      ],
    },
  });

  const layer = created.data.alternate; // e.g. "geonode:parks"
  const pk = created.data.pk;

  // Add a feature (WFS-T Insert). Property names must match the uploaded schema.
  await geonode.addFeature(layer, {
    type: 'Feature',
    geometry: { type: 'Point', coordinates: [-73.94, 40.66] },
    properties: { name: 'Prospect Park', area_sqm: 526000, kind: 'park' },
  });

  // Read features (optionally filtered with CQL).
  const parks = await geonode.getFeatures(layer, { cqlFilter: "kind='park'", limit: 100 });
  console.log(`${parks.data.features.length} parks`);

  // Update a feature by its WFS resource id.
  const fid = parks.data.features[0].id;
  await geonode.updateFeature(layer, fid, { properties: { kind: 'updated_park' } });

  // Delete a feature, then the whole dataset.
  await geonode.deleteFeature(layer, fid);
  await geonode.deleteLayer(pk);
})();

Configuration

| Option | Default | Description | |--------|---------|-------------| | baseUrl | http://localhost:8000 | GeoNode base URL | | username / password | admin / admin | GeoNode credentials | | geoserverUser / geoserverPassword | username / geoserver | GeoServer credentials (WFS-T) | | workspace | geonode | Default workspace for new datasets | | geometryColumn | geom | Geometry column name in PostGIS | | workspaceNamespace | http://www.geonode.org/ | XML namespace bound to the workspace prefix in WFS-T | | uploadTimeout | 300000 | Max ms to wait for an import to finish | | pollInterval | 3000 | ms between import status polls | | wfsReadyTimeout | 300000 | Max ms to wait for a fresh layer to become WFS-accessible | | wfsReadyInterval | 30000 | ms between readiness checks (kept slow on purpose) | | wfsRetries / wfsRetryDelay | 4 / 5000 | Retry policy for transient (5xx) GeoServer errors | | debug | false | Verbose request logging |

API

Every method resolves to { success, data?, error? } (list calls also include total; delete calls include executionId; bulk feature calls include updated / deleted).

Auth

  • authenticate(): Promise<boolean>
  • isAuthenticatedCheck(): boolean

Datasets

  • createLayer({ geojson?, filePath?, name?, title? }) — upload data to create a dataset. Returns the dataset detail (data.pk, data.alternate, data.name, ...).
  • getExecutionStatus(execId) — poll an import execution.
  • listLayers({ limit?, offset?, search? })data is the datasets array, total the count.
  • getLayer(pk) / getLayerAttributes(pk)
  • updateLayer(pk, updates) — patch metadata.
  • deleteLayer(pk) — async delete via the resource service.
  • uploadShapefile(shpPath, metadata?) — upload a .shp (with .shx/.dbf/.prj sidecars).

Features (WFS-T) — layerName is "workspace:layer" (use dataset.alternate)

  • addFeature(layerName, feature) / addFeaturesInBatch(layerName, features)
  • getFeatures(layerName, { cqlFilter?, bbox?, limit? }) / getFeature(layerName, featureId)
  • updateFeature(layerName, featureId, { geometry?, properties? })
  • updateFeaturesByFilter(layerName, updates, cqlFilter) — resolves matches, then updates by resource id.
  • deleteFeature(layerName, featureId)
  • deleteFeaturesByFilter(layerName, cqlFilter)

Feature ids are WFS resource ids of the form layer.N (e.g. parks.3) — read them from getFeatures(...).data.features[i].id.

Geometry

// Point
{ type: 'Point', coordinates: [lon, lat] }
// LineString
{ type: 'LineString', coordinates: [[lon, lat], [lon, lat]] }
// Polygon (closed ring)
{ type: 'Polygon', coordinates: [[[lon, lat], [lon, lat], [lon, lat], [lon, lat]]] }

CQL filter examples

"kind='park'"
"area_sqm>100000"
"kind='park' AND area_sqm>100000"
"name LIKE '%Park%'"
"INTERSECTS(geom, POINT(-74 40))"
"DWITHIN(geom, POINT(-74 40), 1, kilometers)"

TypeScript

Ships with type definitions (geonode-service.d.ts). Import the default export:

import GeoNodeService, { GeoNodeConfig } from '@kaistrum/geonode-node-sdk';

License

MIT © kaistrum

Resources