osmfeatures 0.2.1 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -13
- package/dist/index.d.ts +4 -2
- package/dist/index.js +8 -5
- package/dist/preset/catalog.d.ts +2 -0
- package/dist/preset/catalog.js +4 -4
- package/dist/preset/resolve.d.ts +3 -1
- package/dist/preset/resolve.js +4 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Official client for the [MapLark OSM Features API](https://maplark.com) to get GeoJSON, FlatGeobuf, GeoParquet, or CSV from OpenStreetMap. The API gets data from dedicated postgis OSM servers separate from public Overpass.
|
|
4
4
|
|
|
5
|
-
Query OpenStreetMap features such as buildings, streets, and POIs easily. Search for OSM features by bounding box, tags, and geometry shape and get GeoJSON back within less than 250ms (dependent on query size). No converting between formats manually. The API keeps OSM semantics intact, like tags and ways, and returns OSM features you can feed straight into Leaflet, MapLibre, OpenLayers, or any geospatial toolchain. It is backed by postgis with tiered API keys and rate limiting to keep noisy neighbours out to give you low, predictable latency for real traffic. It also has self-host path for those willing to host complex infrastructure themselves.
|
|
5
|
+
Query OpenStreetMap features such as buildings, streets, and POIs easily. Search for OSM features by bounding box, tags, and geometry shape and get GeoJSON back within less than 250ms (dependent on query size). No converting between formats manually. The API keeps OSM semantics intact, like tags and ways, and returns OSM features you can feed straight into Leaflet, MapLibre, OpenLayers, or any geospatial toolchain. It is backed by postgis with tiered API keys and rate limiting to keep noisy neighbours out to give you low, predictable latency for real traffic. It also has a self-host path for those willing to host complex infrastructure themselves, and Geo Agent methods for places search, opening hours, and walk or bike routing.
|
|
6
6
|
|
|
7
7
|
The translation layer is very simple:
|
|
8
8
|
|
|
@@ -12,11 +12,11 @@ The translation layer is very simple:
|
|
|
12
12
|
|
|
13
13
|
You filter with the same tags mappers already use (`amenity=cafe`, `building=yes`, and so on). Knowledge from OSM, Overpass, and tagging docs transfers immediately.
|
|
14
14
|
|
|
15
|
-
To narrow down between "open ways" and "closed ways", use the `
|
|
15
|
+
To narrow down between "open ways" and "closed ways", use the `way_shape` parameter:
|
|
16
16
|
|
|
17
|
-
- `
|
|
18
|
-
- `
|
|
19
|
-
- `
|
|
17
|
+
- `way_shape=line` - open ways (roads, paths, rivers) or line-shaped relations (routes, boundaries)
|
|
18
|
+
- `way_shape=polygon` - closed ways (buildings, parks) or multipolygon relations.
|
|
19
|
+
- `way_shape=all` - both shapes (default when way_shape is omitted).
|
|
20
20
|
|
|
21
21
|
For example, to get all buildings in an area:
|
|
22
22
|
|
|
@@ -102,7 +102,7 @@ Geometric filters such specific OSM element type, min length, or including centr
|
|
|
102
102
|
| Param | Type | Default | Description |
|
|
103
103
|
| ------------ | ---------------------- | ------- | --------------------------------------------------------------------------------------- |
|
|
104
104
|
| `type` | `string` | all | OSM element types, e.g. `node`, `way`, `relation`, or comma-separated (`way,relation`). |
|
|
105
|
-
| `
|
|
105
|
+
| `wayShape` | `line | polygon | all` | `all` | Geometry class for ways and relations. `shape` is a deprecated alias. |
|
|
106
106
|
| `centroid` | `boolean` | `false` | When `true`, include a centroid on non-point features. |
|
|
107
107
|
| `clipGeometry` | `boolean` | `true` | When `true`, clip returned geometry to the requested `bbox`. Set `false` for full geometry. |
|
|
108
108
|
| `minLengthM` | `number` | | Minimum length in metres (lines). |
|
|
@@ -168,7 +168,7 @@ console.log(all.meta.page_count, all.meta.has_more, all.meta.units_charged);
|
|
|
168
168
|
|
|
169
169
|
### Params
|
|
170
170
|
|
|
171
|
-
Same filter params as `query` (`bbox`, `tags`, `orTags`, `notTags`, `type`, `
|
|
171
|
+
Same filter params as `query` (`bbox`, `tags`, `orTags`, `notTags`, `type`, `wayShape`, `zoom`, `location`, `radius`, `osmIds`, `minLengthM`, `maxLengthM`, `minAreaM2`, `maxAreaM2`, `centroid`, `clipGeometry`, `disableBudgetWarning`), plus:
|
|
172
172
|
|
|
173
173
|
|
|
174
174
|
| Param | Type | Default | Description |
|
|
@@ -221,9 +221,37 @@ const usage = await client.usage();
|
|
|
221
221
|
console.log(usage.tier, usage.usage_this_month, usage.remaining_this_month);
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
-
##
|
|
224
|
+
## Geo Agent (places and routes)
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
`query()` is the generic OpenStreetMap layer: buildings, roads, park polygons, any tag and geometry shape. Geo Agent is the place and mobility layer on top of the same OSM data. You pick OSM tags (`amenity=cafe`), an area, a time, and walk or bike. The API returns coordinates, opening-hours status, nearest-first ranks, and walk or bike geometry.
|
|
227
|
+
|
|
228
|
+
These endpoints answer questions like "cafes near me", "bars open at 20:00", or "suggest a walking bar crawl in Stockholm". An AI agent or a script can call the same methods.
|
|
229
|
+
|
|
230
|
+
| Endpoint | HTTP | What it does |
|
|
231
|
+
| -------- | ---- | ------------ |
|
|
232
|
+
| `places_search` | `POST /v1/places/search` | Find places in a bounding box **or** a `location` plus `radius`. Filter with OSM tags. Optional `openNow` / `asOf` for opening hours. |
|
|
233
|
+
| `places_nearby` | `POST /v1/places/nearby` | "X near this point". Same tags and hours filters, ranked nearest-first by straight-line distance. |
|
|
234
|
+
| `places_details` | `GET /v1/places/{osm_type}/{osm_id}` | Reload one place by the id search or nearby returned (`node/123`). |
|
|
235
|
+
| `routes_isochrone` | `POST /v1/routes/isochrone` | Walk or bike reach polygon from an origin (how far you can get in N metres or seconds). |
|
|
236
|
+
| `routes_path` | `POST /v1/routes/path` | Walk or bike through stops in the order you list them. No reordering. |
|
|
237
|
+
| `routes_optimized_path` | `POST /v1/routes/optimized_path` | Order the stops for you (a tour from `start`). `loop` (default true) returns to start. |
|
|
238
|
+
|
|
239
|
+
Search and nearby hours use each place's local timezone. Optional `asOf` pins the evaluation instant. Routing is walk or bicycle on the OSM network (`travelMode`: `WALK` or `BICYCLE`). Car routing is not available yet.
|
|
240
|
+
|
|
241
|
+
#### Typical questions
|
|
242
|
+
|
|
243
|
+
| Prompt | SDK |
|
|
244
|
+
|------|-----|
|
|
245
|
+
| "Cafes near me" | `client.places_nearby()` or `client.places_search()` with `location` + `radius` |
|
|
246
|
+
| "Restaurants within 150 m of a station" | two `client.places_search()` calls, then join locally by distance |
|
|
247
|
+
| "Bars open at 20:00" | `client.places_search()` with `asOf`, keep `openingHours.status == "open"` |
|
|
248
|
+
| "Cafes within a 10-minute bike ride" | `client.routes_isochrone()` + `client.places_search()` in a covering radius + keep points inside the polygon |
|
|
249
|
+
| "A walking bar crawl in Stockholm" | `client.places_search()` + `client.routes_optimized_path()` (`loop: true`) |
|
|
250
|
+
| "Walk from my hotel to the cafe, then the office" | `client.routes_path()` with those stops in listed order |
|
|
251
|
+
| "Suggest a walk to a bar, a restaurant, and a cafe, no particular order" | `client.routes_optimized_path()` with `loop: false` |
|
|
252
|
+
| "Is the office a 20-minute walk from the apartment?" | `client.routes_isochrone()` from A, point-in-polygon for B |
|
|
253
|
+
|
|
254
|
+
### Examples for `places_search` / `places_nearby` / `places_details`
|
|
227
255
|
|
|
228
256
|
```ts
|
|
229
257
|
const origin = { lat: 59.316, lon: 18.075 };
|
|
@@ -250,9 +278,9 @@ const details = await client.places_details({ osmType: first.id });
|
|
|
250
278
|
|
|
251
279
|
`places_details` also accepts `{ osmType: 'node', osmId: 123 }`. Hours are annotated at request time in the place's local timezone.
|
|
252
280
|
|
|
253
|
-
|
|
281
|
+
### Examples for `routes_isochrone` / `routes_path` / `routes_optimized_path`
|
|
254
282
|
|
|
255
|
-
|
|
283
|
+
Points accept `lon` or `lng`. `routes_isochrone` takes exactly one of `maxDistanceM` or `durationS`. Optional `searchBufferM` widens the highway fetch corridor.
|
|
256
284
|
|
|
257
285
|
```ts
|
|
258
286
|
const origin = { lon: 18.075, lat: 59.316 };
|
|
@@ -273,6 +301,4 @@ const tour = await client.routes_optimized_path({
|
|
|
273
301
|
});
|
|
274
302
|
```
|
|
275
303
|
|
|
276
|
-
`routes_isochrone` takes exactly one of `maxDistanceM` or `durationS`. `routes_path` follows `stops` in listed order (no TSP). `routes_optimized_path` orders `stops` from `start`; `loop` (default true) returns to start. Optional `searchBufferM` and `travelMode` (`WALK` or `BICYCLE`).
|
|
277
|
-
|
|
278
304
|
Read the full API reference here [https://maplark.com/developer](https://maplark.com/developer) such as the OpenAPI 2.0 HTTP docs.
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export type OSMFeaturesLayer = {
|
|
|
32
32
|
orTags?: string[];
|
|
33
33
|
notTags?: string[];
|
|
34
34
|
type?: string;
|
|
35
|
+
wayShape?: 'line' | 'polygon' | 'all';
|
|
36
|
+
/** @deprecated Use `wayShape`. */
|
|
35
37
|
shape?: 'line' | 'polygon' | 'all';
|
|
36
38
|
};
|
|
37
39
|
/** Flat query params (same idea as Python `query(**params)`). */
|
|
@@ -146,9 +148,9 @@ export declare class OSMFeatures {
|
|
|
146
148
|
/** Single HTTP request with retry. Throws on non-OK (same role as Python `_raw_query`). */
|
|
147
149
|
private _rawQuery;
|
|
148
150
|
/** Single upstream page. Params map 1:1 to server query string (no tiling). */
|
|
149
|
-
query({ bbox, tags, orTags, notTags, type, shape, limit, cursor, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, }: OSMFeaturesParams, dependencies?: OSMFeaturesDependencies): Promise<OSMFeaturesResult>;
|
|
151
|
+
query({ bbox, tags, orTags, notTags, type, wayShape, shape, limit, cursor, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, }: OSMFeaturesParams, dependencies?: OSMFeaturesDependencies): Promise<OSMFeaturesResult>;
|
|
150
152
|
/** Auto-paginate (and optionally tile) until complete. Each page uses `_rawQuery`. */
|
|
151
|
-
query_all({ bbox, tags, orTags, notTags, type, shape, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, limitPerPage, bboxTiles, maxPages, maxFeatures, }: Omit<OSMFeaturesParams, 'limit' | 'cursor'> & {
|
|
153
|
+
query_all({ bbox, tags, orTags, notTags, type, wayShape, shape, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, limitPerPage, bboxTiles, maxPages, maxFeatures, }: Omit<OSMFeaturesParams, 'limit' | 'cursor'> & {
|
|
152
154
|
/** Upstream `limit` per HTTP request (page size). */
|
|
153
155
|
limitPerPage?: number;
|
|
154
156
|
bboxTiles?: number;
|
package/dist/index.js
CHANGED
|
@@ -189,8 +189,9 @@ function buildFeaturesQuery(params) {
|
|
|
189
189
|
if (params.type) {
|
|
190
190
|
query.set('type', params.type);
|
|
191
191
|
}
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
const wayShape = params.wayShape ?? params.shape;
|
|
193
|
+
if (wayShape) {
|
|
194
|
+
query.set('way_shape', wayShape);
|
|
194
195
|
}
|
|
195
196
|
for (const tag of params.tags ?? []) {
|
|
196
197
|
query.append('tags', tag);
|
|
@@ -518,13 +519,14 @@ export class OSMFeatures {
|
|
|
518
519
|
};
|
|
519
520
|
}
|
|
520
521
|
/** Single upstream page. Params map 1:1 to server query string (no tiling). */
|
|
521
|
-
async query({ bbox, tags, orTags, notTags, type, shape, limit = DEFAULT_LIMIT, cursor, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, }, dependencies = {}) {
|
|
522
|
+
async query({ bbox, tags, orTags, notTags, type, wayShape, shape, limit = DEFAULT_LIMIT, cursor, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, }, dependencies = {}) {
|
|
522
523
|
const payload = await this._rawQuery({
|
|
523
524
|
bbox,
|
|
524
525
|
tags,
|
|
525
526
|
orTags,
|
|
526
527
|
notTags,
|
|
527
528
|
type,
|
|
529
|
+
wayShape,
|
|
528
530
|
shape,
|
|
529
531
|
limit,
|
|
530
532
|
cursor,
|
|
@@ -544,7 +546,7 @@ export class OSMFeatures {
|
|
|
544
546
|
return payload;
|
|
545
547
|
}
|
|
546
548
|
/** Auto-paginate (and optionally tile) until complete. Each page uses `_rawQuery`. */
|
|
547
|
-
async query_all({ bbox, tags, orTags, notTags, type, shape, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, limitPerPage = DEFAULT_LIMIT, bboxTiles = 2, maxPages = 15, maxFeatures = 55_000, }, dependencies = {}) {
|
|
549
|
+
async query_all({ bbox, tags, orTags, notTags, type, wayShape, shape, zoom, location, radius, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, limitPerPage = DEFAULT_LIMIT, bboxTiles = 2, maxPages = 15, maxFeatures = 55_000, }, dependencies = {}) {
|
|
548
550
|
if (!isGeojsonAccept(accept)) {
|
|
549
551
|
throw appError(400, 'invalid_accept', 'query_all only supports GeoJSON; use query({ accept }) for binary encodings.');
|
|
550
552
|
}
|
|
@@ -570,6 +572,7 @@ export class OSMFeatures {
|
|
|
570
572
|
orTags,
|
|
571
573
|
notTags,
|
|
572
574
|
type,
|
|
575
|
+
wayShape,
|
|
573
576
|
shape,
|
|
574
577
|
limit: limitPerPage,
|
|
575
578
|
zoom,
|
|
@@ -670,7 +673,7 @@ export class OSMFeatures {
|
|
|
670
673
|
orTags: params.orTags,
|
|
671
674
|
notTags: params.notTags,
|
|
672
675
|
type: params.type,
|
|
673
|
-
|
|
676
|
+
wayShape: params.wayShape ?? params.shape,
|
|
674
677
|
limit: params.limit ?? DEFAULT_LIMIT,
|
|
675
678
|
zoom: params.zoom,
|
|
676
679
|
location: params.location,
|
package/dist/preset/catalog.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export type OSMFeaturesLayerPreset = {
|
|
|
7
7
|
orTags?: string[];
|
|
8
8
|
notTags?: string[];
|
|
9
9
|
type?: string;
|
|
10
|
+
wayShape?: 'line' | 'polygon';
|
|
11
|
+
/** @deprecated Use `wayShape`. */
|
|
10
12
|
shape?: 'line' | 'polygon';
|
|
11
13
|
};
|
|
12
14
|
export declare const OSM_FEATURES_LAYER_PRESETS: Record<OSMFeaturesPresetId, OSMFeaturesLayerPreset>;
|
package/dist/preset/catalog.js
CHANGED
|
@@ -4,14 +4,14 @@ export const OSM_FEATURES_LAYER_PRESETS = {
|
|
|
4
4
|
label: 'Buildings',
|
|
5
5
|
tags: ['building'],
|
|
6
6
|
type: 'way,relation',
|
|
7
|
-
|
|
7
|
+
wayShape: 'polygon',
|
|
8
8
|
},
|
|
9
9
|
roads_paths: {
|
|
10
10
|
id: 'roads_paths',
|
|
11
11
|
label: 'Roads & paths',
|
|
12
12
|
tags: ['highway'],
|
|
13
13
|
type: 'way,relation',
|
|
14
|
-
|
|
14
|
+
wayShape: 'line',
|
|
15
15
|
},
|
|
16
16
|
parks_green_space: {
|
|
17
17
|
id: 'parks_green_space',
|
|
@@ -37,7 +37,7 @@ export const OSM_FEATURES_LAYER_PRESETS = {
|
|
|
37
37
|
'amenity=pub',
|
|
38
38
|
'amenity=biergarten',
|
|
39
39
|
],
|
|
40
|
-
|
|
40
|
+
wayShape: 'polygon',
|
|
41
41
|
},
|
|
42
42
|
shops_commerce: {
|
|
43
43
|
id: 'shops_commerce',
|
|
@@ -112,7 +112,7 @@ export const OSM_FEATURES_LAYER_PRESETS = {
|
|
|
112
112
|
'waterway=ditch',
|
|
113
113
|
],
|
|
114
114
|
type: 'way,relation',
|
|
115
|
-
|
|
115
|
+
wayShape: 'line',
|
|
116
116
|
},
|
|
117
117
|
};
|
|
118
118
|
export const OSM_FEATURES_LAYER_PRESET_ORDER = [
|
package/dist/preset/resolve.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export type ResolvedCustomLayer = {
|
|
|
12
12
|
orTags?: string[];
|
|
13
13
|
notTags?: string[];
|
|
14
14
|
type?: string;
|
|
15
|
+
wayShape?: 'line' | 'polygon' | 'all';
|
|
16
|
+
/** @deprecated Use `wayShape`. */
|
|
15
17
|
shape?: 'line' | 'polygon' | 'all';
|
|
16
18
|
};
|
|
17
19
|
export type ResolvedDemoLayer = ResolvedPresetLayer | ResolvedCustomLayer;
|
|
@@ -24,7 +26,7 @@ export declare function getPreset(id: string): OSMFeaturesLayerPreset | undefine
|
|
|
24
26
|
export declare function resolvePresetFromQuery(query: PresetQuery): ResolvedPresetLayer;
|
|
25
27
|
/**
|
|
26
28
|
* Custom layer: `tags` / `or_tags` / `not_tags` + required `bbox`.
|
|
27
|
-
* Optional `type` / `
|
|
29
|
+
* Optional `type` / `way_shape`. Needs at least one positive filter (`tags` or `or_tags`).
|
|
28
30
|
*/
|
|
29
31
|
export declare function resolveCustomLayerFromQuery(query: PresetQuery): ResolvedCustomLayer;
|
|
30
32
|
/**
|
package/dist/preset/resolve.js
CHANGED
|
@@ -91,7 +91,7 @@ export function resolvePresetFromQuery(query) {
|
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
93
|
* Custom layer: `tags` / `or_tags` / `not_tags` + required `bbox`.
|
|
94
|
-
* Optional `type` / `
|
|
94
|
+
* Optional `type` / `way_shape`. Needs at least one positive filter (`tags` or `or_tags`).
|
|
95
95
|
*/
|
|
96
96
|
export function resolveCustomLayerFromQuery(query) {
|
|
97
97
|
const tags = stringList(query, 'tags');
|
|
@@ -114,9 +114,9 @@ export function resolveCustomLayerFromQuery(query) {
|
|
|
114
114
|
if (type) {
|
|
115
115
|
layer.type = type;
|
|
116
116
|
}
|
|
117
|
-
const
|
|
118
|
-
if (
|
|
119
|
-
layer.
|
|
117
|
+
const wayShape = optionalString(query, 'way_shape') ?? optionalString(query, 'shape');
|
|
118
|
+
if (wayShape === 'line' || wayShape === 'polygon' || wayShape === 'all') {
|
|
119
|
+
layer.wayShape = wayShape;
|
|
120
120
|
}
|
|
121
121
|
return layer;
|
|
122
122
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osmfeatures",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Get OpenStreetMap features such as buildings, roads, or points of interest from dedicated servers with a single API call in GeoJSON, FlatGeobuf, Geoparquet, and CSV formats.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "tsc -p tsconfig.json",
|
|
21
|
-
"test": "tsx src/index.test.ts && tsx src/geojson-feature.test.ts && tsx src/preset/preset.test.ts",
|
|
21
|
+
"test": "tsx src/index.test.ts && tsx src/geojson-feature.test.ts && tsx src/preset/preset.test.ts && tsx src/tutorial.test.ts",
|
|
22
22
|
"prepare": "npm run build",
|
|
23
23
|
"prepublishOnly": "npm run build"
|
|
24
24
|
},
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"homepage": "https://maplark.com",
|
|
37
37
|
"repository": {
|
|
38
38
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/MapLark/osmfeatures-
|
|
39
|
+
"url": "https://github.com/MapLark/osmfeatures-ts.git"
|
|
40
40
|
},
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"engines": {
|