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

@unrdf/geosparql

v26.4.8

Published

OGC GeoSPARQL standard compliance for spatial RDF queries

Readme

@unrdf/geosparql

OGC GeoSPARQL standard compliance for spatial RDF queries. Enterprise-grade geospatial capabilities for UNRDF knowledge graphs.

Features

  • OGC Compliance: Full GeoSPARQL 1.0 standard implementation
  • Geometry Types: Point, LineString, Polygon with WKT support
  • Spatial Relations: within, intersects, contains, touches, disjoint, overlaps
  • Distance Calculations: Haversine formula with meter-level accuracy
  • Spatial Indexing: R-tree for high-performance queries (10K+ geometries)
  • CRS Support: WGS84, CRS84, EPSG:4326
  • GeoSPARQL Functions: 13 standard functions (distance, buffer, area, etc.)
  • OTEL Instrumentation: Production-ready observability

Installation

pnpm add @unrdf/geosparql

Quick Start

import {
  Point,
  Polygon,
  within,
  distance,
  createGeoSPARQLEngine
} from '@unrdf/geosparql';

// Create geometries
const sanFrancisco = Point([-122.4194, 37.7749]);
const losAngeles = Point([-118.2437, 34.0522]);

// Calculate distance
const dist = distance(sanFrancisco, losAngeles);
console.log(`Distance: ${(dist / 1000).toFixed(2)} km`); // ~559 km

// Spatial queries
const bayArea = Polygon([[
  [-122.5, 37.7],
  [-122.3, 37.7],
  [-122.3, 37.9],
  [-122.5, 37.9],
  [-122.5, 37.7]
]]);

console.log(within(sanFrancisco, bayArea)); // true

Geometry Types

Point

import { Point, toWKT } from '@unrdf/geosparql';

const sf = Point([-122.4194, 37.7749]); // [longitude, latitude]

console.log(toWKT(sf)); // "POINT(-122.4194 37.7749)"

LineString

import { LineString } from '@unrdf/geosparql';

const route = LineString([
  [-122.4194, 37.7749], // San Francisco
  [-122.4089, 37.7849], // North Beach
  [-122.4169, 37.7949]  // Fisherman's Wharf
]);

Polygon

import { Polygon } from '@unrdf/geosparql';

// Rings must be closed (first point = last point)
const zone = Polygon([[
  [-122.5, 37.7],
  [-122.3, 37.7],
  [-122.3, 37.9],
  [-122.5, 37.9],
  [-122.5, 37.7] // Closed
]]);

Spatial Relations

import {
  Point,
  Polygon,
  within,
  contains,
  intersects,
  disjoint,
  filter
} from '@unrdf/geosparql';

const point = Point([-122.4, 37.8]);
const polygon = Polygon([[
  [-122.5, 37.7],
  [-122.3, 37.7],
  [-122.3, 37.9],
  [-122.5, 37.9],
  [-122.5, 37.7]
]]);

// Test relations
within(point, polygon);      // true
contains(polygon, point);    // true
intersects(point, polygon);  // true
disjoint(point, polygon);    // false

// Filter geometries
const points = [
  Point([-122.4, 37.8]),
  Point([-122.35, 37.85]),
  Point([-118.2, 34.0])
];

const nearby = filter(points, polygon, 'within');
console.log(nearby.length); // 2

Distance Calculations

import {
  Point,
  distance,
  withinDistance,
  bearing,
  convertDistance
} from '@unrdf/geosparql';

const sf = Point([-122.4194, 37.7749]);
const la = Point([-118.2437, 34.0522]);

// Distance in meters
const dist = distance(sf, la);
console.log(`${(dist / 1000).toFixed(2)} km`); // ~559 km

// Check proximity
const nearby = Point([-122.4189, 37.7750]);
console.log(withinDistance(nearby, sf, 100, 'meters')); // true

// Bearing (degrees)
const bear = bearing(sf.coordinates, la.coordinates);
console.log(`${bear.toFixed(2)}°`); // ~130° (southeast)

// Convert units
const km = convertDistance(dist, 'meters', 'kilometers');
const miles = convertDistance(dist, 'meters', 'miles');

Spatial Indexing (R-tree)

import { createSpatialIndex, Point } from '@unrdf/geosparql';

const index = createSpatialIndex();

// Add geometries
index.insert(Point([-122.4, 37.8]), { name: 'Point A' });
index.insert(Point([-122.35, 37.85]), { name: 'Point B' });
index.insert(Point([-118.2, 34.0]), { name: 'Point C' });

// Search by bounding box
const bbox = [-122.5, 37.7, -122.3, 37.9]; // [minLon, minLat, maxLon, maxLat]
const results = index.search(bbox);
console.log(results.length); // 2

// Bulk load (efficient for large datasets)
const entries = Array.from({ length: 10000 }, (_, i) => ({
  geometry: Point([-122.4 + i * 0.01, 37.7 + i * 0.01]),
  data: { id: i }
}));

index.bulkLoad(entries); // <100ms for 10K geometries

// K-nearest neighbors
import { kNearest } from '@unrdf/geosparql';
const target = Point([-122.38, 37.82]);
const nearest = kNearest(index, target, 5);

GeoSPARQL Functions

import {
  Point,
  Polygon,
  geof_distance,
  geof_within,
  geof_buffer,
  geof_area,
  geof_length
} from '@unrdf/geosparql';

const point = Point([-122.4194, 37.7749]);
const polygon = Polygon([[
  [-122.5, 37.7],
  [-122.3, 37.7],
  [-122.3, 37.9],
  [-122.5, 37.9],
  [-122.5, 37.7]
]]);

// geof:distance
geof_distance(point, Point([-118.2437, 34.0522])); // ~559120 meters

// geof:within
geof_within(point, polygon); // false

// geof:buffer (1km radius)
const buffered = geof_buffer(point, 1000);
console.log(buffered.type); // "Polygon"

// geof:area (square meters)
const area = geof_area(polygon);
console.log(`${(area / 1e6).toFixed(2)} km²`);

// geof:length (meters)
const line = LineString([[-122.4, 37.8], [-122.3, 37.9]]);
const length = geof_length(line);

GeoSPARQL Engine

import { createGeoSPARQLEngine, Point, Polygon } from '@unrdf/geosparql';

const engine = createGeoSPARQLEngine({
  enableIndex: true,
  indexMaxEntries: 9
});

// Add geometries with metadata
engine.addGeometry(
  Point([-122.4194, 37.7749]),
  { city: 'San Francisco', population: 883305 }
);

engine.addGeometry(
  Point([-118.2437, 34.0522]),
  { city: 'Los Angeles', population: 3979576 }
);

// Query by bounding box
const results = engine.query({
  bbox: [-123, 37, -122, 38]
});

// Query by spatial relation
const bayArea = Polygon([[
  [-122.5, 37.7],
  [-122.3, 37.7],
  [-122.3, 37.9],
  [-122.5, 37.9],
  [-122.5, 37.7]
]]);

const withinBayArea = engine.query({
  relation: { geometry: bayArea, type: 'within' }
});

// Query by distance
const nearby = engine.query({
  distance: {
    from: Point([-122.4, 37.8]),
    max: 10000, // 10km
    unit: 'meters'
  }
});

// Execute GeoSPARQL functions
const dist = engine.executeFunction(
  'http://www.opengis.net/def/function/geosparql/distance',
  Point([-122.4194, 37.7749]),
  Point([-118.2437, 34.0522])
);

// Add from WKT
engine.addWKT('POINT(-122.4194 37.7749)', { name: 'SF' });

// Statistics
const stats = engine.getStats();
console.log(stats); // { geometryCount: 3, indexEnabled: true, indexSize: 3 }

WKT Support

import { toWKT, fromWKT, Point, LineString } from '@unrdf/geosparql';

// Geometry to WKT
const point = Point([-122.4194, 37.7749]);
console.log(toWKT(point)); // "POINT(-122.4194 37.7749)"

const line = LineString([[-122.4, 37.8], [-122.3, 37.9]]);
console.log(toWKT(line)); // "LINESTRING(-122.4 37.8, -122.3 37.9)"

// WKT to Geometry
const parsed = fromWKT('POINT(-122.4194 37.7749)');
console.log(parsed.type); // "Point"
console.log(parsed.coordinates); // [-122.4194, 37.7749]

Coordinate Reference Systems

import { Point, validateCRS, getCRSUri } from '@unrdf/geosparql';

// Supported CRS
const point = Point([-122.4194, 37.7749], 'WGS84');
console.log(point.crs); // "WGS84"

// Get OGC URI
const uri = getCRSUri('CRS84');
console.log(uri); // "http://www.opengis.net/def/crs/OGC/1.3/CRS84"

// Validate CRS
validateCRS('EPSG:4326'); // Valid
validateCRS('INVALID');   // Throws error

Performance

Targets for production workloads:

| Operation | P95 Target | Typical | |-----------|------------|---------| | Point creation | <0.1ms | ~0.05ms | | Distance calculation | <0.5ms | ~0.2ms | | Spatial relation check | <1ms | ~0.3ms | | R-tree query (10K geometries) | <10ms | ~2ms | | Index build (10K geometries) | <100ms | ~50ms |

// Benchmark distance calculation
const point1 = Point([-122.4194, 37.7749]);
const point2 = Point([-118.2437, 34.0522]);

const start = performance.now();
distance(point1, point2);
const elapsed = performance.now() - start;

console.log(`Elapsed: ${elapsed.toFixed(3)}ms`); // ~0.2ms

Use Cases

Location-Based Services

// Find all restaurants within 1km
const restaurants = engine.query({
  distance: {
    from: userLocation,
    max: 1000,
    unit: 'meters'
  }
});

Geofencing

// Check if vehicle is within delivery zone
const deliveryZone = Polygon([[...]]);
const vehicleLocation = Point([-122.4, 37.8]);

if (within(vehicleLocation, deliveryZone)) {
  console.log('Vehicle in zone');
}

Route Planning

// Calculate route length
const route = LineString([
  [-122.4194, 37.7749],
  [-122.4089, 37.7849],
  [-122.4169, 37.7949]
]);

const routeLength = geof_length(route);
console.log(`Route: ${(routeLength / 1000).toFixed(2)} km`);

Spatial Analytics

// Find points of interest in region
const region = Polygon([[...]]);
const pois = allPOIs.filter(poi => within(poi.location, region));

// Calculate coverage area
const coverageArea = geof_area(region);
console.log(`Coverage: ${(coverageArea / 1e6).toFixed(2)} km²`);

OTEL Observability

import { trace } from '@opentelemetry/api';

// Engine operations emit spans automatically
const engine = createGeoSPARQLEngine();

engine.addGeometry(point, data);
// Emits: geosparql.addGeometry span

const results = engine.query({ bbox: [...] });
// Emits: geosparql.query span with attributes:
//   - query.type: "bbox"
//   - results.count: 42

const dist = engine.executeFunction(uri, g1, g2);
// Emits: geosparql.executeFunction span

OGC GeoSPARQL Compliance

Implements OGC GeoSPARQL 1.0 standard:

  • Geometry Types: Point, LineString, Polygon (GeoJSON/WKT)
  • Spatial Relations: within, contains, intersects, touches, disjoint, overlaps
  • Functions: distance, buffer, convexHull, envelope, intersection, union, difference, area, length
  • CRS: WGS84, CRS84, EPSG:4326
  • Topology: DE-9IM model (via Turf.js)

Dependencies

  • @turf/turf - Geospatial calculations (FOSS)
  • rbush - R-tree spatial indexing (FOSS)
  • @unrdf/oxigraph - SPARQL engine
  • @opentelemetry/api - Observability
  • zod - Runtime validation

API Reference

Geometry

  • Point(coords, crs?) - Create Point geometry
  • LineString(coords, crs?) - Create LineString geometry
  • Polygon(coords, crs?) - Create Polygon geometry
  • getBBox(geometry) - Get bounding box
  • toWKT(geometry) - Convert to Well-Known Text
  • fromWKT(wkt) - Parse Well-Known Text

Distance

  • distance(g1, g2, unit?) - Calculate distance
  • haversineDistance(c1, c2, unit?) - Haversine formula
  • withinDistance(point, center, radius, unit?) - Proximity check
  • bearing(c1, c2) - Calculate bearing
  • convertDistance(value, from, to) - Unit conversion

Spatial Relations

  • within(g1, g2) - g1 within g2
  • contains(g1, g2) - g1 contains g2
  • intersects(g1, g2) - Geometries intersect
  • touches(g1, g2) - Geometries touch
  • disjoint(g1, g2) - Geometries don't intersect
  • overlaps(g1, g2) - Geometries overlap
  • evaluate(g1, g2, relation) - Evaluate named relation
  • filter(geometries, target, relation) - Filter by relation

Spatial Index

  • createSpatialIndex(maxEntries?) - Create R-tree index
  • index.insert(geometry, data?) - Insert geometry
  • index.search(bbox) - Search by bounding box
  • index.searchGeometry(geometry) - Search by geometry
  • index.bulkLoad(entries) - Bulk load geometries
  • kNearest(index, target, k) - K-nearest neighbors

GeoSPARQL Functions

  • geof_distance(g1, g2, unit?) - Distance
  • geof_within(g1, g2) - Within test
  • geof_contains(g1, g2) - Contains test
  • geof_intersects(g1, g2) - Intersects test
  • geof_touches(g1, g2) - Touches test
  • geof_buffer(geometry, distance) - Buffer
  • geof_convexHull(geometry) - Convex hull
  • geof_envelope(geometry) - Envelope
  • geof_intersection(g1, g2) - Intersection
  • geof_union(g1, g2) - Union
  • geof_difference(g1, g2) - Difference
  • geof_area(geometry) - Area
  • geof_length(geometry) - Length

Engine

  • createGeoSPARQLEngine(options?) - Create engine
  • engine.addGeometry(geometry, data?) - Add geometry
  • engine.removeGeometry(id) - Remove geometry
  • engine.query(criteria) - Query geometries
  • engine.executeFunction(uri, ...args) - Execute function
  • engine.addWKT(wkt, data?) - Add from WKT
  • engine.getGeometry(id) - Get geometry by ID
  • engine.getAllGeometries() - Get all geometries
  • engine.clear() - Clear all
  • engine.getStats() - Get statistics

License

MIT

Contributing

See CONTRIBUTING.md

Support

  • Issues: https://github.com/seanchatmangpt/unrdf/issues
  • Docs: https://unrdf.dev/geosparql